@liujitcn/kratos-uni-app-core 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -0
- package/dist/module.mjs +84 -0
- package/dist/vite.mjs +405 -0
- package/package.json +58 -0
- package/src/api/base/config.ts +20 -0
- package/src/api/base/file.ts +79 -0
- package/src/api/base/login.ts +87 -0
- package/src/api/base/menu.ts +17 -0
- package/src/api/base/oauth.ts +149 -0
- package/src/api/system/auth.ts +54 -0
- package/src/api/system/base_area.ts +34 -0
- package/src/api/system/base_dict.ts +24 -0
- package/src/bootstrap.ts +23 -0
- package/src/components/BootstrapStatus.vue +39 -0
- package/src/components/KratosTabBar.vue +73 -0
- package/src/index.ts +6 -0
- package/src/module.ts +85 -0
- package/src/navigation-pattern.d.mts +2 -0
- package/src/navigation-pattern.mjs +29 -0
- package/src/navigation-tree.mjs +45 -0
- package/src/navigation.ts +330 -0
- package/src/pages.ts +26 -0
- package/src/rpc/base/v1/config.ts +34 -0
- package/src/rpc/base/v1/file.ts +66 -0
- package/src/rpc/base/v1/login.ts +128 -0
- package/src/rpc/base/v1/mcp.ts +20 -0
- package/src/rpc/base/v1/oauth.ts +199 -0
- package/src/rpc/base/v1/sse.ts +22 -0
- package/src/rpc/common/v1/common.ts +71 -0
- package/src/rpc/common/v1/enum.ts +71 -0
- package/src/rpc/common/v1/types.ts +77 -0
- package/src/rpc/google/protobuf/empty.ts +19 -0
- package/src/rpc/google/protobuf/wrappers.ts +124 -0
- package/src/rpc/system/app/v1/auth.ts +54 -0
- package/src/rpc/system/app/v1/base_area.ts +24 -0
- package/src/rpc/system/app/v1/base_dict.ts +37 -0
- package/src/rpc/system/app/v1/base_menu.ts +61 -0
- package/src/rpc/system/common/v1/enum.ts +80 -0
- package/src/static/images/avatar.png +0 -0
- package/src/static/images/center_bg.png +0 -0
- package/src/static/images/logo_icon.png +0 -0
- package/src/static/images/navigator_bg.png +0 -0
- package/src/static/tabs/home_default.png +0 -0
- package/src/static/tabs/home_selected.png +0 -0
- package/src/static/tabs/user_default.png +0 -0
- package/src/static/tabs/user_selected.png +0 -0
- package/src/stores/index.ts +14 -0
- package/src/stores/modules/setting.ts +56 -0
- package/src/stores/modules/user.ts +266 -0
- package/src/styles/base.scss +42 -0
- package/src/types/env.d.ts +24 -0
- package/src/types/go-captcha-uni.d.ts +7 -0
- package/src/types/uni-helper.d.ts +54 -0
- package/src/uni.scss +76 -0
- package/src/utils/auth.ts +67 -0
- package/src/utils/file.ts +95 -0
- package/src/utils/http.ts +430 -0
- package/src/utils/index.ts +79 -0
- package/src/utils/navigation.ts +81 -0
- package/src/utils/passwordCrypto.ts +275 -0
- package/src/views/pages/index/index.vue +227 -0
- package/src/views/pages/login/login.vue +1133 -0
- package/src/views/pages/login/protocal.vue +176 -0
- package/src/views/pages/status/index.vue +36 -0
- package/src/views/pages/webview/webview.vue +136 -0
- package/src/vite.ts +474 -0
package/src/vite.ts
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
import {
|
|
2
|
+
copyFileSync,
|
|
3
|
+
existsSync,
|
|
4
|
+
mkdirSync,
|
|
5
|
+
readFileSync,
|
|
6
|
+
readdirSync,
|
|
7
|
+
rmdirSync,
|
|
8
|
+
rmSync,
|
|
9
|
+
statSync,
|
|
10
|
+
unlinkSync,
|
|
11
|
+
writeFileSync,
|
|
12
|
+
} from 'node:fs'
|
|
13
|
+
import { createRequire } from 'node:module'
|
|
14
|
+
import { dirname, isAbsolute, relative, resolve } from 'node:path'
|
|
15
|
+
import uniPlugin from '@dcloudio/vite-plugin-uni'
|
|
16
|
+
import { defineConfig, loadEnv } from 'vite'
|
|
17
|
+
import type { Plugin, UserConfig } from 'vite'
|
|
18
|
+
import type { KratosAppModule, KratosAppPageConfig } from './module'
|
|
19
|
+
|
|
20
|
+
export { defineConfig, loadEnv }
|
|
21
|
+
export type { ConfigEnv, UserConfig } from 'vite'
|
|
22
|
+
|
|
23
|
+
type PageEntry = { path: string; style?: Record<string, unknown> }
|
|
24
|
+
type SubPackage = { root: string; pages: PageEntry[] }
|
|
25
|
+
type PagesManifest = {
|
|
26
|
+
pages: PageEntry[]
|
|
27
|
+
subPackages?: SubPackage[]
|
|
28
|
+
[key: string]: unknown
|
|
29
|
+
}
|
|
30
|
+
type ScannedPage = {
|
|
31
|
+
route: string
|
|
32
|
+
source: string
|
|
33
|
+
style?: Record<string, unknown>
|
|
34
|
+
}
|
|
35
|
+
let sourceVersionCounter = 0
|
|
36
|
+
type BuildTransaction = {
|
|
37
|
+
inputDir: string
|
|
38
|
+
pagesFile: string
|
|
39
|
+
originalPages: string
|
|
40
|
+
generatedFiles: string[]
|
|
41
|
+
generatedStaticFiles: string[]
|
|
42
|
+
generatedStatic?: boolean
|
|
43
|
+
ownerPid?: number
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** uni-app Vite 插件参数。 */
|
|
47
|
+
export interface KratosAppViteOptions {
|
|
48
|
+
/** 宿主模块清单,顺序同时决定覆盖优先级。 */
|
|
49
|
+
modules: KratosAppModule[]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** 创建 uni-app 官方 Vite 插件。 */
|
|
53
|
+
export function createKratosUniPlugin() {
|
|
54
|
+
const createPlugin =
|
|
55
|
+
typeof uniPlugin === 'function'
|
|
56
|
+
? uniPlugin
|
|
57
|
+
: (uniPlugin as unknown as { default: typeof uniPlugin }).default
|
|
58
|
+
return createPlugin()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** 创建自动页面装配插件。 */
|
|
62
|
+
export function kratosApp(options: KratosAppViteOptions): Plugin {
|
|
63
|
+
const sourceVersion = `${process.pid}-${Date.now()}-${++sourceVersionCounter}`
|
|
64
|
+
const state: {
|
|
65
|
+
inputDir?: string
|
|
66
|
+
pagesFile?: string
|
|
67
|
+
originalPages?: string
|
|
68
|
+
generatedFiles: string[]
|
|
69
|
+
generatedStaticFiles: string[]
|
|
70
|
+
cleaned: boolean
|
|
71
|
+
persistent: boolean
|
|
72
|
+
transactionFile?: string
|
|
73
|
+
moduleRoots: Map<string, string>
|
|
74
|
+
} = {
|
|
75
|
+
generatedFiles: [],
|
|
76
|
+
generatedStaticFiles: [],
|
|
77
|
+
cleaned: false,
|
|
78
|
+
persistent: false,
|
|
79
|
+
moduleRoots: new Map(),
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const cleanup = () => {
|
|
83
|
+
if (state.cleaned) return
|
|
84
|
+
state.cleaned = true
|
|
85
|
+
process.removeListener('exit', cleanup)
|
|
86
|
+
process.removeListener('SIGINT', handleSigint)
|
|
87
|
+
process.removeListener('SIGTERM', handleSigterm)
|
|
88
|
+
for (const file of [...state.generatedFiles].reverse()) {
|
|
89
|
+
if (existsSync(file)) unlinkSync(file)
|
|
90
|
+
removeEmptyParents(dirname(file), state.inputDir ?? '')
|
|
91
|
+
}
|
|
92
|
+
if (state.inputDir) {
|
|
93
|
+
removeGeneratedStaticFiles(state.generatedStaticFiles, resolve(state.inputDir, 'static'))
|
|
94
|
+
}
|
|
95
|
+
if (state.pagesFile && state.originalPages !== undefined) {
|
|
96
|
+
writeFileSync(state.pagesFile, state.originalPages)
|
|
97
|
+
}
|
|
98
|
+
if (state.transactionFile && existsSync(state.transactionFile)) {
|
|
99
|
+
unlinkSync(state.transactionFile)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const handleSigint = () => {
|
|
103
|
+
cleanup()
|
|
104
|
+
process.exit(130)
|
|
105
|
+
}
|
|
106
|
+
const handleSigterm = () => {
|
|
107
|
+
cleanup()
|
|
108
|
+
process.exit(143)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
name: 'kratos-uni-app-pages',
|
|
113
|
+
enforce: 'pre',
|
|
114
|
+
configResolved(config) {
|
|
115
|
+
state.persistent = config.command === 'serve' || Boolean(config.build.watch)
|
|
116
|
+
},
|
|
117
|
+
resolveId(source, importer) {
|
|
118
|
+
const [sourcePath, query = ''] = source.split('?', 2)
|
|
119
|
+
let target: string | undefined
|
|
120
|
+
if (
|
|
121
|
+
sourcePath === '@liujitcn/kratos-uni-app-core' ||
|
|
122
|
+
sourcePath.startsWith('@liujitcn/kratos-uni-app-core/')
|
|
123
|
+
) {
|
|
124
|
+
const coreRoot = state.moduleRoots.get('@liujitcn/kratos-uni-app-core')
|
|
125
|
+
if (coreRoot) {
|
|
126
|
+
target = resolveWorkspacePackageSource(
|
|
127
|
+
coreRoot,
|
|
128
|
+
sourcePath.slice('@liujitcn/kratos-uni-app-core'.length).replace(/^\/+/, ''),
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
} else if (
|
|
132
|
+
sourcePath === '@liujitcn/kratos-uni-app-system' ||
|
|
133
|
+
sourcePath.startsWith('@liujitcn/kratos-uni-app-system/')
|
|
134
|
+
) {
|
|
135
|
+
const systemRoot = state.moduleRoots.get('@liujitcn/kratos-uni-app-system')
|
|
136
|
+
if (systemRoot) {
|
|
137
|
+
target = resolveWorkspacePackageSource(
|
|
138
|
+
systemRoot,
|
|
139
|
+
sourcePath.slice('@liujitcn/kratos-uni-app-system'.length).replace(/^\/+/, ''),
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
} else if (sourcePath.startsWith('@kratos-uni-app-system-source/')) {
|
|
143
|
+
const systemRoot = state.moduleRoots.get('@liujitcn/kratos-uni-app-system')
|
|
144
|
+
if (systemRoot) {
|
|
145
|
+
target = resolve(
|
|
146
|
+
systemRoot,
|
|
147
|
+
'src',
|
|
148
|
+
sourcePath.slice('@kratos-uni-app-system-source/'.length),
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
} else if (sourcePath.startsWith('@kratos-uni-app-core-source/')) {
|
|
152
|
+
const coreRoot = state.moduleRoots.get('@liujitcn/kratos-uni-app-core')
|
|
153
|
+
if (coreRoot) {
|
|
154
|
+
target = resolve(coreRoot, 'src', sourcePath.slice('@kratos-uni-app-core-source/'.length))
|
|
155
|
+
}
|
|
156
|
+
} else if (sourcePath.startsWith('.') && importer) {
|
|
157
|
+
const importerPath = importer.split('?', 1)[0]
|
|
158
|
+
const moduleRoot = [...state.moduleRoots.values()].find((root) =>
|
|
159
|
+
isWithinRoot(resolve(root, 'src'), importerPath),
|
|
160
|
+
)
|
|
161
|
+
if (moduleRoot) target = resolve(dirname(importerPath), sourcePath)
|
|
162
|
+
}
|
|
163
|
+
if (!target) return
|
|
164
|
+
const resolved = resolveSourceFile(target)
|
|
165
|
+
const importQuery = query || dependencyVersionQuery(importer, sourceVersion)
|
|
166
|
+
return `${resolved}${importQuery ? `?${importQuery}` : ''}`
|
|
167
|
+
},
|
|
168
|
+
transform(code, id) {
|
|
169
|
+
const sourceFile = id.split('?', 1)[0]
|
|
170
|
+
const isModuleSource = [...state.moduleRoots.values()].some((root) =>
|
|
171
|
+
isWithinRoot(resolve(root, 'src'), sourceFile),
|
|
172
|
+
)
|
|
173
|
+
const isLinkedModuleSource =
|
|
174
|
+
sourceFile.includes('/@liujitcn/kratos-uni-app-core/') ||
|
|
175
|
+
sourceFile.includes('/@liujitcn/kratos-uni-app-system/')
|
|
176
|
+
if (!isModuleSource && !isLinkedModuleSource) return
|
|
177
|
+
const transformed = code
|
|
178
|
+
.replace(/@system\//g, '@kratos-uni-app-system-source/')
|
|
179
|
+
.replace(/@\//g, '@kratos-uni-app-core-source/')
|
|
180
|
+
if (transformed === code) return
|
|
181
|
+
return { code: transformed, map: null }
|
|
182
|
+
},
|
|
183
|
+
config(): UserConfig {
|
|
184
|
+
const inputDir = process.env.UNI_INPUT_DIR || resolve(process.cwd(), 'src')
|
|
185
|
+
const pagesFile = resolve(inputDir, 'pages.json')
|
|
186
|
+
const transactionFile = resolve(inputDir, '../.kratos-uni-app-pages-state.json')
|
|
187
|
+
recoverBuildTransaction(transactionFile, inputDir, pagesFile)
|
|
188
|
+
const hostRequire = createRequire(resolve(inputDir, '../package.json'))
|
|
189
|
+
const originalPages = readFileSync(pagesFile, 'utf8')
|
|
190
|
+
const manifest = JSON.parse(originalPages) as PagesManifest
|
|
191
|
+
manifest.pages ??= []
|
|
192
|
+
const pageMap = new Map<string, ScannedPage>()
|
|
193
|
+
const moduleRoots = options.modules.map((module) => {
|
|
194
|
+
const linkedRoot = resolve(inputDir, '../node_modules', ...module.name.split('/'))
|
|
195
|
+
return {
|
|
196
|
+
module,
|
|
197
|
+
root: existsSync(resolve(linkedRoot, 'package.json'))
|
|
198
|
+
? linkedRoot
|
|
199
|
+
: dirname(hostRequire.resolve(`${module.name}/package.json`)),
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
state.moduleRoots = new Map(moduleRoots.map(({ module, root }) => [module.name, root]))
|
|
203
|
+
|
|
204
|
+
moduleRoots.forEach(({ module, root }) => {
|
|
205
|
+
scanViews(resolve(root, 'src/views')).forEach((page) => {
|
|
206
|
+
const config = module.pages[page.route] ?? {}
|
|
207
|
+
const route = normalizeRoute(config.route ?? page.route)
|
|
208
|
+
pageMap.set(route, {
|
|
209
|
+
route,
|
|
210
|
+
source: `${module.name}/views/${page.route}.vue`,
|
|
211
|
+
style: config.style,
|
|
212
|
+
})
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
state.inputDir = inputDir
|
|
217
|
+
state.pagesFile = pagesFile
|
|
218
|
+
state.originalPages = originalPages
|
|
219
|
+
state.transactionFile = transactionFile
|
|
220
|
+
state.generatedFiles = [...pageMap.values()]
|
|
221
|
+
.map((page) => resolve(inputDir, `${page.route}.vue`))
|
|
222
|
+
.filter((target) => !existsSync(target))
|
|
223
|
+
const staticTarget = resolve(inputDir, 'static')
|
|
224
|
+
const staticFiles = collectModuleStaticFiles(
|
|
225
|
+
moduleRoots.map(({ root }) => resolve(root, 'src/static')),
|
|
226
|
+
staticTarget,
|
|
227
|
+
)
|
|
228
|
+
state.generatedStaticFiles = staticFiles.map(({ target }) => target)
|
|
229
|
+
writeFileSync(
|
|
230
|
+
transactionFile,
|
|
231
|
+
`${JSON.stringify(
|
|
232
|
+
{
|
|
233
|
+
inputDir,
|
|
234
|
+
pagesFile,
|
|
235
|
+
originalPages,
|
|
236
|
+
generatedFiles: state.generatedFiles,
|
|
237
|
+
generatedStaticFiles: state.generatedStaticFiles,
|
|
238
|
+
ownerPid: process.pid,
|
|
239
|
+
} satisfies BuildTransaction,
|
|
240
|
+
null,
|
|
241
|
+
2,
|
|
242
|
+
)}\n`,
|
|
243
|
+
{ flag: 'wx' },
|
|
244
|
+
)
|
|
245
|
+
pageMap.forEach((page) => {
|
|
246
|
+
const target = resolve(inputDir, `${page.route}.vue`)
|
|
247
|
+
if (existsSync(target)) return
|
|
248
|
+
mkdirSync(dirname(target), { recursive: true })
|
|
249
|
+
writeFileSync(target, createPageWrapper(page))
|
|
250
|
+
appendPage(manifest, page)
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
staticFiles.forEach(({ source, target }) => {
|
|
254
|
+
mkdirSync(dirname(target), { recursive: true })
|
|
255
|
+
copyFileSync(source, target)
|
|
256
|
+
})
|
|
257
|
+
writeFileSync(pagesFile, `${JSON.stringify(manifest, null, 2)}\n`)
|
|
258
|
+
process.once('exit', cleanup)
|
|
259
|
+
process.prependOnceListener('SIGINT', handleSigint)
|
|
260
|
+
process.prependOnceListener('SIGTERM', handleSigterm)
|
|
261
|
+
return {
|
|
262
|
+
resolve: {
|
|
263
|
+
alias: [
|
|
264
|
+
{
|
|
265
|
+
find: '@kratos-uni-app-core-source',
|
|
266
|
+
replacement: resolve(
|
|
267
|
+
state.moduleRoots.get('@liujitcn/kratos-uni-app-core') ?? '',
|
|
268
|
+
'src',
|
|
269
|
+
),
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
find: '@kratos-uni-app-system-source',
|
|
273
|
+
replacement: resolve(
|
|
274
|
+
state.moduleRoots.get('@liujitcn/kratos-uni-app-system') ?? '',
|
|
275
|
+
'src',
|
|
276
|
+
),
|
|
277
|
+
},
|
|
278
|
+
],
|
|
279
|
+
},
|
|
280
|
+
optimizeDeps: {
|
|
281
|
+
exclude: options.modules.map((module) => module.name),
|
|
282
|
+
},
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
configureServer(server) {
|
|
286
|
+
server.httpServer?.once('close', cleanup)
|
|
287
|
+
},
|
|
288
|
+
closeBundle() {
|
|
289
|
+
if (!state.persistent) cleanup()
|
|
290
|
+
},
|
|
291
|
+
closeWatcher: cleanup,
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function recoverBuildTransaction(
|
|
296
|
+
transactionFile: string,
|
|
297
|
+
inputDir: string,
|
|
298
|
+
pagesFile: string,
|
|
299
|
+
): void {
|
|
300
|
+
if (!existsSync(transactionFile)) return
|
|
301
|
+
const transaction = JSON.parse(readFileSync(transactionFile, 'utf8')) as BuildTransaction
|
|
302
|
+
if (transaction.inputDir !== inputDir || transaction.pagesFile !== pagesFile) {
|
|
303
|
+
throw new Error(`uni-app 构建事务目录不匹配:${transactionFile}`)
|
|
304
|
+
}
|
|
305
|
+
if (
|
|
306
|
+
transaction.ownerPid !== undefined &&
|
|
307
|
+
transaction.ownerPid !== process.pid &&
|
|
308
|
+
isProcessRunning(transaction.ownerPid)
|
|
309
|
+
) {
|
|
310
|
+
throw new Error(
|
|
311
|
+
`页面装配已由进程 ${transaction.ownerPid} 使用,请先停止另一个 H5 或小程序开发进程`,
|
|
312
|
+
)
|
|
313
|
+
}
|
|
314
|
+
for (const file of [...transaction.generatedFiles].reverse()) {
|
|
315
|
+
if (existsSync(file)) unlinkSync(file)
|
|
316
|
+
removeEmptyParents(dirname(file), inputDir)
|
|
317
|
+
}
|
|
318
|
+
removeGeneratedStaticFiles(transaction.generatedStaticFiles ?? [], resolve(inputDir, 'static'))
|
|
319
|
+
// 兼容旧事务:旧格式仅在 static 原本不存在时记录整个目录由插件生成。
|
|
320
|
+
if (transaction.generatedStatic && transaction.generatedStaticFiles === undefined) {
|
|
321
|
+
rmSync(resolve(inputDir, 'static'), { recursive: true, force: true })
|
|
322
|
+
}
|
|
323
|
+
writeFileSync(pagesFile, transaction.originalPages)
|
|
324
|
+
unlinkSync(transactionFile)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// isProcessRunning 判断页面事务的所属进程是否仍然存活。
|
|
328
|
+
function isProcessRunning(pid: number): boolean {
|
|
329
|
+
try {
|
|
330
|
+
process.kill(pid, 0)
|
|
331
|
+
return true
|
|
332
|
+
} catch (error) {
|
|
333
|
+
return (error as NodeJS.ErrnoException).code === 'EPERM'
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function collectModuleStaticFiles(
|
|
338
|
+
sourceRoots: string[],
|
|
339
|
+
targetRoot: string,
|
|
340
|
+
): Array<{ source: string; target: string }> {
|
|
341
|
+
const fileMap = new Map<string, { source: string; target: string }>()
|
|
342
|
+
sourceRoots.forEach((sourceRoot) => {
|
|
343
|
+
scanFiles(sourceRoot).forEach((source) => {
|
|
344
|
+
const target = resolve(targetRoot, relative(sourceRoot, source))
|
|
345
|
+
if (!existsSync(target)) fileMap.set(target, { source, target })
|
|
346
|
+
})
|
|
347
|
+
})
|
|
348
|
+
return [...fileMap.values()]
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function scanFiles(root: string): string[] {
|
|
352
|
+
if (!existsSync(root)) return []
|
|
353
|
+
const files: string[] = []
|
|
354
|
+
const visit = (directory: string) => {
|
|
355
|
+
readdirSync(directory).forEach((entry) => {
|
|
356
|
+
const path = resolve(directory, entry)
|
|
357
|
+
if (statSync(path).isDirectory()) visit(path)
|
|
358
|
+
else files.push(path)
|
|
359
|
+
})
|
|
360
|
+
}
|
|
361
|
+
visit(root)
|
|
362
|
+
return files
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function removeGeneratedStaticFiles(files: string[], staticRoot: string): void {
|
|
366
|
+
for (const file of [...files].reverse()) {
|
|
367
|
+
if (existsSync(file)) unlinkSync(file)
|
|
368
|
+
removeEmptyParents(dirname(file), staticRoot)
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function scanViews(root: string): Array<{ route: string; source: string }> {
|
|
373
|
+
if (!existsSync(root)) return []
|
|
374
|
+
const files: string[] = []
|
|
375
|
+
const visit = (directory: string) => {
|
|
376
|
+
readdirSync(directory).forEach((entry) => {
|
|
377
|
+
const path = resolve(directory, entry)
|
|
378
|
+
if (statSync(path).isDirectory()) {
|
|
379
|
+
if (entry !== 'components') visit(path)
|
|
380
|
+
} else if (entry.endsWith('.vue')) {
|
|
381
|
+
files.push(path)
|
|
382
|
+
}
|
|
383
|
+
})
|
|
384
|
+
}
|
|
385
|
+
visit(root)
|
|
386
|
+
return files.map((source) => ({
|
|
387
|
+
route: normalizeRoute(relative(root, source)),
|
|
388
|
+
source,
|
|
389
|
+
}))
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function appendPage(manifest: PagesManifest, page: ScannedPage): void {
|
|
393
|
+
const [first, ...rest] = page.route.split('/')
|
|
394
|
+
if (!first.startsWith('pages') || first === 'pages') {
|
|
395
|
+
manifest.pages.push({ path: page.route, style: page.style })
|
|
396
|
+
return
|
|
397
|
+
}
|
|
398
|
+
manifest.subPackages ??= []
|
|
399
|
+
let subPackage = manifest.subPackages.find((item) => item.root === first)
|
|
400
|
+
if (!subPackage) {
|
|
401
|
+
subPackage = { root: first, pages: [] }
|
|
402
|
+
manifest.subPackages.push(subPackage)
|
|
403
|
+
}
|
|
404
|
+
subPackage.pages.push({ path: rest.join('/'), style: page.style })
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function createPageWrapper(page: ScannedPage): string {
|
|
408
|
+
const source = page.source.replace(/\\/g, '/')
|
|
409
|
+
return `<script setup lang="ts">
|
|
410
|
+
import KratosPage from ${JSON.stringify(source)}
|
|
411
|
+
import KratosTabBar from '@liujitcn/kratos-uni-app-core/components/KratosTabBar.vue'
|
|
412
|
+
|
|
413
|
+
defineOptions({ inheritAttrs: false })
|
|
414
|
+
</script>
|
|
415
|
+
|
|
416
|
+
<template>
|
|
417
|
+
<KratosPage />
|
|
418
|
+
<KratosTabBar route=${JSON.stringify(page.route)} />
|
|
419
|
+
</template>
|
|
420
|
+
`
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function normalizeRoute(route: string): string {
|
|
424
|
+
return route
|
|
425
|
+
.replace(/\\/g, '/')
|
|
426
|
+
.replace(/^\/+/, '')
|
|
427
|
+
.replace(/\.vue$/, '')
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function removeEmptyParents(directory: string, boundary: string): void {
|
|
431
|
+
let current = directory
|
|
432
|
+
while (current !== boundary && current.startsWith(boundary) && existsSync(current)) {
|
|
433
|
+
if (readdirSync(current).length) return
|
|
434
|
+
rmdirSync(current)
|
|
435
|
+
current = dirname(current)
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function resolveSourceFile(target: string): string {
|
|
440
|
+
const candidates = [
|
|
441
|
+
target,
|
|
442
|
+
`${target}.ts`,
|
|
443
|
+
`${target}.js`,
|
|
444
|
+
`${target}.vue`,
|
|
445
|
+
resolve(target, 'index.ts'),
|
|
446
|
+
resolve(target, 'index.js'),
|
|
447
|
+
]
|
|
448
|
+
const resolved =
|
|
449
|
+
candidates.find((candidate) => existsSync(candidate) && statSync(candidate).isFile()) ?? target
|
|
450
|
+
if (!isAbsolute(resolved)) throw new Error(`模块源码路径不是绝对路径:${resolved}`)
|
|
451
|
+
return resolved
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// dependencyVersionQuery 继承依赖版本并隔离开发服务缓存,避免源码重复实例或跨服务过期。
|
|
455
|
+
function dependencyVersionQuery(importer: string | undefined, sourceVersion: string): string {
|
|
456
|
+
const query = importer?.split('?', 2)[1] ?? ''
|
|
457
|
+
const version = new URLSearchParams(query).get('v')
|
|
458
|
+
const params = new URLSearchParams()
|
|
459
|
+
if (version) params.set('v', version)
|
|
460
|
+
params.set('kratos', sourceVersion)
|
|
461
|
+
return params.toString()
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function resolveWorkspacePackageSource(packageRoot: string, subpath: string): string {
|
|
465
|
+
if (!subpath) return resolve(packageRoot, 'src/index.ts')
|
|
466
|
+
if (subpath === 'module') return resolve(packageRoot, 'src/module.ts')
|
|
467
|
+
if (subpath === 'stores') return resolve(packageRoot, 'src/stores/index.ts')
|
|
468
|
+
return resolve(packageRoot, 'src', subpath)
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function isWithinRoot(root: string, target: string): boolean {
|
|
472
|
+
const relativePath = relative(root, target)
|
|
473
|
+
return relativePath === '' || (!relativePath.startsWith('..') && !isAbsolute(relativePath))
|
|
474
|
+
}
|