create-unibest 3.0.0 → 3.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/bin/index.js +0 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +748 -0
- package/package.json +15 -10
- package/.prettierrc +0 -14
- package/.vscode/launch.json +0 -15
- package/.vscode/settings.json +0 -3
- package/DEVELOPER.md +0 -16
- package/src/commands/create/generate.ts +0 -60
- package/src/commands/create/prompts.ts +0 -163
- package/src/commands/create.ts +0 -43
- package/src/index.ts +0 -64
- package/src/types/index.ts +0 -26
- package/src/utils/beacon.ts +0 -54
- package/src/utils/cloneRepo.ts +0 -54
- package/src/utils/color.ts +0 -12
- package/src/utils/debug.ts +0 -17
- package/src/utils/ejs.ts +0 -22
- package/src/utils/file.ts +0 -48
- package/src/utils/generator.ts +0 -133
- package/src/utils/help.ts +0 -27
- package/src/utils/logger.ts +0 -31
- package/src/utils/replacePackageJson.ts +0 -16
- package/src/utils/template.ts +0 -96
- package/src/utils/uiLibrary.ts +0 -493
- package/src/utils/unibestVersion.ts +0 -48
- package/src/utils/validate.ts +0 -59
- package/tsconfig.json +0 -17
- package/tsup.config.ts +0 -14
package/src/utils/uiLibrary.ts
DELETED
|
@@ -1,493 +0,0 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, existsSync } from 'node:fs'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import type { UILibrary } from '../types'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* UI 库配置接口
|
|
7
|
-
*/
|
|
8
|
-
export interface UILibraryConfig {
|
|
9
|
-
/** 包名 */
|
|
10
|
-
packageName: string
|
|
11
|
-
/** easycom 配置 */
|
|
12
|
-
easycom?: {
|
|
13
|
-
pattern: string
|
|
14
|
-
path: string
|
|
15
|
-
}
|
|
16
|
-
/** TypeScript 类型配置 */
|
|
17
|
-
types?: string[]
|
|
18
|
-
/** 是否需要在 main.ts 中引入 */
|
|
19
|
-
needMainImport?: boolean
|
|
20
|
-
/** main.ts 中的引入代码 */
|
|
21
|
-
mainImport?: string
|
|
22
|
-
/** 是否需要在 uni.scss 中引入样式 */
|
|
23
|
-
needUniScss?: boolean
|
|
24
|
-
/** uni.scss 中的引入代码 */
|
|
25
|
-
uniScssImport?: string
|
|
26
|
-
/** 是否需要在 App.vue 中引入样式 */
|
|
27
|
-
needAppVue?: boolean
|
|
28
|
-
/** App.vue 中的引入代码 */
|
|
29
|
-
appVueImport?: string
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* UI 库配置映射
|
|
34
|
-
*/
|
|
35
|
-
export const UI_LIBRARY_CONFIGS: Record<UILibrary, UILibraryConfig | null> = {
|
|
36
|
-
none: null,
|
|
37
|
-
'wot-ui': {
|
|
38
|
-
packageName: 'wot-design-uni',
|
|
39
|
-
easycom: {
|
|
40
|
-
pattern: '^wd-(.*)',
|
|
41
|
-
path: 'wot-design-uni/components/wd-$1/wd-$1.vue',
|
|
42
|
-
},
|
|
43
|
-
types: ['wot-design-uni/global.d.ts'],
|
|
44
|
-
},
|
|
45
|
-
'sard-uniapp': {
|
|
46
|
-
packageName: 'sard-uniapp',
|
|
47
|
-
easycom: {
|
|
48
|
-
pattern: '^sar-(.*)',
|
|
49
|
-
path: 'sard-uniapp/components/$1/$1.vue',
|
|
50
|
-
},
|
|
51
|
-
types: ['sard-uniapp/global'],
|
|
52
|
-
},
|
|
53
|
-
'uview-pro': {
|
|
54
|
-
packageName: 'uview-pro',
|
|
55
|
-
easycom: {
|
|
56
|
-
pattern: '^u-(.*)',
|
|
57
|
-
path: 'uview-pro/components/u-$1/u-$1.vue',
|
|
58
|
-
},
|
|
59
|
-
needMainImport: true,
|
|
60
|
-
mainImport: "import uViewPro from 'uview-pro';",
|
|
61
|
-
needUniScss: true,
|
|
62
|
-
uniScssImport: "@import 'uview-pro/theme.scss';",
|
|
63
|
-
needAppVue: true,
|
|
64
|
-
appVueImport: "@import 'uview-pro/index.scss';",
|
|
65
|
-
},
|
|
66
|
-
'uv-ui': {
|
|
67
|
-
packageName: '@climblee/uv-ui',
|
|
68
|
-
easycom: {
|
|
69
|
-
pattern: '^uv-(.*)',
|
|
70
|
-
path: '@climblee/uv-ui/components/uv-$1/uv-$1.vue',
|
|
71
|
-
},
|
|
72
|
-
types: ['@ttou/uv-typings/shim', '@ttou/uv-typings/v2'],
|
|
73
|
-
},
|
|
74
|
-
'uview-plus': {
|
|
75
|
-
packageName: 'uview-plus',
|
|
76
|
-
// uview-plus 需要多个 easycom 配置
|
|
77
|
-
easycom: {
|
|
78
|
-
pattern: '^u--(.*)',
|
|
79
|
-
path: 'uview-plus/components/u-$1/u-$1.vue',
|
|
80
|
-
},
|
|
81
|
-
types: ['uview-plus/types'],
|
|
82
|
-
needUniScss: true,
|
|
83
|
-
uniScssImport: "@import 'uview-plus/theme.scss'; // /* 行为相关颜色 */",
|
|
84
|
-
},
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* 获取 UI 库配置
|
|
89
|
-
*/
|
|
90
|
-
export function getUILibraryConfig(uiLibrary: UILibrary): UILibraryConfig | null {
|
|
91
|
-
return UI_LIBRARY_CONFIGS[uiLibrary]
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* 应用 UI 库配置到项目
|
|
96
|
-
*/
|
|
97
|
-
export async function applyUILibraryConfig(projectPath: string, uiLibrary: UILibrary): Promise<void> {
|
|
98
|
-
// 如果选择的是 none,直接返回
|
|
99
|
-
if (uiLibrary === 'none') {
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const config = getUILibraryConfig(uiLibrary)
|
|
104
|
-
if (!config) {
|
|
105
|
-
return // 未配置的 UI 库,直接返回
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// 1. 更新 package.json
|
|
109
|
-
await updatePackageJson(projectPath, config.packageName)
|
|
110
|
-
|
|
111
|
-
// 2. 更新 pages.config.ts
|
|
112
|
-
if (config.easycom) {
|
|
113
|
-
await updatePagesConfig(projectPath, config.easycom)
|
|
114
|
-
|
|
115
|
-
// uview-plus 需要多个 easycom 配置
|
|
116
|
-
if (uiLibrary === 'uview-plus') {
|
|
117
|
-
await updatePagesConfig(projectPath, {
|
|
118
|
-
pattern: '^up-(.*)',
|
|
119
|
-
path: 'uview-plus/components/u-$1/u-$1.vue',
|
|
120
|
-
})
|
|
121
|
-
await updatePagesConfig(projectPath, {
|
|
122
|
-
pattern: '^u-([^-].*)',
|
|
123
|
-
path: 'uview-plus/components/u-$1/u-$1.vue',
|
|
124
|
-
})
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// 3. 更新 tsconfig.json
|
|
129
|
-
if (config.types && config.types.length > 0) {
|
|
130
|
-
await updateTsConfig(projectPath, config.types)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// 4. 更新 main.ts
|
|
134
|
-
if (config.needMainImport && config.mainImport) {
|
|
135
|
-
await updateMainTs(projectPath, config.mainImport)
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// 5. 更新 uni.scss
|
|
139
|
-
if (config.needUniScss && config.uniScssImport) {
|
|
140
|
-
await updateUniScss(projectPath, config.uniScssImport)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// 6. 更新 App.vue
|
|
144
|
-
if (config.needAppVue && config.appVueImport) {
|
|
145
|
-
await updateAppVue(projectPath, config.appVueImport)
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* 更新 package.json,添加 UI 库依赖
|
|
151
|
-
*/
|
|
152
|
-
async function updatePackageJson(projectPath: string, packageName: string): Promise<void> {
|
|
153
|
-
const packageJsonPath = join(projectPath, 'package.json')
|
|
154
|
-
if (!existsSync(packageJsonPath)) {
|
|
155
|
-
return
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
|
|
159
|
-
if (!packageJson.dependencies) {
|
|
160
|
-
packageJson.dependencies = {}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// 如果依赖已存在,不重复添加
|
|
164
|
-
if (!packageJson.dependencies[packageName]) {
|
|
165
|
-
packageJson.dependencies[packageName] = 'latest'
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n')
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* 更新 pages.config.ts,添加 easycom 配置
|
|
173
|
-
*/
|
|
174
|
-
async function updatePagesConfig(projectPath: string, easycom: { pattern: string; path: string }): Promise<void> {
|
|
175
|
-
const pagesConfigPath = join(projectPath, 'pages.config.ts')
|
|
176
|
-
if (!existsSync(pagesConfigPath)) {
|
|
177
|
-
return
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const originalContent = readFileSync(pagesConfigPath, 'utf8')
|
|
181
|
-
let content = originalContent
|
|
182
|
-
|
|
183
|
-
const patternLiteral = escapeSingleQuotes(easycom.pattern)
|
|
184
|
-
const pathLiteral = escapeSingleQuotes(easycom.path)
|
|
185
|
-
const existingEntryRegex = new RegExp(
|
|
186
|
-
`["']${escapeForRegExp(patternLiteral)}["']\\s*:\\s*["']${escapeForRegExp(pathLiteral)}["']`,
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
if (existingEntryRegex.test(content)) {
|
|
190
|
-
return
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const entry = { pattern: patternLiteral, path: pathLiteral }
|
|
194
|
-
|
|
195
|
-
content =
|
|
196
|
-
addToExistingCustomBlock(content, entry) ??
|
|
197
|
-
addCustomBlock(content, entry) ??
|
|
198
|
-
addEasycomBlock(content, entry) ??
|
|
199
|
-
appendEasycomBlock(content, entry)
|
|
200
|
-
|
|
201
|
-
if (content !== originalContent) {
|
|
202
|
-
writeFileSync(pagesConfigPath, ensureTrailingNewline(content))
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* 更新 tsconfig.json,添加类型配置
|
|
208
|
-
*/
|
|
209
|
-
async function updateTsConfig(projectPath: string, types: string[]): Promise<void> {
|
|
210
|
-
const tsConfigPath = join(projectPath, 'tsconfig.json')
|
|
211
|
-
if (!existsSync(tsConfigPath)) {
|
|
212
|
-
return
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const tsConfig = JSON.parse(readFileSync(tsConfigPath, 'utf8'))
|
|
216
|
-
|
|
217
|
-
if (!tsConfig.compilerOptions) {
|
|
218
|
-
tsConfig.compilerOptions = {}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (!tsConfig.compilerOptions.types) {
|
|
222
|
-
tsConfig.compilerOptions.types = []
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// 添加新的类型,避免重复
|
|
226
|
-
const existingTypes = tsConfig.compilerOptions.types as string[]
|
|
227
|
-
for (const type of types) {
|
|
228
|
-
if (!existingTypes.includes(type)) {
|
|
229
|
-
existingTypes.push(type)
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
writeFileSync(tsConfigPath, JSON.stringify(tsConfig, null, 2) + '\n')
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* 更新 main.ts,添加 UI 库引入
|
|
238
|
-
*/
|
|
239
|
-
async function updateMainTs(projectPath: string, importCode: string): Promise<void> {
|
|
240
|
-
const mainTsPath = join(projectPath, 'src', 'main.ts')
|
|
241
|
-
if (!existsSync(mainTsPath)) {
|
|
242
|
-
return
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
let content = readFileSync(mainTsPath, 'utf8')
|
|
246
|
-
|
|
247
|
-
// 检查是否已存在该引入(通过包名检查)
|
|
248
|
-
const firstLine = importCode.split('\n')[0]
|
|
249
|
-
if (content.includes(firstLine)) {
|
|
250
|
-
return
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// 查找 import { createSSRApp } from "vue" 的位置
|
|
254
|
-
const vueImportRegex = /(import\s+.*from\s+['"]vue['"];?\s*\n)/
|
|
255
|
-
const match = content.match(vueImportRegex)
|
|
256
|
-
|
|
257
|
-
if (match) {
|
|
258
|
-
// 在 vue import 之后添加 UI 库引入
|
|
259
|
-
content = content.replace(vueImportRegex, `$1${importCode}\n`)
|
|
260
|
-
} else {
|
|
261
|
-
// 如果找不到 vue import,在文件开头添加
|
|
262
|
-
content = `${importCode}\n\n${content}`
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// 对于 uview-pro,需要添加 app.use(uViewPro)
|
|
266
|
-
if (importCode.includes('uview-pro')) {
|
|
267
|
-
const appUseRegex = /(const\s+app\s*=\s*createSSRApp\(App\);?\s*\n)/
|
|
268
|
-
const appUseMatch = content.match(appUseRegex)
|
|
269
|
-
|
|
270
|
-
if (appUseMatch && !content.includes('app.use(uViewPro)')) {
|
|
271
|
-
content = content.replace(appUseRegex, `$1 app.use(uViewPro);\n`)
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
writeFileSync(mainTsPath, content)
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* 更新 uni.scss,添加样式引入
|
|
280
|
-
*/
|
|
281
|
-
async function updateUniScss(projectPath: string, importCode: string): Promise<void> {
|
|
282
|
-
const uniScssPath = join(projectPath, 'src', 'style', 'uni.scss')
|
|
283
|
-
if (!existsSync(uniScssPath)) {
|
|
284
|
-
// 尝试其他可能的位置
|
|
285
|
-
const altPath = join(projectPath, 'uni.scss')
|
|
286
|
-
if (existsSync(altPath)) {
|
|
287
|
-
await updateScssFile(altPath, importCode)
|
|
288
|
-
}
|
|
289
|
-
return
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
await updateScssFile(uniScssPath, importCode)
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* 更新 SCSS 文件,在末尾添加引入
|
|
297
|
-
*/
|
|
298
|
-
async function updateScssFile(filePath: string, importCode: string): Promise<void> {
|
|
299
|
-
let content = readFileSync(filePath, 'utf8')
|
|
300
|
-
|
|
301
|
-
// 检查是否已存在该引入
|
|
302
|
-
if (content.includes(importCode)) {
|
|
303
|
-
return
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// 在文件末尾添加引入
|
|
307
|
-
content = `${content.trim()}\n${importCode}\n`
|
|
308
|
-
writeFileSync(filePath, content)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* 更新 App.vue,添加样式引入
|
|
313
|
-
*/
|
|
314
|
-
async function updateAppVue(projectPath: string, importCode: string): Promise<void> {
|
|
315
|
-
const appVuePath = join(projectPath, 'src', 'App.vue')
|
|
316
|
-
if (!existsSync(appVuePath)) {
|
|
317
|
-
return
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
let content = readFileSync(appVuePath, 'utf8')
|
|
321
|
-
|
|
322
|
-
// 检查是否已存在该引入
|
|
323
|
-
if (content.includes(importCode)) {
|
|
324
|
-
return
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// 查找 <style> 标签
|
|
328
|
-
const styleRegex = /(<style[^>]*>)/s
|
|
329
|
-
const match = content.match(styleRegex)
|
|
330
|
-
|
|
331
|
-
if (match) {
|
|
332
|
-
// 在 <style> 标签后添加引入
|
|
333
|
-
content = content.replace(styleRegex, `$1\n${importCode}`)
|
|
334
|
-
} else {
|
|
335
|
-
// 如果没有 style 标签,在文件末尾添加
|
|
336
|
-
content = `${content}\n<style lang="scss">\n${importCode}\n</style>`
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
writeFileSync(appVuePath, content)
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
interface EasycomEntry {
|
|
343
|
-
pattern: string
|
|
344
|
-
path: string
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
function addToExistingCustomBlock(content: string, entry: EasycomEntry): string | null {
|
|
348
|
-
const customIndex = content.indexOf('custom:')
|
|
349
|
-
if (customIndex === -1) {
|
|
350
|
-
return null
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const braceIndex = content.indexOf('{', customIndex)
|
|
354
|
-
if (braceIndex === -1) {
|
|
355
|
-
return null
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
const closingIndex = findMatchingBrace(content, braceIndex)
|
|
359
|
-
if (closingIndex === -1) {
|
|
360
|
-
return null
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
const inside = content.slice(braceIndex + 1, closingIndex)
|
|
364
|
-
const hasEntries = inside.trim().length > 0
|
|
365
|
-
const entryIndent = getLineIndent(content, braceIndex) + ' '
|
|
366
|
-
const entryLine = `${entryIndent}'${entry.pattern}': '${entry.path}',`
|
|
367
|
-
|
|
368
|
-
if (!hasEntries) {
|
|
369
|
-
const closingIndent = getLineIndent(content, closingIndex)
|
|
370
|
-
return (
|
|
371
|
-
content.slice(0, braceIndex + 1) +
|
|
372
|
-
`
|
|
373
|
-
${entryLine}
|
|
374
|
-
${closingIndent}` +
|
|
375
|
-
content.slice(closingIndex)
|
|
376
|
-
)
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
const beforeRaw = content.slice(0, closingIndex).replace(/\s*$/, '')
|
|
380
|
-
const separator = beforeRaw.endsWith('\n') ? '' : '\n'
|
|
381
|
-
const after = content.slice(closingIndex)
|
|
382
|
-
return `${beforeRaw}${separator}${entryLine}
|
|
383
|
-
${after}`
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
function addCustomBlock(content: string, entry: EasycomEntry): string | null {
|
|
387
|
-
const easycomIndex = content.indexOf('easycom:')
|
|
388
|
-
if (easycomIndex === -1) {
|
|
389
|
-
return null
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
const braceIndex = content.indexOf('{', easycomIndex)
|
|
393
|
-
if (braceIndex === -1) {
|
|
394
|
-
return null
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
const closingIndex = findMatchingBrace(content, braceIndex)
|
|
398
|
-
if (closingIndex === -1) {
|
|
399
|
-
return null
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
const easycomIndent = getLineIndent(content, braceIndex)
|
|
403
|
-
const customIndent = easycomIndent + ' '
|
|
404
|
-
const entryIndent = customIndent + ' '
|
|
405
|
-
const customBlock = `${customIndent}custom: {
|
|
406
|
-
${entryIndent}'${entry.pattern}': '${entry.path}',
|
|
407
|
-
${customIndent}},`
|
|
408
|
-
|
|
409
|
-
const beforeRaw = content.slice(0, closingIndex).replace(/\s*$/, '')
|
|
410
|
-
const separator = beforeRaw.endsWith('\n') ? '' : '\n'
|
|
411
|
-
const after = content.slice(closingIndex)
|
|
412
|
-
return `${beforeRaw}${separator}${customBlock}
|
|
413
|
-
${after}`
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
function addEasycomBlock(content: string, entry: EasycomEntry): string | null {
|
|
417
|
-
const exportIndex = content.indexOf('export default')
|
|
418
|
-
if (exportIndex === -1) {
|
|
419
|
-
return null
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
const braceIndex = content.indexOf('{', exportIndex)
|
|
423
|
-
if (braceIndex === -1) {
|
|
424
|
-
return null
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
const closingIndex = findMatchingBrace(content, braceIndex)
|
|
428
|
-
if (closingIndex === -1) {
|
|
429
|
-
return null
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
const blockIndent = getLineIndent(content, braceIndex) + ' '
|
|
433
|
-
const entryIndent = blockIndent + ' '
|
|
434
|
-
const block = `${blockIndent}easycom: {
|
|
435
|
-
${blockIndent} autoscan: true,
|
|
436
|
-
${blockIndent} custom: {
|
|
437
|
-
${entryIndent}'${entry.pattern}': '${entry.path}',
|
|
438
|
-
${blockIndent} },
|
|
439
|
-
${blockIndent}},`
|
|
440
|
-
|
|
441
|
-
const before = content.slice(0, braceIndex + 1)
|
|
442
|
-
const after = content.slice(braceIndex + 1)
|
|
443
|
-
const prefix = before.endsWith('\n') ? before : `${before}\n`
|
|
444
|
-
return `${prefix}${block}
|
|
445
|
-
${after}`
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
function appendEasycomBlock(content: string, entry: EasycomEntry): string {
|
|
449
|
-
const block = `
|
|
450
|
-
export const easycom = {
|
|
451
|
-
autoscan: true,
|
|
452
|
-
custom: {
|
|
453
|
-
'${entry.pattern}': '${entry.path}',
|
|
454
|
-
},
|
|
455
|
-
}
|
|
456
|
-
`
|
|
457
|
-
return `${content}${block}`
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
function findMatchingBrace(content: string, startIndex: number): number {
|
|
461
|
-
let depth = 0
|
|
462
|
-
for (let i = startIndex; i < content.length; i += 1) {
|
|
463
|
-
const char = content[i]
|
|
464
|
-
if (char === '{') {
|
|
465
|
-
depth += 1
|
|
466
|
-
} else if (char === '}') {
|
|
467
|
-
depth -= 1
|
|
468
|
-
if (depth === 0) {
|
|
469
|
-
return i
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
return -1
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
function getLineIndent(content: string, index: number): string {
|
|
477
|
-
const lineStart = content.lastIndexOf('\n', index) + 1
|
|
478
|
-
const line = content.slice(lineStart, index)
|
|
479
|
-
const match = line.match(/^\s*/)
|
|
480
|
-
return match ? match[0] : ''
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
function escapeSingleQuotes(value: string): string {
|
|
484
|
-
return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'")
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
function escapeForRegExp(value: string): string {
|
|
488
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
function ensureTrailingNewline(value: string): string {
|
|
492
|
-
return value.endsWith('\n') ? value : `${value}\n`
|
|
493
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import fetch from 'node-fetch'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Gitee API 返回的文件响应接口
|
|
5
|
-
*/
|
|
6
|
-
interface GiteeFileResponse {
|
|
7
|
-
content: string
|
|
8
|
-
encoding: string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* 获取 unibest 仓库的最新版本号
|
|
13
|
-
* @returns 版本号字符串或 null(如果获取失败)
|
|
14
|
-
*/
|
|
15
|
-
async function getUnibestVersion(): Promise<string | null> {
|
|
16
|
-
try {
|
|
17
|
-
const apiUrl = `https://gitee.com/api/v5/repos/feige996/unibest/contents/package.json?ref=main`
|
|
18
|
-
const response = await fetch(apiUrl, {
|
|
19
|
-
method: 'GET',
|
|
20
|
-
headers: {
|
|
21
|
-
'Content-Type': 'application/json',
|
|
22
|
-
},
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
if (response.ok) {
|
|
26
|
-
const data = (await response.json()) as GiteeFileResponse
|
|
27
|
-
const { content, encoding } = data
|
|
28
|
-
|
|
29
|
-
if (encoding === 'base64') {
|
|
30
|
-
// 使用 Node.js 内置的 Buffer 解码 base64 内容
|
|
31
|
-
const decodedContent = Buffer.from(content, 'base64').toString('utf8')
|
|
32
|
-
const packageJson = JSON.parse(decodedContent)
|
|
33
|
-
return packageJson.version || null
|
|
34
|
-
} else {
|
|
35
|
-
// console.error(`Unsupported encoding: ${encoding}`);
|
|
36
|
-
return null
|
|
37
|
-
}
|
|
38
|
-
} else {
|
|
39
|
-
// console.error(`Request failed with status: ${response.status}`);
|
|
40
|
-
return null
|
|
41
|
-
}
|
|
42
|
-
} catch (error) {
|
|
43
|
-
// console.error(`An error occurred: ${error}`);
|
|
44
|
-
return null
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export default getUnibestVersion
|
package/src/utils/validate.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { logger } from './logger'
|
|
2
|
-
import { existsSync } from 'fs'
|
|
3
|
-
import { yellow } from 'kolorist'
|
|
4
|
-
import { join } from 'path'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 验证项目名称是否符合规范
|
|
8
|
-
* npm包命名规则:只能包含小写字母、数字、连字符和下划线,且不能以连字符开头或结尾
|
|
9
|
-
* @param name - 项目名称
|
|
10
|
-
* @returns 是否有效
|
|
11
|
-
*/
|
|
12
|
-
export function validateProjectName(name: string): boolean {
|
|
13
|
-
const reg = /^[a-z0-9_-]+$/
|
|
14
|
-
if (!reg.test(name)) {
|
|
15
|
-
return false
|
|
16
|
-
}
|
|
17
|
-
if (name.startsWith('-') || name.endsWith('-')) {
|
|
18
|
-
return false
|
|
19
|
-
}
|
|
20
|
-
return true
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* 先检查目录是否已存在,再验证名称格式是否符合规范
|
|
25
|
-
* @param projectName - 项目名称
|
|
26
|
-
* @returns 错误信息或undefined
|
|
27
|
-
*/
|
|
28
|
-
export function checkProjectNameExistAndValidate(_projectName: string): string {
|
|
29
|
-
const projectName = _projectName.trim()
|
|
30
|
-
if (existsSync(join(process.cwd(), projectName))) {
|
|
31
|
-
return `目录 ${yellow(projectName)} 已存在,请选择其他名称`
|
|
32
|
-
}
|
|
33
|
-
if (!validateProjectName(projectName)) {
|
|
34
|
-
return `项目名称 ${yellow(projectName)} 不符合规范,请使用字母、数字、连字符或下划线`
|
|
35
|
-
}
|
|
36
|
-
return ''
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* 验证项目配置是否完整
|
|
41
|
-
* @param options - 项目配置选项
|
|
42
|
-
* @returns 是否有效
|
|
43
|
-
*/
|
|
44
|
-
export function validateProjectOptions(options: Record<string, any>): boolean {
|
|
45
|
-
const requiredFields = ['projectName', 'platforms', 'uiLibrary', 'requestLibrary']
|
|
46
|
-
const missingFields = requiredFields.filter(field => !options[field])
|
|
47
|
-
|
|
48
|
-
if (missingFields.length > 0) {
|
|
49
|
-
logger.error(`项目配置不完整,缺少以下字段: ${missingFields.join(', ')}`)
|
|
50
|
-
return false
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (!Array.isArray(options.platforms) || options.platforms.length === 0) {
|
|
54
|
-
logger.error('至少需要选择一个平台')
|
|
55
|
-
return false
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return true
|
|
59
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "es2022",
|
|
4
|
-
"module": "esnext",
|
|
5
|
-
"moduleResolution": "node",
|
|
6
|
-
"esModuleInterop": true,
|
|
7
|
-
"allowSyntheticDefaultImports": true,
|
|
8
|
-
"strict": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
"resolveJsonModule": true,
|
|
12
|
-
"isolatedModules": true,
|
|
13
|
-
"noEmit": true
|
|
14
|
-
},
|
|
15
|
-
"include": ["src/**/*"],
|
|
16
|
-
"exclude": ["node_modules", "dist"]
|
|
17
|
-
}
|
package/tsup.config.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'tsup'
|
|
2
|
-
|
|
3
|
-
// 检查是否为开发环境(通过NODE_ENV环境变量)
|
|
4
|
-
const isProduction = process.env.NODE_ENV === 'production'
|
|
5
|
-
|
|
6
|
-
export default defineConfig({
|
|
7
|
-
entry: ['src/index.ts'],
|
|
8
|
-
outDir: 'dist',
|
|
9
|
-
format: ['esm'],
|
|
10
|
-
target: 'esnext',
|
|
11
|
-
clean: true,
|
|
12
|
-
sourcemap: !isProduction, // 开发环境启用sourcemap,生产环境禁用
|
|
13
|
-
dts: true,
|
|
14
|
-
})
|