@neuxnet/neux-cli 0.2.3
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 +438 -0
- package/README.zh-CN.md +554 -0
- package/assets/container/assets/index.css +1 -0
- package/assets/container/assets/index.js +137 -0
- package/assets/container/assets/pageFrame.css +1 -0
- package/assets/container/assets/pageFrame.js +56 -0
- package/assets/container/assets/service.js +6 -0
- package/assets/container/assets/vconsole.js +931 -0
- package/assets/container/favicon.ico +0 -0
- package/assets/container/images/icon-arrow.png +0 -0
- package/assets/container/images/mini-action-white.png +0 -0
- package/assets/container/images/mini-action.png +0 -0
- package/assets/container/images/mini-arrow-left-white.png +0 -0
- package/assets/container/images/mini-arrow-left.jpg +0 -0
- package/assets/container/images/mini-arrow-left.png +0 -0
- package/assets/container/images/mini-close-white.png +0 -0
- package/assets/container/images/mini-close.png +0 -0
- package/assets/container/images/more.png +0 -0
- package/assets/container/images/search.jpg +0 -0
- package/assets/container/index.html +1 -0
- package/assets/container/pageFrame.html +1 -0
- package/assets/init/tabbar/home-active.png +0 -0
- package/assets/init/tabbar/home.png +0 -0
- package/assets/init/tabbar/list-active.png +0 -0
- package/assets/init/tabbar/list.png +0 -0
- package/assets/init/types/neux-api.d.ts +1402 -0
- package/package.json +68 -0
- package/scripts/generate-init-types.js +210 -0
- package/scripts/sync-compiler.js +22 -0
- package/scripts/sync-web-container.js +34 -0
- package/src/bin/cli.js +646 -0
- package/src/core/brand.js +11 -0
- package/src/core/compiler.js +305 -0
- package/src/core/defaults.js +12 -0
- package/src/core/dev.js +15 -0
- package/src/core/errors.js +17 -0
- package/src/core/fs.js +66 -0
- package/src/core/i18n.js +37 -0
- package/src/core/init.js +866 -0
- package/src/core/lifecycle.js +32 -0
- package/src/core/manifest.js +72 -0
- package/src/core/pack.js +156 -0
- package/src/core/package-info.js +27 -0
- package/src/core/preview-server.js +123 -0
- package/src/core/project.js +101 -0
- package/src/core/prompts.js +71 -0
- package/src/core/proxy-security.js +141 -0
- package/src/core/proxy.js +156 -0
- package/src/core/qr.js +41 -0
- package/src/core/terminal-qr.js +72 -0
- package/src/core/update.js +278 -0
- package/src/core/watch.js +113 -0
- package/src/core/web.js +649 -0
- package/src/core/zip.js +120 -0
- package/src/index.js +20 -0
- package/src/providers/service-client.js +149 -0
- package/src/providers/service-config.js +264 -0
- package/src/providers/service.js +146 -0
- package/src/providers/upload.js +112 -0
- package/vendor/dimina-compiler/bin/index.cjs +265 -0
- package/vendor/dimina-compiler/bin/index.js +263 -0
- package/vendor/dimina-compiler/compatibility-B-DoZtUX.cjs +395 -0
- package/vendor/dimina-compiler/compatibility-Cl3-DO6V.js +366 -0
- package/vendor/dimina-compiler/core/logic-compiler.cjs +378 -0
- package/vendor/dimina-compiler/core/logic-compiler.js +374 -0
- package/vendor/dimina-compiler/core/style-compiler.cjs +392 -0
- package/vendor/dimina-compiler/core/style-compiler.js +377 -0
- package/vendor/dimina-compiler/core/view-compiler.cjs +1601 -0
- package/vendor/dimina-compiler/core/view-compiler.js +1582 -0
- package/vendor/dimina-compiler/index.cjs +762 -0
- package/vendor/dimina-compiler/index.js +751 -0
- package/vendor/dimina-compiler/sourcemap-BgtIgqkC.cjs +1377 -0
- package/vendor/dimina-compiler/sourcemap-CKjhV9h7.js +1135 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function createLifecycleEvent(event, payload = {}) {
|
|
2
|
+
return {
|
|
3
|
+
event,
|
|
4
|
+
timestamp: Date.now(),
|
|
5
|
+
...jsonSafe(payload),
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function emitLifecycleEvent(options, event, payload = {}) {
|
|
10
|
+
const record = createLifecycleEvent(event, payload)
|
|
11
|
+
await options.onEvent?.(record)
|
|
12
|
+
return record
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function jsonSafe(value) {
|
|
16
|
+
if (value instanceof Error) {
|
|
17
|
+
return {
|
|
18
|
+
name: value.name,
|
|
19
|
+
message: value.message,
|
|
20
|
+
code: value.code,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (Array.isArray(value)) return value.map(jsonSafe)
|
|
24
|
+
if (!value || typeof value !== 'object') return value
|
|
25
|
+
|
|
26
|
+
const output = {}
|
|
27
|
+
for (const [key, item] of Object.entries(value)) {
|
|
28
|
+
if (typeof item === 'function') continue
|
|
29
|
+
output[key] = jsonSafe(item)
|
|
30
|
+
}
|
|
31
|
+
return output
|
|
32
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export function createManifest(config, packageUrl, packageSha256, allowDowngrade = false) {
|
|
2
|
+
return {
|
|
3
|
+
schemaVersion: 2,
|
|
4
|
+
appId: config.appId,
|
|
5
|
+
name: config.name,
|
|
6
|
+
description: config.description || '',
|
|
7
|
+
versionCode: config.versionCode,
|
|
8
|
+
versionName: config.versionName,
|
|
9
|
+
path: config.path,
|
|
10
|
+
entryPath: config.path,
|
|
11
|
+
packageUrl,
|
|
12
|
+
sha256: packageSha256,
|
|
13
|
+
allowDowngrade,
|
|
14
|
+
address: {
|
|
15
|
+
id: config.appId,
|
|
16
|
+
manifestUrl: '',
|
|
17
|
+
version: config.versionCode,
|
|
18
|
+
path: config.path,
|
|
19
|
+
},
|
|
20
|
+
appInfo: {
|
|
21
|
+
description: config.description || '',
|
|
22
|
+
categories: config.categories || [],
|
|
23
|
+
icons: Object.values(config.icons || {}).filter(Boolean),
|
|
24
|
+
screenshots: config.screenshots || [],
|
|
25
|
+
},
|
|
26
|
+
signature: '',
|
|
27
|
+
algorithm: '',
|
|
28
|
+
publicKeyId: '',
|
|
29
|
+
offlineEnabled: true,
|
|
30
|
+
updateMode: 'manual',
|
|
31
|
+
minRuntimeVersion: '',
|
|
32
|
+
permissions: [],
|
|
33
|
+
domains: [],
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function createDeepLink({ appId, version, appPath, query = '', fragment = '' }) {
|
|
38
|
+
const encodedPath = String(appPath || '')
|
|
39
|
+
.split('/')
|
|
40
|
+
.filter(Boolean)
|
|
41
|
+
.map(segment => encodeURIComponent(segment))
|
|
42
|
+
.join('/')
|
|
43
|
+
const pathSegment = encodedPath ? `/${encodedPath}` : ''
|
|
44
|
+
const versionSegment = Number.isInteger(version) ? `;version=${version}` : ''
|
|
45
|
+
const querySegment = query ? `?${query}` : ''
|
|
46
|
+
const fragmentSegment = fragment ? `#${fragment}` : ''
|
|
47
|
+
return `dimina://miniapp/${encodeURIComponent(appId)}${versionSegment}${pathSegment}${querySegment}${fragmentSegment}`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function createAppConfig({
|
|
51
|
+
appId,
|
|
52
|
+
appName,
|
|
53
|
+
appPath,
|
|
54
|
+
description = '',
|
|
55
|
+
versionCode = 1,
|
|
56
|
+
versionName = '1.0.0',
|
|
57
|
+
categories = [],
|
|
58
|
+
icons = {},
|
|
59
|
+
screenshots = [],
|
|
60
|
+
}) {
|
|
61
|
+
return {
|
|
62
|
+
appId,
|
|
63
|
+
name: appName || `App ${appId}`,
|
|
64
|
+
path: appPath || 'pages/index',
|
|
65
|
+
description,
|
|
66
|
+
categories,
|
|
67
|
+
icons,
|
|
68
|
+
screenshots,
|
|
69
|
+
versionCode,
|
|
70
|
+
versionName,
|
|
71
|
+
}
|
|
72
|
+
}
|
package/src/core/pack.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { buildProject } from './compiler.js'
|
|
4
|
+
import { pathExists, readJson, resolvePath, writeJson } from './fs.js'
|
|
5
|
+
import { createAppConfig, createDeepLink, createManifest } from './manifest.js'
|
|
6
|
+
import { inspectProject } from './project.js'
|
|
7
|
+
import { createZip } from './zip.js'
|
|
8
|
+
import { defaultOut } from './defaults.js'
|
|
9
|
+
|
|
10
|
+
export async function packProject(options = {}) {
|
|
11
|
+
const projectInfo = await inspectProject(options)
|
|
12
|
+
const out = resolvePath(options.out || options.output || defaultOut(options.command || 'pack'))
|
|
13
|
+
let packageSourceDir = resolvePath(options.sourceDir || options.compiledDir || projectInfo.sourceRoot)
|
|
14
|
+
let buildResult = null
|
|
15
|
+
const packageExtension = String(options.packageExtension || 'zip').replace(/^\./, '')
|
|
16
|
+
const isWgtPackage = packageExtension === 'wgt'
|
|
17
|
+
const temporaryPaths = []
|
|
18
|
+
|
|
19
|
+
if (options.build) {
|
|
20
|
+
const buildOut = resolvePath(options.buildOut || (isWgtPackage ? path.join(out, '..', '.wgt-build') : path.join(out, '.build')))
|
|
21
|
+
buildResult = await buildProject({ ...options, out: buildOut })
|
|
22
|
+
packageSourceDir = await resolveBuiltAppDir(buildOut, projectInfo.appId, buildResult)
|
|
23
|
+
if (isWgtPackage && !options.buildOut) temporaryPaths.push(buildOut)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const appId = options.appId || projectInfo.appId
|
|
27
|
+
const compilerConfig = buildResult?.compilerResult && typeof buildResult.compilerResult === 'object'
|
|
28
|
+
? buildResult.compilerResult
|
|
29
|
+
: {}
|
|
30
|
+
const cliConfig = projectInfo.cliConfig || {}
|
|
31
|
+
const appOutDir = isWgtPackage ? out : path.join(out, appId)
|
|
32
|
+
const config = createAppConfig({
|
|
33
|
+
appId,
|
|
34
|
+
appName: options.name || compilerConfig.name || projectInfo.name,
|
|
35
|
+
appPath: options.entryPath || compilerConfig.path || compilerConfig.entryPath || projectInfo.entryPath,
|
|
36
|
+
description: options.description || '',
|
|
37
|
+
versionCode: Number.parseInt(firstConfigValue(options.versionCode, cliConfig.versionCode, 1), 10),
|
|
38
|
+
versionName: firstConfigValue(
|
|
39
|
+
options.versionName,
|
|
40
|
+
options.version,
|
|
41
|
+
cliConfig.versionName,
|
|
42
|
+
cliConfig.version,
|
|
43
|
+
await readPackageVersion(projectInfo.projectPath),
|
|
44
|
+
'1.0.0',
|
|
45
|
+
),
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
if (isWgtPackage && (options.command === 'build' || options.command === 'wgt')) {
|
|
49
|
+
await fs.rm(appOutDir, { recursive: true, force: true })
|
|
50
|
+
}
|
|
51
|
+
await fs.mkdir(appOutDir, { recursive: true })
|
|
52
|
+
if (isWgtPackage) {
|
|
53
|
+
const stagingDir = path.join(out, `.wgt-${appId}`)
|
|
54
|
+
temporaryPaths.push(stagingDir)
|
|
55
|
+
try {
|
|
56
|
+
await fs.rm(stagingDir, { recursive: true, force: true })
|
|
57
|
+
await fs.mkdir(stagingDir, { recursive: true })
|
|
58
|
+
|
|
59
|
+
const configPath = path.join(stagingDir, 'config.json')
|
|
60
|
+
await writeJson(configPath, config)
|
|
61
|
+
const innerPackagePath = path.join(stagingDir, `${appId}.zip`)
|
|
62
|
+
const innerZipInfo = await createZip(packageSourceDir, innerPackagePath)
|
|
63
|
+
|
|
64
|
+
const packagePath = path.join(appOutDir, `${appId}.wgt`)
|
|
65
|
+
const zipInfo = await createZip(stagingDir, packagePath)
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
ok: true,
|
|
69
|
+
command: options.command || 'pack',
|
|
70
|
+
projectPath: projectInfo.projectPath,
|
|
71
|
+
sourceDir: packageSourceDir,
|
|
72
|
+
outputDir: appOutDir,
|
|
73
|
+
appId,
|
|
74
|
+
config,
|
|
75
|
+
configPath: null,
|
|
76
|
+
packagePath,
|
|
77
|
+
manifestPath: null,
|
|
78
|
+
sha256: zipInfo.sha256,
|
|
79
|
+
packageSize: zipInfo.size,
|
|
80
|
+
innerPackageName: `${appId}.zip`,
|
|
81
|
+
innerSha256: innerZipInfo.sha256,
|
|
82
|
+
innerPackageSize: innerZipInfo.size,
|
|
83
|
+
buildResult,
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
for (const temporaryPath of temporaryPaths.reverse()) {
|
|
88
|
+
await fs.rm(temporaryPath, { recursive: true, force: true })
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const configPath = path.join(appOutDir, 'config.json')
|
|
94
|
+
await writeJson(configPath, config)
|
|
95
|
+
|
|
96
|
+
const zipPath = path.join(appOutDir, `${appId}.${packageExtension}`)
|
|
97
|
+
const configContent = `${JSON.stringify(config, null, 2)}\n`
|
|
98
|
+
const zipInfo = await createZip(packageSourceDir, zipPath, [{ name: 'config.json', content: configContent }])
|
|
99
|
+
const manifest = createManifest(config, `${appId}.${packageExtension}`, zipInfo.sha256, !!options.allowDowngrade)
|
|
100
|
+
const manifestPath = path.join(appOutDir, 'manifest.json')
|
|
101
|
+
await writeJson(manifestPath, manifest)
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
ok: true,
|
|
105
|
+
command: 'pack',
|
|
106
|
+
projectPath: projectInfo.projectPath,
|
|
107
|
+
sourceDir: packageSourceDir,
|
|
108
|
+
outputDir: appOutDir,
|
|
109
|
+
appId,
|
|
110
|
+
config,
|
|
111
|
+
configPath,
|
|
112
|
+
packagePath: zipPath,
|
|
113
|
+
manifestPath,
|
|
114
|
+
sha256: zipInfo.sha256,
|
|
115
|
+
packageSize: zipInfo.size,
|
|
116
|
+
buildResult,
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function readPackageVersion(projectPath) {
|
|
121
|
+
const packageJson = await readJson(path.join(projectPath, 'package.json'), {})
|
|
122
|
+
return packageJson?.version
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function firstConfigValue(...values) {
|
|
126
|
+
return values.find(value => value !== undefined && value !== null && value !== '')
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function resolveBuiltAppDir(buildOut, appId, buildResult) {
|
|
130
|
+
const compilerResult = buildResult?.compilerResult && typeof buildResult.compilerResult === 'object'
|
|
131
|
+
? buildResult.compilerResult
|
|
132
|
+
: {}
|
|
133
|
+
const candidates = Array.from(new Set([
|
|
134
|
+
appId,
|
|
135
|
+
compilerResult.appId,
|
|
136
|
+
buildResult?.appId,
|
|
137
|
+
].filter(Boolean)))
|
|
138
|
+
|
|
139
|
+
for (const candidate of candidates) {
|
|
140
|
+
const candidatePath = path.join(buildOut, candidate)
|
|
141
|
+
if (await pathExists(candidatePath)) return candidatePath
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return path.join(buildOut, appId)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function createPreviewUrls({ serverUrl, appId, versionCode, appPath, packageExtension = 'zip' }) {
|
|
148
|
+
const base = `${serverUrl}/${encodeURIComponent(appId)}`
|
|
149
|
+
const extension = String(packageExtension).replace(/^\./, '')
|
|
150
|
+
return {
|
|
151
|
+
serverUrl,
|
|
152
|
+
manifestUrl: `${base}/manifest.json`,
|
|
153
|
+
packageUrl: `${base}/${encodeURIComponent(appId)}.${extension}`,
|
|
154
|
+
deepLink: createDeepLink({ appId, version: versionCode, appPath }),
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { brand } from './brand.js'
|
|
5
|
+
|
|
6
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..')
|
|
7
|
+
let packageInfoPromise
|
|
8
|
+
|
|
9
|
+
export async function getCliPackageInfo() {
|
|
10
|
+
packageInfoPromise ||= fs.readFile(path.join(packageRoot, 'package.json'), 'utf8')
|
|
11
|
+
.then(JSON.parse)
|
|
12
|
+
|
|
13
|
+
const packageJson = await packageInfoPromise
|
|
14
|
+
return {
|
|
15
|
+
packageName: packageJson.name || brand.packageName,
|
|
16
|
+
version: packageJson.version,
|
|
17
|
+
packageRoot,
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function getCliVersion() {
|
|
22
|
+
return (await getCliPackageInfo()).version
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function getServiceClientVersion() {
|
|
26
|
+
return `${brand.serviceClientName}/${await getCliVersion()}`
|
|
27
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import http from 'node:http'
|
|
3
|
+
import os from 'node:os'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { DiminaCliError } from './errors.js'
|
|
6
|
+
import { emitLifecycleEvent } from './lifecycle.js'
|
|
7
|
+
import { packProject, createPreviewUrls } from './pack.js'
|
|
8
|
+
import { createLocalPreviewDeepLink, createQrPayloadResult } from './qr.js'
|
|
9
|
+
|
|
10
|
+
export function getLocalIPAddress() {
|
|
11
|
+
for (const addresses of Object.values(os.networkInterfaces())) {
|
|
12
|
+
for (const address of addresses || []) {
|
|
13
|
+
if (address.family === 'IPv4' && !address.internal) return address.address
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return '127.0.0.1'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function contentType(filePath) {
|
|
20
|
+
const ext = path.extname(filePath)
|
|
21
|
+
if (ext === '.json') return 'application/json; charset=utf-8'
|
|
22
|
+
if (ext === '.zip') return 'application/zip'
|
|
23
|
+
if (ext === '.png') return 'image/png'
|
|
24
|
+
return 'application/octet-stream'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function startStaticServer(rootDir, host, port) {
|
|
28
|
+
const root = path.resolve(rootDir)
|
|
29
|
+
const server = http.createServer((req, res) => {
|
|
30
|
+
let pathname
|
|
31
|
+
try {
|
|
32
|
+
pathname = decodeURIComponent(new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`).pathname)
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
res.writeHead(400)
|
|
36
|
+
res.end('Bad request')
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const resolved = path.resolve(path.join(root, path.normalize(pathname)))
|
|
41
|
+
if (resolved !== root && !resolved.startsWith(root + path.sep)) {
|
|
42
|
+
res.writeHead(403)
|
|
43
|
+
res.end('Forbidden')
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
fs.stat(resolved, (statError, stat) => {
|
|
48
|
+
if (statError || !stat.isFile()) {
|
|
49
|
+
res.writeHead(404)
|
|
50
|
+
res.end('Not found')
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
res.writeHead(200, { 'Content-Type': contentType(resolved) })
|
|
54
|
+
fs.createReadStream(resolved).pipe(res)
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
await new Promise((resolve, reject) => {
|
|
59
|
+
server.once('error', reject)
|
|
60
|
+
server.listen(port, host, () => {
|
|
61
|
+
server.off('error', reject)
|
|
62
|
+
resolve()
|
|
63
|
+
})
|
|
64
|
+
}).catch((error) => {
|
|
65
|
+
throw new DiminaCliError('DIMINA_PREVIEW_SERVER_FAILED', `Failed to start preview server: ${error.message}`, {
|
|
66
|
+
host,
|
|
67
|
+
port,
|
|
68
|
+
cause: error.code,
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
return server
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function startPreview(options = {}) {
|
|
76
|
+
const command = options.command || 'preview'
|
|
77
|
+
const host = options.host || getLocalIPAddress()
|
|
78
|
+
const port = Number.parseInt(options.port ?? 5273, 10)
|
|
79
|
+
const runPack = options.withPackOutputRedirect || (action => action())
|
|
80
|
+
const pack = await runPack(() => packProject({ ...options, command }))
|
|
81
|
+
const wgtPack = await runPack(() => packProject({
|
|
82
|
+
...options,
|
|
83
|
+
command,
|
|
84
|
+
out: pack.outputDir,
|
|
85
|
+
packageExtension: 'wgt',
|
|
86
|
+
}))
|
|
87
|
+
const server = await startStaticServer(path.dirname(pack.outputDir), host, port)
|
|
88
|
+
const address = server.address()
|
|
89
|
+
const resolvedPort = typeof address === 'object' && address ? address.port : port
|
|
90
|
+
const serverUrl = `http://${host}:${resolvedPort}`
|
|
91
|
+
const urls = createPreviewUrls({
|
|
92
|
+
serverUrl,
|
|
93
|
+
appId: pack.appId,
|
|
94
|
+
versionCode: wgtPack.config.versionCode,
|
|
95
|
+
appPath: pack.config.path,
|
|
96
|
+
packageExtension: 'wgt',
|
|
97
|
+
})
|
|
98
|
+
const deepLink = createLocalPreviewDeepLink({
|
|
99
|
+
appId: pack.appId,
|
|
100
|
+
download: urls.packageUrl,
|
|
101
|
+
version: wgtPack.config.versionCode,
|
|
102
|
+
pagePath: pack.config.path,
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
const session = {
|
|
106
|
+
ok: true,
|
|
107
|
+
command,
|
|
108
|
+
...urls,
|
|
109
|
+
...createQrPayloadResult(deepLink),
|
|
110
|
+
appId: pack.appId,
|
|
111
|
+
artifact: pack,
|
|
112
|
+
close: async () => {
|
|
113
|
+
await new Promise((resolve, reject) => server.close(error => error ? reject(error) : resolve()))
|
|
114
|
+
await emitLifecycleEvent(options, 'close', {
|
|
115
|
+
command,
|
|
116
|
+
appId: pack.appId,
|
|
117
|
+
serverUrl,
|
|
118
|
+
})
|
|
119
|
+
},
|
|
120
|
+
}
|
|
121
|
+
await emitLifecycleEvent(options, 'ready', session)
|
|
122
|
+
return session
|
|
123
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { DiminaCliError } from './errors.js'
|
|
3
|
+
import { pathExists, readJson, resolvePath } from './fs.js'
|
|
4
|
+
|
|
5
|
+
export async function inspectProject(options = {}) {
|
|
6
|
+
const projectPath = resolvePath(options.project)
|
|
7
|
+
const projectConfigPath = path.join(projectPath, 'project.config.json')
|
|
8
|
+
const projectPrivateConfigPath = path.join(projectPath, 'project.private.config.json')
|
|
9
|
+
|
|
10
|
+
if (!(await pathExists(projectConfigPath))) {
|
|
11
|
+
throw new DiminaCliError('DIMINA_PROJECT_CONFIG_NOT_FOUND', `project.config.json not found: ${projectConfigPath}`, {
|
|
12
|
+
projectPath,
|
|
13
|
+
projectConfigPath,
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const projectConfig = await readJson(projectConfigPath)
|
|
18
|
+
const projectPrivateConfig = await readJson(projectPrivateConfigPath, {})
|
|
19
|
+
const effectiveProjectConfig = mergeProjectConfig(projectConfig, projectPrivateConfig)
|
|
20
|
+
const cliConfig = await readProjectCliConfig(projectPath, effectiveProjectConfig)
|
|
21
|
+
const miniprogramRoot = effectiveProjectConfig.miniprogramRoot || ''
|
|
22
|
+
const sourceRoot = path.resolve(projectPath, miniprogramRoot)
|
|
23
|
+
const appConfigPath = path.join(sourceRoot, 'app.json')
|
|
24
|
+
const appConfig = await readJson(appConfigPath, {})
|
|
25
|
+
const pages = Array.isArray(appConfig.pages) ? appConfig.pages : []
|
|
26
|
+
const appId = options.appId || effectiveProjectConfig.appid || effectiveProjectConfig.appId || ''
|
|
27
|
+
const appName = options.name || effectiveProjectConfig.projectname || effectiveProjectConfig.projectName || `App ${appId || 'unknown'}`
|
|
28
|
+
const entryPath = options.entryPath || appConfig.entryPagePath || pages[0] || 'pages/index'
|
|
29
|
+
const hasPrivateConfig = await pathExists(projectPrivateConfigPath)
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
ok: true,
|
|
33
|
+
command: 'inspect',
|
|
34
|
+
projectPath,
|
|
35
|
+
sourceRoot,
|
|
36
|
+
projectConfigPath,
|
|
37
|
+
projectPrivateConfigPath: hasPrivateConfig ? projectPrivateConfigPath : null,
|
|
38
|
+
appConfigPath,
|
|
39
|
+
appId,
|
|
40
|
+
name: appName,
|
|
41
|
+
entryPath,
|
|
42
|
+
pages,
|
|
43
|
+
compileType: effectiveProjectConfig.compileType || 'miniprogram',
|
|
44
|
+
libVersion: effectiveProjectConfig.libVersion || '',
|
|
45
|
+
miniprogramRoot,
|
|
46
|
+
setting: effectiveProjectConfig.setting || {},
|
|
47
|
+
packOptions: normalizePackOptions(effectiveProjectConfig.packOptions),
|
|
48
|
+
condition: effectiveProjectConfig.condition || {},
|
|
49
|
+
neuxCli: effectiveProjectConfig.neuxCli || {},
|
|
50
|
+
cliConfig,
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function mergeProjectConfig(projectConfig = {}, privateConfig = {}) {
|
|
55
|
+
return {
|
|
56
|
+
...projectConfig,
|
|
57
|
+
...privateConfig,
|
|
58
|
+
setting: {
|
|
59
|
+
...(projectConfig.setting || {}),
|
|
60
|
+
...(privateConfig.setting || {}),
|
|
61
|
+
},
|
|
62
|
+
packOptions: {
|
|
63
|
+
...(projectConfig.packOptions || {}),
|
|
64
|
+
...(privateConfig.packOptions || {}),
|
|
65
|
+
},
|
|
66
|
+
neux: {
|
|
67
|
+
...(projectConfig.neux || {}),
|
|
68
|
+
...(privateConfig.neux || {}),
|
|
69
|
+
},
|
|
70
|
+
neuxCli: {
|
|
71
|
+
...(projectConfig.neuxCli || {}),
|
|
72
|
+
...(privateConfig.neuxCli || {}),
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function normalizePackOptions(packOptions = {}) {
|
|
78
|
+
return {
|
|
79
|
+
ignore: Array.isArray(packOptions.ignore) ? packOptions.ignore : [],
|
|
80
|
+
include: Array.isArray(packOptions.include) ? packOptions.include : [],
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function readProjectCliConfig(projectPath, projectConfig) {
|
|
85
|
+
const neuxConfigPath = path.join(projectPath, 'neux.config.json')
|
|
86
|
+
const neuxConfig = await readJson(neuxConfigPath, {})
|
|
87
|
+
const source = {
|
|
88
|
+
...pickCliConfig(projectConfig),
|
|
89
|
+
...neuxConfig,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return pickCliConfig(source)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function pickCliConfig(source = {}) {
|
|
96
|
+
return {
|
|
97
|
+
version: source.version,
|
|
98
|
+
versionName: source.versionName,
|
|
99
|
+
versionCode: source.versionCode,
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import readline from 'node:readline/promises'
|
|
2
|
+
import process from 'node:process'
|
|
3
|
+
|
|
4
|
+
export function shouldPrompt(options = {}) {
|
|
5
|
+
return options.interactive !== false
|
|
6
|
+
&& options.noInteractive !== true
|
|
7
|
+
&& !options.json
|
|
8
|
+
&& !!process.stdin.isTTY
|
|
9
|
+
&& !!process.stdout.isTTY
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function promptLine(label, options = {}) {
|
|
13
|
+
const terminal = readline.createInterface({ input: process.stdin, output: process.stdout })
|
|
14
|
+
try {
|
|
15
|
+
if (options.secret) return await promptSecret(terminal, label)
|
|
16
|
+
return await terminal.question(label)
|
|
17
|
+
}
|
|
18
|
+
finally {
|
|
19
|
+
terminal.close()
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function promptLines(prompts) {
|
|
24
|
+
const terminal = readline.createInterface({ input: process.stdin, output: process.stdout })
|
|
25
|
+
try {
|
|
26
|
+
const values = {}
|
|
27
|
+
for (const prompt of prompts) {
|
|
28
|
+
values[prompt.name] = prompt.secret
|
|
29
|
+
? await promptSecret(terminal, prompt.label)
|
|
30
|
+
: await terminal.question(prompt.label)
|
|
31
|
+
}
|
|
32
|
+
return values
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
terminal.close()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function promptSecret(terminal, label) {
|
|
40
|
+
if (!process.stdin.isTTY || typeof process.stdin.setRawMode !== 'function') {
|
|
41
|
+
return await terminal.question(label)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
process.stdout.write(label)
|
|
45
|
+
process.stdin.setRawMode(true)
|
|
46
|
+
process.stdin.resume()
|
|
47
|
+
return await new Promise(resolve => {
|
|
48
|
+
let value = ''
|
|
49
|
+
const onData = chunk => {
|
|
50
|
+
const character = String(chunk)
|
|
51
|
+
if (character === '\u0003') {
|
|
52
|
+
process.stdin.setRawMode(false)
|
|
53
|
+
process.exit(130)
|
|
54
|
+
}
|
|
55
|
+
if (character === '\r' || character === '\n') {
|
|
56
|
+
process.stdin.setRawMode(false)
|
|
57
|
+
process.stdin.pause()
|
|
58
|
+
process.stdin.off('data', onData)
|
|
59
|
+
process.stdout.write('\n')
|
|
60
|
+
resolve(value)
|
|
61
|
+
}
|
|
62
|
+
else if (character === '\u007f' || character === '\b') {
|
|
63
|
+
value = value.slice(0, -1)
|
|
64
|
+
}
|
|
65
|
+
else if (character >= ' ') {
|
|
66
|
+
value += character
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
process.stdin.on('data', onData)
|
|
70
|
+
})
|
|
71
|
+
}
|