mbler 0.2.4 → 0.2.7-rc.2
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 +48 -41
- package/bin/mbler.js +3 -3
- package/bin/mcx-tsc.js +1 -1
- package/client.d.ts +17 -0
- package/dist/build.d.ts +18 -5
- package/dist/build.esm.mjs +834 -447
- package/dist/build.esm.mjs.map +1 -1
- package/dist/build.js +833 -447
- package/dist/build.js.map +1 -1
- package/dist/index.d.ts +22 -63
- package/dist/index.esm.mjs +665 -851
- package/dist/index.esm.mjs.map +1 -1
- package/dist/index.js +655 -839
- package/dist/index.js.map +1 -1
- package/dist/template/mcx/behavior/scripts/app.mcx +8 -5
- package/dist/template/mcx/behavior/scripts/component/ComponentTest.mcx +19 -0
- package/dist/template/mcx/behavior/scripts/config/config.json +5 -0
- package/dist/template/mcx/behavior/scripts/{event$1.mcx → event/event$1.mcx} +2 -3
- package/dist/template/mcx/behavior/scripts/event/event.mcx +10 -0
- package/dist/template/mcx/behavior/scripts/event/test.ts +3 -0
- package/dist/template/mcx/behavior/scripts/index.ts +5 -0
- package/dist/template/ts/behavior/scripts/index.ts +1 -1
- package/package.json +31 -20
- package/dist/template/mcx/behavior/pack_icon.png +0 -0
- package/dist/template/mcx/behavior/scripts/event.mcx +0 -9
- package/dist/template/mcx/behavior/scripts/index.mjs +0 -5
package/dist/build.esm.mjs
CHANGED
|
@@ -1,65 +1,407 @@
|
|
|
1
1
|
import * as mcxDef from '@mbler/mcx-core';
|
|
2
2
|
import _chalk from 'chalk';
|
|
3
|
-
import jsonPlugin from '@rollup/plugin-json';
|
|
4
|
-
import resolvePlugin from '@rollup/plugin-node-resolve';
|
|
5
3
|
import minifyPlugin from '@rollup/plugin-terser';
|
|
6
|
-
import { watch as watch$
|
|
4
|
+
import { watch as watch$2 } from 'chokidar';
|
|
7
5
|
import * as fs from 'node:fs/promises';
|
|
8
|
-
import fs__default from 'node:fs/promises';
|
|
6
|
+
import fs__default$1 from 'node:fs/promises';
|
|
9
7
|
import * as path from 'node:path';
|
|
10
8
|
import path__default, { extname, isAbsolute } from 'node:path';
|
|
11
|
-
import
|
|
9
|
+
import { rolldown, watch as watch$1 } from 'rolldown';
|
|
12
10
|
import * as readline from 'readline';
|
|
13
|
-
import
|
|
14
|
-
import
|
|
11
|
+
import * as fs$1 from 'node:fs';
|
|
12
|
+
import fs__default from 'node:fs';
|
|
13
|
+
import os, { homedir, tmpdir } from 'node:os';
|
|
15
14
|
import 'node:child_process';
|
|
16
|
-
import { deserialize, serialize } from 'node:v8';
|
|
17
15
|
import crypto from 'node:crypto';
|
|
18
|
-
import * as fs$1 from 'node:fs';
|
|
19
16
|
import { env } from 'node:process';
|
|
20
|
-
import AdmZip from 'adm-zip';
|
|
21
|
-
import commonjs from '@rollup/plugin-commonjs';
|
|
22
17
|
import { createMCXLanguagePlugin } from '@mbler/mcx-server';
|
|
23
|
-
import typescript from '@rollup/plugin-typescript';
|
|
24
18
|
import ts from 'typescript';
|
|
25
19
|
import { runTsc } from '@volar/typescript/lib/quickstart/runTsc.js';
|
|
26
20
|
|
|
27
|
-
|
|
21
|
+
const LanguageNames = ['zh', 'en'];
|
|
22
|
+
const cmdList = [
|
|
23
|
+
'c',
|
|
24
|
+
'work',
|
|
25
|
+
'help',
|
|
26
|
+
'h',
|
|
27
|
+
'init',
|
|
28
|
+
'version',
|
|
29
|
+
'build',
|
|
30
|
+
'watch',
|
|
31
|
+
'lang',
|
|
32
|
+
'set-work-dir',
|
|
33
|
+
'publish',
|
|
34
|
+
'unpublish',
|
|
35
|
+
'install',
|
|
36
|
+
'uninstall',
|
|
37
|
+
'login',
|
|
38
|
+
'profile',
|
|
39
|
+
'log',
|
|
40
|
+
'view',
|
|
41
|
+
'config',
|
|
42
|
+
];
|
|
43
|
+
const templateMblerConfig = {
|
|
44
|
+
name: 'demo',
|
|
45
|
+
description: 'demo',
|
|
46
|
+
version: '0.0.0',
|
|
47
|
+
mcVersion: '1.21.100',
|
|
48
|
+
script: {
|
|
49
|
+
main: '',
|
|
50
|
+
},
|
|
51
|
+
minify: false,
|
|
52
|
+
outdir: {
|
|
53
|
+
behavior: '',
|
|
54
|
+
resources: '',
|
|
55
|
+
dist: '',
|
|
56
|
+
},
|
|
57
|
+
build: {
|
|
58
|
+
rollupPlugins: [],
|
|
59
|
+
cache: 'auto',
|
|
60
|
+
bundle: true,
|
|
61
|
+
outputDir: 'scripts',
|
|
62
|
+
outputFilename: '',
|
|
63
|
+
onEnd: () => { },
|
|
64
|
+
onStart: () => { },
|
|
65
|
+
onWarn: () => { },
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
var version = { version: "0.2.7-rc.1" };
|
|
70
|
+
|
|
71
|
+
var ZhLang = {
|
|
72
|
+
description: `MBLER
|
|
73
|
+
Minecraft Bedrock Edition
|
|
74
|
+
Addon Bulider In Nodejs
|
|
75
|
+
在基岩版我的世界上的 nodejs 构建工具
|
|
76
|
+
命令 : ${cmdList.join(', ')}
|
|
77
|
+
帮助命令 :
|
|
78
|
+
help
|
|
79
|
+
显示帮助信息
|
|
80
|
+
第二个参数为要查询的命令名称或空
|
|
81
|
+
别名: h
|
|
82
|
+
git https://github.com/RuanhoR/mbler/`,
|
|
83
|
+
help: {
|
|
84
|
+
cmds: cmdList,
|
|
85
|
+
help: 'mbler [help/h] [?:查看的命令名称]\n - 查看帮助',
|
|
86
|
+
h: '$help',
|
|
87
|
+
work: 'mbler [work/c] [?:相对或绝对路径]\n - 没有输入路径:查询当前工作目录\n - 输入路径:设置工作目录',
|
|
88
|
+
c: '$work',
|
|
89
|
+
init: 'mbler init\n - 初始化当前工作目录,可使用 mbler work 指定工作目录或使用参数一次确定(例: mbler init -in ./)\n - 将会询问选项以完成初始化',
|
|
90
|
+
build: 'mbler build\n - 在工作目录执行构建',
|
|
91
|
+
log: 'mbler log\n - 处理日志文件\n - mbler log point: 得到日志文件路径 \n - mbler log clean: 清除日志',
|
|
92
|
+
watch: 'mbler watch\n - 启动构建并开启监视模式,文件变化会自动重新构建',
|
|
93
|
+
lang: 'mbler lang\n- 无参数:显示当前语言\n- 跟 zh 或 en(如 mbler lang en): 设置语言',
|
|
94
|
+
version: 'mbler version - 版本管理命令\n- 无参数:显示当前版本和提交哈希\n- --show=<commit|version>:筛选显示内容\n- <新版本号>:更新package.json和配置文件的版本',
|
|
95
|
+
'set-work-dir': 'mbler set-work-dir <on|off>\n - on: 启用工作目录功能\n - off: 禁用工作目录功能,直接使用 process.cwd()',
|
|
96
|
+
publish: 'mbler publish\n - 将你的附加包发布到 pmnx\n- 参数:\n- -tag: 版本标签名称\n- -build <skip|always>: 是否跳过构建(默认 always)',
|
|
97
|
+
uninstall: 'mbler uninstall @<scope>/<name>@version\n从你的游戏中移除一个包',
|
|
98
|
+
install: 'mbler install @<scope>/<name>@version\n将一个包安装到你的游戏中',
|
|
99
|
+
unpublish: 'mbler unpublish @<scope>/<name>@version\n从 pmnx 取消发布一个包',
|
|
100
|
+
login: 'mbler login <?:token>\n使用 token 登录你的 pmnx 账户\n- 如果没有 token,会向你请求',
|
|
101
|
+
profile: 'mbler profile\n显示当前登录账户信息',
|
|
102
|
+
view: 'mbler view @<scope>/<name>\n查看包的版本列表',
|
|
103
|
+
config: 'mbler config get <key>\nmbler config set <key> <value>\nmbler config point <path>\nmbler config point get',
|
|
104
|
+
},
|
|
105
|
+
init: {
|
|
106
|
+
useUI: '使用UI模块? (y/n): ',
|
|
107
|
+
useGIT: '初始化GIT仓库? (y/n): ',
|
|
108
|
+
name: '项目名称: ',
|
|
109
|
+
welcome: '欢迎使用Mbler初始化向导 语言:中文 mbler 版本: ' + version.version,
|
|
110
|
+
description: '项目描述: ',
|
|
111
|
+
initDes: '初始化依赖? (y/n): ',
|
|
112
|
+
lang: '选择项目语言: ',
|
|
113
|
+
betaApi: '使用Beta Api? (y/n): ',
|
|
114
|
+
mcVersion: '项目使用的mc版本(x.x.x): ',
|
|
115
|
+
noLanguare: '没有输入项目语言,这是必要的',
|
|
116
|
+
noName: '没有项目名称,这是必要的',
|
|
117
|
+
noMCVersion: "输入的 '支持的mc版本' 格式不对",
|
|
118
|
+
},
|
|
119
|
+
default: {
|
|
120
|
+
unexpected: '不正确的命令,',
|
|
121
|
+
youis: '你是否想说: ',
|
|
122
|
+
},
|
|
123
|
+
workdir: {
|
|
124
|
+
set: '[工作目录] 设置为: ',
|
|
125
|
+
nfound: '找不到输入文件夹(无法创建或不是文件夹)',
|
|
126
|
+
disabled: '工作目录功能已禁用,将使用当前目录',
|
|
127
|
+
enabled: '工作目录功能已启用',
|
|
128
|
+
invalidParam: '参数错误,请使用 on 或 off',
|
|
129
|
+
},
|
|
130
|
+
publish: {
|
|
131
|
+
askTip: '输入MCBE游戏绝对目录 (如 /sdcard/Android/data/com.mojang.minecraftpe/files/games),以进行下一步: ',
|
|
132
|
+
notLoggedIn: '未登录,请先执行 `mbler login <token>`',
|
|
133
|
+
progress: '进度: {progress}%',
|
|
134
|
+
publishFailed: '发布失败: {error}',
|
|
135
|
+
publishing: '正在发布...',
|
|
136
|
+
building: '正在构建项目...',
|
|
137
|
+
publishToMarket: '正在上传到市场...',
|
|
138
|
+
publishSuccess: '发布成功',
|
|
139
|
+
publishResult: '+ {name}@{version} ({tag})',
|
|
140
|
+
projectPathNotExist: '项目路径不存在',
|
|
141
|
+
outdirNotFound: '未找到构建输出目录配置',
|
|
142
|
+
outdirNotExist: '构建输出目录不存在',
|
|
143
|
+
readmeNotFound: '未找到 README 文件',
|
|
144
|
+
metadataInvalid: '元数据无效',
|
|
145
|
+
packageNameInvalid: '包名格式必须是 @scope/name',
|
|
146
|
+
notLoginError: '未登录',
|
|
147
|
+
tokenMissing: '获取 token 失败',
|
|
148
|
+
unpublishReqFailed: '取消发布请求失败',
|
|
149
|
+
createSessionFailed: '创建发布会话失败',
|
|
150
|
+
uploadZipFailed: '上传 zip 文件失败',
|
|
151
|
+
packageJsonNotFound: '未找到 package.json',
|
|
152
|
+
noBuildScript: 'package.json 中未找到 build 脚本',
|
|
153
|
+
buildFailed: '构建失败,退出码: {code}',
|
|
154
|
+
},
|
|
155
|
+
install: {
|
|
156
|
+
failedNoPackageJson: '安装失败:工作目录必须包含 package.json',
|
|
157
|
+
failedNoBuildScript: '安装失败:package.json 必须包含 build 脚本',
|
|
158
|
+
installing: '正在安装包 {pkg}...',
|
|
159
|
+
packageNotFound: '未找到包 {pkg}',
|
|
160
|
+
noVersion: '包 {pkg} 没有可用版本',
|
|
161
|
+
usingLatest: '使用最新版本 {version}',
|
|
162
|
+
noValidAddon: '包内未找到有效 addon',
|
|
163
|
+
success: '包 {pkg}@{version} 已安装为 {id}',
|
|
164
|
+
failed: '安装失败: {error}',
|
|
165
|
+
},
|
|
166
|
+
uninstall: {
|
|
167
|
+
success: '包 {pkg}@{version} 卸载成功',
|
|
168
|
+
failed: '卸载失败: {error}',
|
|
169
|
+
},
|
|
170
|
+
unpublish: {
|
|
171
|
+
success: '包 {pkg}@{version} 取消发布成功',
|
|
172
|
+
failed: '取消发布失败: {error}',
|
|
173
|
+
},
|
|
174
|
+
view: {
|
|
175
|
+
usage: 'mbler view @<scope>/<name>',
|
|
176
|
+
packageNotFound: '未找到包 {pkg}',
|
|
177
|
+
title: '包 {pkg} 版本列表:',
|
|
178
|
+
versionLine: '- {version} [{tag}] by {user} at {time}',
|
|
179
|
+
failed: '查看失败: {error}',
|
|
180
|
+
},
|
|
181
|
+
config: {
|
|
182
|
+
usage: 'mbler config get <key> | set <key> <value> | point <path> | point get',
|
|
183
|
+
missingArg: '参数不足',
|
|
184
|
+
getResult: '{key} = {value}',
|
|
185
|
+
setSuccess: '已设置 {key} = {value}',
|
|
186
|
+
pointGet: '当前配置文件: {path}',
|
|
187
|
+
pointSetSuccess: '配置文件指向已设置为: {path}',
|
|
188
|
+
pointSetFailed: '配置文件指向设置失败: {error}',
|
|
189
|
+
failed: '配置操作失败: {error}',
|
|
190
|
+
},
|
|
191
|
+
commander: {
|
|
192
|
+
selectTip: '(按 b 确认,n 键选择下一个)',
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
var enLang = {
|
|
197
|
+
description: 'MBLER\nMinecraft Bedrock Edition\nAddon Bulider In Nodejs\nnodejs build tools on bedrock version of minecraft\nCommands: ' +
|
|
198
|
+
cmdList.join(', ') +
|
|
199
|
+
'\nHelp command:\n help\n Show help information\n The second parameter is the name of the command to be queried or empty\n Alias: -h, -help\n git https://github.com/RuanhoR/mbler/',
|
|
200
|
+
help: {
|
|
201
|
+
cmds: cmdList,
|
|
202
|
+
help: 'mbler [help/h] [?: command name]\n - see tip',
|
|
203
|
+
h: '$help',
|
|
204
|
+
work: 'mbler [work/c] [?: path]\n - No input path: see current work dir\n - input path: set as current dir',
|
|
205
|
+
c: '$work',
|
|
206
|
+
init: 'mbler init\n - Init current work dir, you can use `mbler work` command or use command param(like be: mbler init -in ./)',
|
|
207
|
+
build: 'mbler build\n - perform a build using the library API',
|
|
208
|
+
b: '$build',
|
|
209
|
+
log: 'mbler log\n - Handler log file\n - mbler log point: Get log file path \n - mbler log clean: Remove Log',
|
|
210
|
+
watch: 'mbler watch\n - run build and enter watch mode; changes will trigger rebuilds',
|
|
211
|
+
lang: 'mbler lang [?:language]\n- No args: show current language\n- language = "zh” | “en": set language',
|
|
212
|
+
version: 'mbler version\n - Version control command\n- No args: Shows version + commit hash\n- --show=<commit|version>: Filters output\n- <new_version>: Updates version in both package.json and config file',
|
|
213
|
+
'set-work-dir': 'mbler set-work-dir <on|off>\n - on: Enable work dir feature\n - off: Disable work dir feature, use process.cwd() directly',
|
|
214
|
+
publish: 'mbler publish\n - Publish your package to pmnx\n- Params:\n- -tag: version tag name\n- -build <skip|always>: skip or run build before publish (default: always)',
|
|
215
|
+
uninstall: 'mbler uninstall @<scope>/<name>@version\nRemove a package from your game',
|
|
216
|
+
install: 'mbler install @<scope>/<name>@version\nInstall a package to your game',
|
|
217
|
+
unpublish: 'mbler unpublish @<scope>/<name>@version\nUnpublish a package from pmnx',
|
|
218
|
+
login: 'mbler login <?:token>\nUse token login your pmnx account',
|
|
219
|
+
profile: 'mbler profile\nShow current logged-in account profile',
|
|
220
|
+
view: 'mbler view @<scope>/<name>\nShow package versions',
|
|
221
|
+
config: 'mbler config get <key>\nmbler config set <key> <value>\nmbler config point <path>\nmbler config point get',
|
|
222
|
+
},
|
|
223
|
+
init: {
|
|
224
|
+
useUI: 'Use UI? (y/n): ',
|
|
225
|
+
useGIT: 'Initialize GIT repository? (y/n): ',
|
|
226
|
+
name: 'Project name: ',
|
|
227
|
+
description: 'Project description: ',
|
|
228
|
+
initDes: 'Initialize dependencies? (y/n): ',
|
|
229
|
+
welcome: 'Welcome to use Mbler init wizard! Language: English mbler version: ' +
|
|
230
|
+
version.version,
|
|
231
|
+
lang: 'Project language: ',
|
|
232
|
+
betaApi: 'use beta api(y/n): ',
|
|
233
|
+
mcVersion: 'Minecraft version(be like: x.x.x): ',
|
|
234
|
+
noLanguare: 'project language is required',
|
|
235
|
+
noMCVersion: 'project mcVersion format is not right',
|
|
236
|
+
noName: 'project name is required',
|
|
237
|
+
},
|
|
238
|
+
default: {
|
|
239
|
+
unexpected: 'Not found this command,',
|
|
240
|
+
youis: 'You want to input: ',
|
|
241
|
+
},
|
|
242
|
+
workdir: {
|
|
243
|
+
set: '[path to]: ',
|
|
244
|
+
nfound: "not found this dir(can't create or not directory)",
|
|
245
|
+
disabled: 'Work dir disabled, will use current directory',
|
|
246
|
+
enabled: 'Work dir enabled',
|
|
247
|
+
invalidParam: 'Invalid parameter, use on or off',
|
|
248
|
+
},
|
|
249
|
+
publish: {
|
|
250
|
+
askTip: 'Plase input the absolute path of your MCBE game directory (like /sdcard/Android/data/com.mojang.minecraftpe/files/games) for next step: ',
|
|
251
|
+
notLoggedIn: 'Not logged in. Use `mbler login <token>` first.',
|
|
252
|
+
progress: 'Progress: {progress}%',
|
|
253
|
+
publishFailed: 'Publish failed: {error}',
|
|
254
|
+
publishing: 'Publishing...',
|
|
255
|
+
building: 'Building project...',
|
|
256
|
+
publishToMarket: 'Publishing to marketplace...',
|
|
257
|
+
publishSuccess: 'Publish successful',
|
|
258
|
+
publishResult: '+ {name}@{version} ({tag})',
|
|
259
|
+
projectPathNotExist: 'Project path does not exist',
|
|
260
|
+
outdirNotFound: 'Build output directories not found',
|
|
261
|
+
outdirNotExist: 'Build output directories do not exist',
|
|
262
|
+
readmeNotFound: 'README file not found',
|
|
263
|
+
metadataInvalid: 'Invalid metadata',
|
|
264
|
+
packageNameInvalid: 'Package name must be in the format of @scope/name',
|
|
265
|
+
notLoginError: 'Not logged in',
|
|
266
|
+
tokenMissing: 'Failed to get token',
|
|
267
|
+
unpublishReqFailed: 'Failed to unpublish package',
|
|
268
|
+
createSessionFailed: 'Failed to create publish session',
|
|
269
|
+
uploadZipFailed: 'Failed to upload zip file',
|
|
270
|
+
packageJsonNotFound: 'package.json not found',
|
|
271
|
+
noBuildScript: 'No build script found in package.json',
|
|
272
|
+
buildFailed: 'Build failed with code {code}',
|
|
273
|
+
},
|
|
274
|
+
install: {
|
|
275
|
+
failedNoPackageJson: 'Install failed: work directory must contain package.json',
|
|
276
|
+
failedNoBuildScript: 'Install failed: package.json must contain a build script',
|
|
277
|
+
installing: 'Installing package {pkg}...',
|
|
278
|
+
packageNotFound: 'Package {pkg} not found',
|
|
279
|
+
noVersion: 'Package {pkg} has no available version',
|
|
280
|
+
usingLatest: 'Using latest version {version}',
|
|
281
|
+
noValidAddon: 'No valid addon found in package',
|
|
282
|
+
success: 'Package {pkg}@{version} installed successfully as {id}',
|
|
283
|
+
failed: 'Install failed: {error}',
|
|
284
|
+
},
|
|
285
|
+
uninstall: {
|
|
286
|
+
success: 'Package {pkg}@{version} uninstalled successfully',
|
|
287
|
+
failed: 'Uninstall failed: {error}',
|
|
288
|
+
},
|
|
289
|
+
unpublish: {
|
|
290
|
+
success: 'Package {pkg}@{version} unpublished successfully',
|
|
291
|
+
failed: 'Unpublish failed: {error}',
|
|
292
|
+
},
|
|
293
|
+
view: {
|
|
294
|
+
usage: 'mbler view @<scope>/<name>',
|
|
295
|
+
packageNotFound: 'Package {pkg} not found',
|
|
296
|
+
title: 'Package {pkg} versions:',
|
|
297
|
+
versionLine: '- {version} [{tag}] by {user} at {time}',
|
|
298
|
+
failed: 'View failed: {error}',
|
|
299
|
+
},
|
|
300
|
+
config: {
|
|
301
|
+
usage: 'mbler config get <key> | set <key> <value> | point <path> | point get',
|
|
302
|
+
missingArg: 'Missing argument',
|
|
303
|
+
getResult: '{key} = {value}',
|
|
304
|
+
setSuccess: 'Set {key} = {value}',
|
|
305
|
+
pointGet: 'Current config file: {path}',
|
|
306
|
+
pointSetSuccess: 'Config file pointer set to: {path}',
|
|
307
|
+
pointSetFailed: 'Failed to set config pointer: {error}',
|
|
308
|
+
failed: 'Config command failed: {error}',
|
|
309
|
+
},
|
|
310
|
+
commander: {
|
|
311
|
+
selectTip: '(Press b to confirm, n to select next)',
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const configPath = path__default.join(homedir(), // ~/.cache/mbler/lang.db: push language config
|
|
316
|
+
'.cache/mbler/lang.db');
|
|
317
|
+
function isLanguareName(language) {
|
|
318
|
+
return LanguageNames.includes(language);
|
|
319
|
+
}
|
|
320
|
+
class Lang {
|
|
321
|
+
currenyLang = 'zh';
|
|
322
|
+
init() {
|
|
323
|
+
try {
|
|
324
|
+
const TheyLang = fs__default.readFileSync(configPath, 'utf-8').toString().trim();
|
|
325
|
+
if (isLanguareName(TheyLang)) {
|
|
326
|
+
this.currenyLang = TheyLang;
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
throw new Error('[setup lang]: set lang error');
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
this.currenyLang = 'zh';
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
set(newLang) {
|
|
337
|
+
if (LanguageNames.includes(newLang)) {
|
|
338
|
+
if (!fs__default.existsSync(configPath)) {
|
|
339
|
+
fs__default.mkdirSync(path__default.dirname(configPath), {
|
|
340
|
+
recursive: true,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
fs__default.writeFileSync(configPath, newLang);
|
|
344
|
+
this.currenyLang = newLang;
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
get() {
|
|
350
|
+
try {
|
|
351
|
+
if (this.currenyLang == 'zh')
|
|
352
|
+
return ZhLang;
|
|
353
|
+
return enLang;
|
|
354
|
+
}
|
|
355
|
+
catch {
|
|
356
|
+
return ZhLang;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const lang = new Lang();
|
|
361
|
+
const i18n = {};
|
|
362
|
+
function Export(lang) {
|
|
363
|
+
const obj = lang.get();
|
|
364
|
+
Object.setPrototypeOf(i18n, {
|
|
365
|
+
...obj,
|
|
366
|
+
__internal: {
|
|
367
|
+
class: lang,
|
|
368
|
+
set: (newLang) => {
|
|
369
|
+
lang.set(newLang);
|
|
370
|
+
Export(lang);
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
lang.init();
|
|
376
|
+
Export(lang);
|
|
377
|
+
|
|
28
378
|
if (process.stdin.isTTY) {
|
|
29
379
|
process.stdin.setRawMode(true);
|
|
30
380
|
readline.emitKeypressEvents(process.stdin);
|
|
31
381
|
}
|
|
32
382
|
const promises = [];
|
|
33
383
|
const tasks = [];
|
|
34
|
-
process.on(
|
|
35
|
-
process.stdout.write(
|
|
384
|
+
process.on('exit', (_code) => {
|
|
385
|
+
process.stdout.write('\x1b[?25h');
|
|
36
386
|
});
|
|
37
387
|
const endTasks = [];
|
|
38
388
|
function onEnd(task) {
|
|
39
389
|
endTasks.push(task);
|
|
40
390
|
}
|
|
41
|
-
click(
|
|
391
|
+
click('c', {
|
|
42
392
|
ctrl: true,
|
|
43
393
|
}).then(() => {
|
|
44
394
|
endTasks.forEach((task) => task());
|
|
45
395
|
process.exit(0);
|
|
46
396
|
});
|
|
47
|
-
/**
|
|
48
|
-
* 监听键盘输入并触发对应的 Promise 或任务
|
|
49
|
-
*/
|
|
50
397
|
function handler(name, { ctrl, alt, }, raw) {
|
|
51
|
-
// 查找是否有匹配的 Promise 等待触发
|
|
52
398
|
const find = promises.find((e) => e.name === name && e.ctrl === ctrl && e.alt === alt);
|
|
53
399
|
if (find) {
|
|
54
400
|
find.resolve();
|
|
55
401
|
promises.splice(promises.indexOf(find), 1);
|
|
56
402
|
}
|
|
57
|
-
// 通知所有注册的监听任务
|
|
58
403
|
tasks.forEach((item) => item(name, ctrl, alt, raw));
|
|
59
404
|
}
|
|
60
|
-
/**
|
|
61
|
-
* 模拟等待某个按键被按下,返回一个 Promise
|
|
62
|
-
*/
|
|
63
405
|
function click(name, { ctrl = false, alt = false, }) {
|
|
64
406
|
return new Promise((resolve) => {
|
|
65
407
|
promises.push({
|
|
@@ -70,36 +412,21 @@ function click(name, { ctrl = false, alt = false, }) {
|
|
|
70
412
|
});
|
|
71
413
|
});
|
|
72
414
|
}
|
|
73
|
-
/**
|
|
74
|
-
* 工具类:提供控制台交互功能,比如高亮菜单渲染、交互式选择等
|
|
75
|
-
*/
|
|
76
415
|
class Input {
|
|
77
|
-
/**
|
|
78
|
-
* 渲染一个字符串数组,高亮当前选中的项
|
|
79
|
-
* @param arr 菜单项数组
|
|
80
|
-
* @param index 当前选中索引
|
|
81
|
-
* @returns 格式化后的字符串
|
|
82
|
-
*/
|
|
83
416
|
static render(arr, index) {
|
|
84
417
|
return arr
|
|
85
418
|
.map((item, pindex) => {
|
|
86
419
|
if (pindex === index)
|
|
87
|
-
return
|
|
88
|
-
return
|
|
420
|
+
return '\x1b[1m\x1b[32m' + item + '\x1b[0m'; // 亮绿,高亮
|
|
421
|
+
return '\x1b[1m\x1b[33m' + item + '\x1b[0m'; // 亮黄
|
|
89
422
|
})
|
|
90
|
-
.join(
|
|
423
|
+
.join(' ');
|
|
91
424
|
}
|
|
92
|
-
/**
|
|
93
|
-
* 提供一个交互式菜单选择器
|
|
94
|
-
* @param tip 提示文本
|
|
95
|
-
* @param arr 选项数组
|
|
96
|
-
* @returns 用户选中的选项内容(Promise<string>)
|
|
97
|
-
*/
|
|
98
425
|
static select(tip, arr) {
|
|
99
426
|
let index = 0;
|
|
100
427
|
let win = false;
|
|
101
|
-
console.log(`\x1b[2K\x1b[47m\x1b[1m\x1b[30m${tip}
|
|
102
|
-
console.log(Input.render(arr, index) +
|
|
428
|
+
console.log(`\x1b[2K\x1b[47m\x1b[1m\x1b[30m${tip} ${i18n.commander.selectTip} \x1b[0m\x1b[?25l`);
|
|
429
|
+
console.log(Input.render(arr, index) + '\n\x1b[1A');
|
|
103
430
|
const handlerNext = () => {
|
|
104
431
|
if (win)
|
|
105
432
|
return;
|
|
@@ -107,39 +434,32 @@ class Input {
|
|
|
107
434
|
if (index >= arr.length)
|
|
108
435
|
index = 0;
|
|
109
436
|
console.log(`\x1b[1A${Input.render(arr, index)}\n\x1b[1A`);
|
|
110
|
-
click(
|
|
437
|
+
click('n', {
|
|
111
438
|
ctrl: false,
|
|
112
439
|
alt: false,
|
|
113
440
|
}).then(handlerNext);
|
|
114
441
|
};
|
|
115
442
|
return new Promise((resolve) => {
|
|
116
|
-
|
|
117
|
-
click("n", {
|
|
443
|
+
click('n', {
|
|
118
444
|
ctrl: false,
|
|
119
445
|
alt: false,
|
|
120
446
|
}).then(handlerNext);
|
|
121
|
-
|
|
122
|
-
click("b", {
|
|
447
|
+
click('b', {
|
|
123
448
|
ctrl: false,
|
|
124
449
|
alt: false,
|
|
125
450
|
}).then(() => {
|
|
126
451
|
win = true;
|
|
127
|
-
process.stdout.write(
|
|
452
|
+
process.stdout.write('\x1b[?25h');
|
|
128
453
|
resolve(arr[index]);
|
|
129
454
|
});
|
|
130
455
|
});
|
|
131
456
|
}
|
|
132
|
-
/**
|
|
133
|
-
* 注册一个全局任务,每次按键都会被调用
|
|
134
|
-
* @param task 回调函数
|
|
135
|
-
*/
|
|
136
457
|
static use(task) {
|
|
137
458
|
tasks.push(task);
|
|
138
459
|
}
|
|
139
460
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const rawKeyName = key?.name || "";
|
|
461
|
+
process.stdin.on('keypress', (str, key) => {
|
|
462
|
+
const rawKeyName = key?.name || '';
|
|
143
463
|
const ctrl = Boolean(key?.ctrl);
|
|
144
464
|
const alt = Boolean(key?.alt);
|
|
145
465
|
handler(rawKeyName, {
|
|
@@ -148,98 +468,147 @@ process.stdin.on("keypress", (str, key) => {
|
|
|
148
468
|
}, str);
|
|
149
469
|
});
|
|
150
470
|
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
},
|
|
165
|
-
build: {
|
|
166
|
-
rollupPlugins: [],
|
|
167
|
-
cache: "auto",
|
|
168
|
-
bundle: true,
|
|
169
|
-
onEnd: () => { },
|
|
170
|
-
onStart: () => { },
|
|
171
|
-
onWarn: () => { }
|
|
471
|
+
const logFile = path__default.join(os.homedir(), '.cache/mbler/latest.log');
|
|
472
|
+
function _clean(promise) {
|
|
473
|
+
return () => {
|
|
474
|
+
Logger.run = Logger.run.filter((item) => {
|
|
475
|
+
return item !== promise;
|
|
476
|
+
});
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
async function FileExsit$1(file) {
|
|
480
|
+
try {
|
|
481
|
+
const f = await fs__default$1.stat(file);
|
|
482
|
+
if (f)
|
|
483
|
+
return true;
|
|
172
484
|
}
|
|
173
|
-
|
|
485
|
+
catch {
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
function writeLog(logContent) {
|
|
491
|
+
async function write() {
|
|
492
|
+
try {
|
|
493
|
+
const dir = path__default.dirname(logFile);
|
|
494
|
+
if (!(await FileExsit$1(dir))) {
|
|
495
|
+
// ensure the directory exists, root-to-leaf
|
|
496
|
+
await fs__default$1.mkdir(dir, { recursive: true }).catch(() => void 0);
|
|
497
|
+
}
|
|
498
|
+
// if file does not exist, create it (touch)
|
|
499
|
+
if (!(await FileExsit$1(logFile))) {
|
|
500
|
+
await fs__default$1.writeFile(logFile, '');
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
catch (err) {
|
|
504
|
+
// if we can't prepare the log file, output to stderr but don't crash
|
|
505
|
+
console.error('[logger] unable to prepare log file:', err);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
try {
|
|
509
|
+
await fs__default$1.appendFile(logFile, '\n' + logContent);
|
|
510
|
+
}
|
|
511
|
+
catch (err) {
|
|
512
|
+
console.error('[logger] failed to append to log file:', err);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
const asy = write();
|
|
516
|
+
Logger.run.push(asy.then(_clean(asy)));
|
|
517
|
+
}
|
|
518
|
+
class Logger {
|
|
519
|
+
static LogFile = logFile;
|
|
520
|
+
static run = [];
|
|
521
|
+
static _b(tag, msg, t) {
|
|
522
|
+
const date = new Date();
|
|
523
|
+
const logContent = [
|
|
524
|
+
`${date.toLocaleDateString()} ${date.toLocaleTimeString()}`,
|
|
525
|
+
`[${t} ${tag}]`,
|
|
526
|
+
msg,
|
|
527
|
+
].join(' ');
|
|
528
|
+
writeLog(logContent);
|
|
529
|
+
}
|
|
530
|
+
static w(tag, msg) {
|
|
531
|
+
Logger._b(tag, msg, 'WARN');
|
|
532
|
+
}
|
|
533
|
+
static e(tag, msg) {
|
|
534
|
+
Logger._b(tag, msg, 'ERROR');
|
|
535
|
+
}
|
|
536
|
+
static i(tag, msg) {
|
|
537
|
+
Logger._b(tag, msg, 'INFO');
|
|
538
|
+
}
|
|
539
|
+
static d(tag, msg) {
|
|
540
|
+
Logger._b(tag, msg, 'DEBUG');
|
|
541
|
+
}
|
|
542
|
+
}
|
|
174
543
|
|
|
175
544
|
const BuildConfig = {
|
|
176
|
-
ConfigFile:
|
|
545
|
+
ConfigFile: 'mbler.config.js',
|
|
177
546
|
salt: {
|
|
178
|
-
header:
|
|
179
|
-
sapi:
|
|
180
|
-
module:
|
|
547
|
+
header: 'd61e721d-a2c9-4535-8054-0183bce24767',
|
|
548
|
+
sapi: '33e2c698-908f-45ab-8a9f-66018f8486ed',
|
|
549
|
+
module: 'cbbacfa4-8b1e-4a9c-9cbd-7a0d2e5f0b3c',
|
|
181
550
|
},
|
|
182
|
-
behavior:
|
|
183
|
-
resources:
|
|
551
|
+
behavior: 'behavior',
|
|
552
|
+
resources: 'resources',
|
|
184
553
|
includes: {
|
|
185
554
|
public: {
|
|
186
|
-
|
|
187
|
-
|
|
555
|
+
'pack_icon.png': 'file',
|
|
556
|
+
'manifest.json': 'file',
|
|
188
557
|
},
|
|
189
558
|
resources: {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
animation_controllers:
|
|
200
|
-
animations:
|
|
201
|
-
attachables:
|
|
202
|
-
biomes:
|
|
203
|
-
cameras:
|
|
204
|
-
entity:
|
|
205
|
-
fogs:
|
|
206
|
-
font:
|
|
207
|
-
items:
|
|
208
|
-
library:
|
|
209
|
-
materials:
|
|
210
|
-
models:
|
|
211
|
-
particles:
|
|
212
|
-
render_controllers:
|
|
213
|
-
sounds:
|
|
214
|
-
texts:
|
|
215
|
-
textures:
|
|
559
|
+
'biomes_client.json': 'file',
|
|
560
|
+
'blocks.json': 'file',
|
|
561
|
+
'bug_pack_icon.png': 'file',
|
|
562
|
+
'contents.json': 'file',
|
|
563
|
+
'loading_messages.json': 'file',
|
|
564
|
+
'manifest_publish.json': 'file',
|
|
565
|
+
'signatures.json': 'file',
|
|
566
|
+
'sounds.json': 'file',
|
|
567
|
+
'splashes.json': 'file',
|
|
568
|
+
animation_controllers: 'directory',
|
|
569
|
+
animations: 'directory',
|
|
570
|
+
attachables: 'directory',
|
|
571
|
+
biomes: 'directory',
|
|
572
|
+
cameras: 'directory',
|
|
573
|
+
entity: 'directory',
|
|
574
|
+
fogs: 'directory',
|
|
575
|
+
font: 'directory',
|
|
576
|
+
items: 'directory',
|
|
577
|
+
library: 'directory',
|
|
578
|
+
materials: 'directory',
|
|
579
|
+
models: 'directory',
|
|
580
|
+
particles: 'directory',
|
|
581
|
+
render_controllers: 'directory',
|
|
582
|
+
sounds: 'directory',
|
|
583
|
+
texts: 'directory',
|
|
584
|
+
textures: 'directory',
|
|
216
585
|
},
|
|
217
586
|
behavior: {
|
|
218
|
-
aim_assist:
|
|
219
|
-
animation_controllers:
|
|
220
|
-
animations:
|
|
221
|
-
behavior_trees:
|
|
222
|
-
biomes:
|
|
223
|
-
blocks:
|
|
224
|
-
cameras:
|
|
225
|
-
dimensions:
|
|
226
|
-
entities:
|
|
227
|
-
feature_rules:
|
|
228
|
-
features:
|
|
229
|
-
functions:
|
|
230
|
-
item_catalog:
|
|
231
|
-
items:
|
|
232
|
-
loot_tables:
|
|
233
|
-
recipes:
|
|
234
|
-
scripts:
|
|
235
|
-
spawn_rules:
|
|
236
|
-
structures:
|
|
237
|
-
texts:
|
|
238
|
-
trading:
|
|
239
|
-
worldgen:
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
587
|
+
aim_assist: 'directory',
|
|
588
|
+
animation_controllers: 'directory',
|
|
589
|
+
animations: 'directory',
|
|
590
|
+
behavior_trees: 'directory',
|
|
591
|
+
biomes: 'directory',
|
|
592
|
+
blocks: 'directory',
|
|
593
|
+
cameras: 'directory',
|
|
594
|
+
dimensions: 'directory',
|
|
595
|
+
entities: 'directory',
|
|
596
|
+
feature_rules: 'directory',
|
|
597
|
+
features: 'directory',
|
|
598
|
+
functions: 'directory',
|
|
599
|
+
item_catalog: 'directory',
|
|
600
|
+
items: 'directory',
|
|
601
|
+
loot_tables: 'directory',
|
|
602
|
+
recipes: 'directory',
|
|
603
|
+
scripts: 'skip', // special handling
|
|
604
|
+
spawn_rules: 'directory',
|
|
605
|
+
structures: 'directory',
|
|
606
|
+
texts: 'directory',
|
|
607
|
+
trading: 'directory',
|
|
608
|
+
worldgen: 'directory',
|
|
609
|
+
'contents.json': 'file',
|
|
610
|
+
'manifest_publish.json': 'file',
|
|
611
|
+
'signatures.json': 'file',
|
|
243
612
|
},
|
|
244
613
|
},
|
|
245
614
|
};
|
|
@@ -266,14 +635,32 @@ async function ReadProjectMblerConfig(project) {
|
|
|
266
635
|
throw new Error(`[read config]: read config from '${project}' error: Unexpected '${key}'`);
|
|
267
636
|
}
|
|
268
637
|
}
|
|
269
|
-
|
|
638
|
+
const config = {
|
|
639
|
+
...templateMblerConfig,
|
|
640
|
+
...file,
|
|
641
|
+
};
|
|
642
|
+
try {
|
|
643
|
+
const pkgRaw = await fs.readFile(path.join(project, 'package.json'), 'utf-8');
|
|
644
|
+
const pkg = JSON.parse(pkgRaw);
|
|
645
|
+
if (pkg.name)
|
|
646
|
+
config.name = pkg.name;
|
|
647
|
+
if (pkg.version)
|
|
648
|
+
config.version = pkg.version;
|
|
649
|
+
}
|
|
650
|
+
catch {
|
|
651
|
+
// fallback to mbler.config.js or template defaults
|
|
652
|
+
}
|
|
653
|
+
if (!config.name)
|
|
654
|
+
config.name = 'unknown';
|
|
655
|
+
if (!config.version)
|
|
656
|
+
config.version = '0.0.0';
|
|
657
|
+
return config;
|
|
270
658
|
}
|
|
271
659
|
/**
|
|
272
660
|
* Print a single-line message to stdout with a trailing newline.
|
|
273
661
|
* Exported here so other modules (for example `build`) do not need
|
|
274
662
|
* to import from `cli`, avoiding a circular dependency.
|
|
275
663
|
*/
|
|
276
|
-
// IO缓冲队列,避免多线程写入冲突
|
|
277
664
|
let outputQueue = [];
|
|
278
665
|
let isFlushing = false;
|
|
279
666
|
async function flushOutputQueue() {
|
|
@@ -292,11 +679,13 @@ async function flushOutputQueue() {
|
|
|
292
679
|
isFlushing = false;
|
|
293
680
|
}
|
|
294
681
|
}
|
|
295
|
-
process.on(
|
|
682
|
+
process.on('exit', flushOutputQueue);
|
|
296
683
|
function showText(text, needNextLine = true) {
|
|
297
|
-
outputQueue.push(text + (needNextLine ? '\n' :
|
|
684
|
+
outputQueue.push(text + (needNextLine ? '\n' : ''));
|
|
298
685
|
if (!isFlushing) {
|
|
299
|
-
Promise.resolve()
|
|
686
|
+
Promise.resolve()
|
|
687
|
+
.then(() => flushOutputQueue())
|
|
688
|
+
.catch(() => {
|
|
300
689
|
outputQueue = [];
|
|
301
690
|
isFlushing = false;
|
|
302
691
|
});
|
|
@@ -379,165 +768,54 @@ function compareVersion(a, b) {
|
|
|
379
768
|
};
|
|
380
769
|
}))();
|
|
381
770
|
|
|
382
|
-
const logFile = path__default.join(os.homedir(), ".cache/mbler/latest.log");
|
|
383
|
-
function _clean(promise) {
|
|
384
|
-
return () => {
|
|
385
|
-
Logger.run = Logger.run.filter((item) => {
|
|
386
|
-
return item !== promise;
|
|
387
|
-
});
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
function writeLog(logContent) {
|
|
391
|
-
async function write() {
|
|
392
|
-
try {
|
|
393
|
-
const dir = path__default.dirname(logFile);
|
|
394
|
-
if (!(await FileExsit(dir))) {
|
|
395
|
-
// ensure the directory exists, root-to-leaf
|
|
396
|
-
await fs__default.mkdir(dir, { recursive: true }).catch(() => void 0);
|
|
397
|
-
}
|
|
398
|
-
// if file does not exist, create it (touch)
|
|
399
|
-
if (!(await FileExsit(logFile))) {
|
|
400
|
-
await fs__default.writeFile(logFile, "");
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
catch (err) {
|
|
404
|
-
// if we can't prepare the log file, output to stderr but don't crash
|
|
405
|
-
console.error("[logger] unable to prepare log file:", err);
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
try {
|
|
409
|
-
await fs__default.appendFile(logFile, "\n" + logContent);
|
|
410
|
-
}
|
|
411
|
-
catch (err) {
|
|
412
|
-
console.error("[logger] failed to append to log file:", err);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
const asy = write();
|
|
416
|
-
Logger.run.push(asy.then(_clean(asy)));
|
|
417
|
-
}
|
|
418
|
-
class Logger {
|
|
419
|
-
// 写入日志池
|
|
420
|
-
static LogFile = logFile;
|
|
421
|
-
static run = [];
|
|
422
|
-
static _b(tag, msg, t) {
|
|
423
|
-
const date = new Date();
|
|
424
|
-
const logContent = [
|
|
425
|
-
`${date.toLocaleDateString()} ${date.toLocaleTimeString()}`,
|
|
426
|
-
`[${t} ${tag}]`,
|
|
427
|
-
msg,
|
|
428
|
-
].join(" ");
|
|
429
|
-
writeLog(logContent);
|
|
430
|
-
}
|
|
431
|
-
static w(tag, msg) {
|
|
432
|
-
Logger._b(tag, msg, "WARN");
|
|
433
|
-
}
|
|
434
|
-
static e(tag, msg) {
|
|
435
|
-
Logger._b(tag, msg, "ERROR");
|
|
436
|
-
}
|
|
437
|
-
static i(tag, msg) {
|
|
438
|
-
Logger._b(tag, msg, "INFO");
|
|
439
|
-
}
|
|
440
|
-
static d(tag, msg) {
|
|
441
|
-
Logger._b(tag, msg, "DEBUG");
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
771
|
class BuildCacheManager {
|
|
446
|
-
projectRoot;
|
|
447
772
|
isWatch;
|
|
448
|
-
cacheDir;
|
|
449
|
-
cacheFile;
|
|
450
773
|
mode;
|
|
451
|
-
|
|
452
|
-
constructor(projectRoot, mode, isWatch) {
|
|
453
|
-
this.projectRoot = projectRoot;
|
|
774
|
+
constructor(_projectRoot, mode, isWatch, _cachePath) {
|
|
454
775
|
this.isWatch = isWatch;
|
|
455
|
-
this.cacheDir = path__default.join(this.projectRoot, ".mbler", "cache");
|
|
456
|
-
this.cacheFile = path__default.join(this.cacheDir, "rollup.cache.bin");
|
|
457
776
|
this.mode = this.resolveMode(mode);
|
|
458
777
|
}
|
|
459
778
|
getMode() {
|
|
460
779
|
return this.mode;
|
|
461
780
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
return undefined;
|
|
465
|
-
if (this.mode === "memory")
|
|
466
|
-
return this.memoryCache;
|
|
467
|
-
if (this.memoryCache)
|
|
468
|
-
return this.memoryCache;
|
|
469
|
-
try {
|
|
470
|
-
const raw = await fs__default.readFile(this.cacheFile);
|
|
471
|
-
this.memoryCache = deserialize(raw);
|
|
472
|
-
return this.memoryCache;
|
|
473
|
-
}
|
|
474
|
-
catch {
|
|
475
|
-
return undefined;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
getWatchCacheOption() {
|
|
479
|
-
if (this.mode === "none")
|
|
480
|
-
return false;
|
|
481
|
-
return true;
|
|
482
|
-
}
|
|
483
|
-
async saveRollupCache(cache) {
|
|
484
|
-
if (!cache || this.mode === "none")
|
|
485
|
-
return;
|
|
486
|
-
this.memoryCache = cache;
|
|
487
|
-
if (this.mode !== "file")
|
|
488
|
-
return;
|
|
489
|
-
try {
|
|
490
|
-
await fs__default.mkdir(this.cacheDir, { recursive: true });
|
|
491
|
-
await fs__default.writeFile(this.cacheFile, serialize(cache));
|
|
492
|
-
}
|
|
493
|
-
catch (error) {
|
|
494
|
-
Logger.w("BuildCache", `failed to write file cache: ${error}`);
|
|
495
|
-
}
|
|
781
|
+
shouldUseIncrementalBuild() {
|
|
782
|
+
return this.mode !== 'none';
|
|
496
783
|
}
|
|
497
784
|
resolveMode(mode) {
|
|
498
|
-
const value = mode ??
|
|
499
|
-
if (value ===
|
|
500
|
-
return
|
|
501
|
-
|
|
502
|
-
if (this.isWatch)
|
|
503
|
-
return "memory";
|
|
504
|
-
return "none";
|
|
505
|
-
}
|
|
506
|
-
if (value === "file" || value === "filesystem")
|
|
507
|
-
return "file";
|
|
508
|
-
// auto: watch mode uses memory, non-watch uses file
|
|
509
|
-
return this.isWatch ? "memory" : "file";
|
|
785
|
+
const value = mode ?? 'auto';
|
|
786
|
+
if (value === 'none')
|
|
787
|
+
return 'none';
|
|
788
|
+
return 'file';
|
|
510
789
|
}
|
|
511
790
|
}
|
|
512
791
|
|
|
513
|
-
|
|
792
|
+
/**
|
|
793
|
+
* @description To generate uuid
|
|
794
|
+
*/
|
|
514
795
|
const fromString = (input, salt = '') => {
|
|
515
796
|
const combinedInput = salt + input;
|
|
516
|
-
const hash = crypto
|
|
517
|
-
|
|
518
|
-
.update(combinedInput)
|
|
519
|
-
.digest('hex');
|
|
520
|
-
const base = hash
|
|
521
|
-
.slice(0, 32); // 取前 32 个 hex 字符(16 字节)
|
|
797
|
+
const hash = crypto.createHash('sha256').update(combinedInput).digest('hex');
|
|
798
|
+
const base = hash.slice(0, 32);
|
|
522
799
|
const ls = '89ab';
|
|
523
800
|
const r = (t) => ls[(combinedInput.length + t + salt.length) % ls.length];
|
|
524
|
-
//
|
|
801
|
+
// build to:xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
|
525
802
|
const uuid = `${base.substring(0, 8)}-${base.substring(8, 12)}-4${base.substring(12, 15)}-8${r(1)}${r(2)}${r(3)}-${base.substring(18, 30)}`;
|
|
526
803
|
return uuid;
|
|
527
804
|
};
|
|
528
805
|
({
|
|
529
|
-
uuid: crypto.randomUUID
|
|
806
|
+
uuid: crypto.randomUUID,
|
|
530
807
|
});
|
|
531
808
|
|
|
532
809
|
const config = {
|
|
533
|
-
tmpdir: path.join(tmpdir(),
|
|
810
|
+
tmpdir: path.join(tmpdir(), '.mbler')};
|
|
534
811
|
|
|
535
812
|
/**
|
|
536
813
|
* Compare two dotted version strings ("major.minor.patch").
|
|
537
814
|
* Returns negative if a < b, positive if a > b, zero if equal.
|
|
538
815
|
*/
|
|
539
|
-
const
|
|
540
|
-
const
|
|
816
|
+
const Sapi$1 = function () {
|
|
817
|
+
const { json } = require('npm-registry-fetch');
|
|
818
|
+
const cacheFile = path.join(config.tmpdir, '_sapi_version.json');
|
|
541
819
|
// cacheData is an array of entries keyed by the embedded mc version string
|
|
542
820
|
let cacheData = null;
|
|
543
821
|
/**
|
|
@@ -563,7 +841,11 @@ const exp = (function () {
|
|
|
563
841
|
const isStable = /(?:-stable)(?:$|[-.])/.test(v);
|
|
564
842
|
let entry = reValue[mcVersion];
|
|
565
843
|
if (!entry) {
|
|
566
|
-
entry = {
|
|
844
|
+
entry = {
|
|
845
|
+
formal: '',
|
|
846
|
+
beta: '',
|
|
847
|
+
_v: -1,
|
|
848
|
+
};
|
|
567
849
|
reValue[mcVersion] = entry;
|
|
568
850
|
}
|
|
569
851
|
if (isStable) {
|
|
@@ -586,8 +868,8 @@ const exp = (function () {
|
|
|
586
868
|
}
|
|
587
869
|
async function refresh() {
|
|
588
870
|
// grab the two packages we care about and merge the keys
|
|
589
|
-
const serverMap = await fetchData(
|
|
590
|
-
const uiMap = await fetchData(
|
|
871
|
+
const serverMap = await fetchData('@minecraft/server');
|
|
872
|
+
const uiMap = await fetchData('@minecraft/server-ui');
|
|
591
873
|
const versions = new Set([
|
|
592
874
|
...Object.keys(serverMap),
|
|
593
875
|
...Object.keys(uiMap),
|
|
@@ -597,24 +879,38 @@ const exp = (function () {
|
|
|
597
879
|
arr.push({
|
|
598
880
|
version: ver,
|
|
599
881
|
server: serverMap[ver]
|
|
600
|
-
? {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
: {
|
|
882
|
+
? {
|
|
883
|
+
formal: serverMap[ver].formal,
|
|
884
|
+
beta: serverMap[ver].beta,
|
|
885
|
+
}
|
|
886
|
+
: {
|
|
887
|
+
formal: '',
|
|
888
|
+
beta: '',
|
|
889
|
+
},
|
|
890
|
+
'server-ui': uiMap[ver]
|
|
891
|
+
? {
|
|
892
|
+
formal: uiMap[ver].formal,
|
|
893
|
+
beta: uiMap[ver].beta,
|
|
894
|
+
}
|
|
895
|
+
: {
|
|
896
|
+
formal: '',
|
|
897
|
+
beta: '',
|
|
898
|
+
},
|
|
605
899
|
});
|
|
606
900
|
}
|
|
607
901
|
arr.sort((a, b) => compareVersion(a.version, b.version));
|
|
608
902
|
cacheData = arr;
|
|
609
903
|
await fs$1.promises
|
|
610
|
-
.mkdir(config.tmpdir, {
|
|
904
|
+
.mkdir(config.tmpdir, {
|
|
905
|
+
recursive: true,
|
|
906
|
+
})
|
|
611
907
|
.catch(() => void 0);
|
|
612
|
-
await fs$1.promises.writeFile(cacheFile, JSON.stringify(arr, null, 2),
|
|
908
|
+
await fs$1.promises.writeFile(cacheFile, JSON.stringify(arr, null, 2), 'utf-8');
|
|
613
909
|
}
|
|
614
|
-
async function generateVersion(module, mcVersion, isBeta) {
|
|
910
|
+
async function generateVersion(module, mcVersion, isBeta, withFull = false) {
|
|
615
911
|
if (!cacheData) {
|
|
616
912
|
try {
|
|
617
|
-
const txt = await fs$1.promises.readFile(cacheFile,
|
|
913
|
+
const txt = await fs$1.promises.readFile(cacheFile, 'utf-8');
|
|
618
914
|
cacheData = JSON.parse(txt);
|
|
619
915
|
}
|
|
620
916
|
catch {
|
|
@@ -622,7 +918,7 @@ const exp = (function () {
|
|
|
622
918
|
}
|
|
623
919
|
}
|
|
624
920
|
if (!cacheData) {
|
|
625
|
-
throw new Error(
|
|
921
|
+
throw new Error('unable to load sapi cache data');
|
|
626
922
|
}
|
|
627
923
|
// try exact match first
|
|
628
924
|
let entry = cacheData.find((e) => e.version === mcVersion);
|
|
@@ -643,26 +939,50 @@ const exp = (function () {
|
|
|
643
939
|
}
|
|
644
940
|
entry = candidate;
|
|
645
941
|
}
|
|
646
|
-
const moduleKey = module ===
|
|
942
|
+
const moduleKey = module === '@minecraft/server' ? 'server' : 'server-ui';
|
|
647
943
|
const entryModule = entry[moduleKey];
|
|
648
944
|
let result = isBeta ? entryModule.beta : entryModule.formal;
|
|
649
945
|
if (!result) {
|
|
650
946
|
// fall back to whatever is available
|
|
651
947
|
result = entryModule.formal || entryModule.beta;
|
|
652
948
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
949
|
+
if (withFull)
|
|
950
|
+
return result || '';
|
|
951
|
+
else {
|
|
952
|
+
const tmp = result.split('-').slice(0, 2);
|
|
953
|
+
tmp[1] = tmp[1].split('.')[0];
|
|
954
|
+
result = tmp.join('-');
|
|
955
|
+
return result || 'error';
|
|
956
|
+
}
|
|
657
957
|
}
|
|
658
958
|
return {
|
|
659
959
|
refresh,
|
|
660
960
|
generateVersion,
|
|
661
961
|
};
|
|
662
|
-
}
|
|
962
|
+
};
|
|
963
|
+
let sapiEmul = null;
|
|
964
|
+
var Sapi = new Proxy({}, {
|
|
965
|
+
get(_, p) {
|
|
966
|
+
if (!sapiEmul)
|
|
967
|
+
sapiEmul = Sapi$1();
|
|
968
|
+
return sapiEmul[p];
|
|
969
|
+
},
|
|
970
|
+
set(_, p, n) {
|
|
971
|
+
if (!sapiEmul)
|
|
972
|
+
sapiEmul = Sapi$1();
|
|
973
|
+
sapiEmul[p] = n;
|
|
974
|
+
return true;
|
|
975
|
+
},
|
|
976
|
+
});
|
|
977
|
+
function evalVersion(result) {
|
|
978
|
+
const tmp = result.split('-').slice(0, 2);
|
|
979
|
+
tmp[1] = tmp[1].split('.')[0];
|
|
980
|
+
result = tmp.join('-');
|
|
981
|
+
return result;
|
|
982
|
+
}
|
|
663
983
|
|
|
664
984
|
async function generateManifest(config, type) {
|
|
665
|
-
const hashRaw = `${config.name}-${type}-${config.script?.lang ||
|
|
985
|
+
const hashRaw = `${config.name}-${type}-${config.script?.lang || 'js'}--mbler-hash-raw--:build-manifest`;
|
|
666
986
|
const manifest = {
|
|
667
987
|
format_version: 2,
|
|
668
988
|
header: {
|
|
@@ -670,10 +990,10 @@ async function generateManifest(config, type) {
|
|
|
670
990
|
description: config.description,
|
|
671
991
|
uuid: fromString(hashRaw, BuildConfig.salt.header),
|
|
672
992
|
version: stringToNumberArray(config.version),
|
|
673
|
-
min_engine_version: stringToNumberArray(typeof config.mcVersion ===
|
|
993
|
+
min_engine_version: stringToNumberArray(typeof config.mcVersion === 'string'
|
|
674
994
|
? config.mcVersion
|
|
675
995
|
: (() => {
|
|
676
|
-
throw new Error(
|
|
996
|
+
throw new Error('mcVersion in mblerconfig should be a string');
|
|
677
997
|
})()),
|
|
678
998
|
},
|
|
679
999
|
modules: [
|
|
@@ -685,80 +1005,106 @@ async function generateManifest(config, type) {
|
|
|
685
1005
|
},
|
|
686
1006
|
],
|
|
687
1007
|
};
|
|
688
|
-
if (type ===
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
1008
|
+
if (type === 'data' && config.script) {
|
|
1009
|
+
const isBundle = config.build?.bundle !== false;
|
|
1010
|
+
const outputDir = config.build?.outputDir || 'scripts';
|
|
1011
|
+
let entry;
|
|
1012
|
+
if (isBundle) {
|
|
1013
|
+
let filename = config.script.main || 'index.js';
|
|
1014
|
+
if (config.build?.outputFilename) {
|
|
1015
|
+
filename = config.build.outputFilename;
|
|
1016
|
+
}
|
|
1017
|
+
const extName = extname(filename);
|
|
1018
|
+
if (extName !== '.js') {
|
|
1019
|
+
filename = filename.slice(0, -extName.length) + '.js';
|
|
1020
|
+
}
|
|
1021
|
+
if (config.script.lang == 'mcx') {
|
|
1022
|
+
entry = `${outputDir}/index.js`;
|
|
1023
|
+
}
|
|
1024
|
+
else {
|
|
1025
|
+
entry = `${outputDir}/${filename}`;
|
|
1026
|
+
}
|
|
692
1027
|
}
|
|
693
1028
|
else {
|
|
694
|
-
entry =
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
1029
|
+
entry = `${outputDir}/${config.script.main || 'index.js'}`;
|
|
1030
|
+
const extName = extname(entry);
|
|
1031
|
+
if (extName !== '.js') {
|
|
1032
|
+
entry = entry.slice(0, -extName.length) + '.js';
|
|
1033
|
+
}
|
|
699
1034
|
}
|
|
700
1035
|
manifest.modules.push({
|
|
701
|
-
type:
|
|
1036
|
+
type: 'script',
|
|
702
1037
|
entry: entry,
|
|
703
|
-
language:
|
|
1038
|
+
language: 'javascript',
|
|
704
1039
|
uuid: fromString(hashRaw, BuildConfig.salt.sapi),
|
|
705
1040
|
description: `sapi generate by mbler, weclome to download and star at https://github.com/RuanhoR/mbler`,
|
|
706
1041
|
version: stringToNumberArray(config.version),
|
|
707
1042
|
});
|
|
708
|
-
manifest.capabilities = [
|
|
1043
|
+
manifest.capabilities = ['script_eval'];
|
|
709
1044
|
manifest.dependencies = [
|
|
710
1045
|
{
|
|
711
|
-
module_name:
|
|
712
|
-
version: (await
|
|
1046
|
+
module_name: '@minecraft/server',
|
|
1047
|
+
version: evalVersion(await Sapi.generateVersion('@minecraft/server', config.mcVersion, config.script?.UseBeta || false, false)), // only major.minor.patch, remove -beta or -rc
|
|
713
1048
|
},
|
|
714
1049
|
];
|
|
715
1050
|
if (config.script.ui) {
|
|
716
1051
|
manifest.dependencies.push({
|
|
717
|
-
module_name:
|
|
718
|
-
version: (await
|
|
1052
|
+
module_name: '@minecraft/server-ui',
|
|
1053
|
+
version: evalVersion(await Sapi.generateVersion('@minecraft/server-ui', config.mcVersion, config.script?.UseBeta || false, false)), // only major.minor.patch, remove -beta or -rc
|
|
719
1054
|
});
|
|
720
1055
|
}
|
|
721
1056
|
}
|
|
722
1057
|
return manifest;
|
|
723
1058
|
}
|
|
724
1059
|
|
|
725
|
-
function
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
const zip = new AdmZip();
|
|
732
|
-
for (const folder of dir) {
|
|
733
|
-
await zip.addLocalFolderPromise(folder[0], {
|
|
734
|
-
zipPath: folder[1]
|
|
735
|
-
});
|
|
736
|
-
}
|
|
737
|
-
return zip;
|
|
738
|
-
}
|
|
739
|
-
async function generateRelease(build) {
|
|
740
|
-
if (!build.outdirs)
|
|
741
|
-
throw new Error("invalid Build");
|
|
742
|
-
if (env.BUILD_MODULE !== "release")
|
|
743
|
-
return;
|
|
744
|
-
let zip;
|
|
745
|
-
if (build.module == "all") {
|
|
746
|
-
zip = await createZipWithMoreFolder([
|
|
747
|
-
[build.outdirs?.behavior, "behavior"],
|
|
748
|
-
[build.outdirs?.resources, "resources"]
|
|
749
|
-
]);
|
|
1060
|
+
function Release() {
|
|
1061
|
+
const AdmZip = require('adm-zip');
|
|
1062
|
+
function createFullZip(dir) {
|
|
1063
|
+
const zip = new AdmZip();
|
|
1064
|
+
zip.addLocalFolder(dir);
|
|
1065
|
+
return zip;
|
|
750
1066
|
}
|
|
751
|
-
|
|
752
|
-
zip =
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
1067
|
+
async function createZipWithMoreFolder(dir) {
|
|
1068
|
+
const zip = new AdmZip();
|
|
1069
|
+
for (const folder of dir) {
|
|
1070
|
+
await zip.addLocalFolderPromise(folder[0], {
|
|
1071
|
+
zipPath: folder[1],
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
return zip;
|
|
756
1075
|
}
|
|
757
|
-
|
|
1076
|
+
return async function generateRelease(build) {
|
|
1077
|
+
if (!build.outdirs)
|
|
1078
|
+
throw new Error('invalid Build');
|
|
1079
|
+
if (env.BUILD_MODULE !== 'release')
|
|
1080
|
+
return;
|
|
1081
|
+
let zip;
|
|
1082
|
+
if (build.module == 'all') {
|
|
1083
|
+
zip = await createZipWithMoreFolder([
|
|
1084
|
+
[build.outdirs?.behavior, 'behavior'],
|
|
1085
|
+
[build.outdirs?.resources, 'resources'],
|
|
1086
|
+
]);
|
|
1087
|
+
}
|
|
1088
|
+
else if (build.module == 'behavior') {
|
|
1089
|
+
zip = createFullZip(build.outdirs?.behavior);
|
|
1090
|
+
}
|
|
1091
|
+
else {
|
|
1092
|
+
zip = createFullZip(build.outdirs?.resources);
|
|
1093
|
+
}
|
|
1094
|
+
await zip.writeZipPromise(build.outdirs?.dist);
|
|
1095
|
+
};
|
|
758
1096
|
}
|
|
1097
|
+
let releaseEmul = null;
|
|
1098
|
+
const generateRelease = (...argv) => {
|
|
1099
|
+
if (!releaseEmul)
|
|
1100
|
+
releaseEmul = Release();
|
|
1101
|
+
return releaseEmul(...argv);
|
|
1102
|
+
};
|
|
759
1103
|
|
|
760
1104
|
// cjs support
|
|
761
|
-
const chalk$1 = _chalk instanceof Function
|
|
1105
|
+
const chalk$1 = _chalk instanceof Function
|
|
1106
|
+
? _chalk
|
|
1107
|
+
: _chalk.default;
|
|
762
1108
|
class Postgress {
|
|
763
1109
|
max;
|
|
764
1110
|
constructor(max) {
|
|
@@ -776,7 +1122,7 @@ class Postgress {
|
|
|
776
1122
|
const progressText = `\n\u001B[1A\r[${progressBar}] ${percentText} (${current}/${this.max})`;
|
|
777
1123
|
showText(progressText, false);
|
|
778
1124
|
if (current == this.max) {
|
|
779
|
-
showText(
|
|
1125
|
+
showText('', true);
|
|
780
1126
|
}
|
|
781
1127
|
}
|
|
782
1128
|
}
|
|
@@ -785,7 +1131,7 @@ class Postgress {
|
|
|
785
1131
|
* 运行 MCX TypeScript 编译器
|
|
786
1132
|
* 为 .mcx 文件提供 TypeScript 类型检查支持
|
|
787
1133
|
*/
|
|
788
|
-
function runTSC(tscpath = require.resolve(
|
|
1134
|
+
function runTSC(tscpath = require.resolve('typescript/lib/tsc')) {
|
|
789
1135
|
runTsc(tscpath, {
|
|
790
1136
|
extraSupportedExtensions: ['.mcx'],
|
|
791
1137
|
extraExtensionsToRemove: ['.mcx'],
|
|
@@ -794,8 +1140,10 @@ function runTSC(tscpath = require.resolve("typescript/lib/tsc")) {
|
|
|
794
1140
|
});
|
|
795
1141
|
}
|
|
796
1142
|
|
|
797
|
-
// cjs support
|
|
798
|
-
const chalk = _chalk instanceof Function
|
|
1143
|
+
// cjs support (Why is chalk's type so weak? )
|
|
1144
|
+
const chalk = _chalk instanceof Function
|
|
1145
|
+
? _chalk
|
|
1146
|
+
: _chalk.default;
|
|
799
1147
|
class Build {
|
|
800
1148
|
baseBuildDir;
|
|
801
1149
|
resolve;
|
|
@@ -811,12 +1159,13 @@ class Build {
|
|
|
811
1159
|
this.isWatch = isWatch;
|
|
812
1160
|
try {
|
|
813
1161
|
const tsModule = ts;
|
|
814
|
-
this.mcxLanguagePluginCreator =
|
|
1162
|
+
this.mcxLanguagePluginCreator =
|
|
1163
|
+
createMCXLanguagePlugin;
|
|
815
1164
|
this.mcxTs = tsModule;
|
|
816
1165
|
}
|
|
817
1166
|
catch (error) {
|
|
818
1167
|
this.mcxTs = ts;
|
|
819
|
-
Logger.w(
|
|
1168
|
+
Logger.w('Build', `Failed to initialize MCX language plugin: ${error}`);
|
|
820
1169
|
}
|
|
821
1170
|
}
|
|
822
1171
|
/**
|
|
@@ -831,7 +1180,7 @@ class Build {
|
|
|
831
1180
|
onEnd(() => {
|
|
832
1181
|
if (this.watchers) {
|
|
833
1182
|
this.watchers.chokidar.close();
|
|
834
|
-
this.watchers.rollup
|
|
1183
|
+
this.watchers.rollup?.close();
|
|
835
1184
|
}
|
|
836
1185
|
});
|
|
837
1186
|
await this._watch();
|
|
@@ -884,7 +1233,7 @@ class Build {
|
|
|
884
1233
|
closeWatchers() {
|
|
885
1234
|
if (this.watchers) {
|
|
886
1235
|
this.watchers.chokidar.close();
|
|
887
|
-
this.watchers.rollup
|
|
1236
|
+
this.watchers.rollup?.close();
|
|
888
1237
|
this.watchers = null;
|
|
889
1238
|
}
|
|
890
1239
|
}
|
|
@@ -944,7 +1293,7 @@ class Build {
|
|
|
944
1293
|
this.currentConfig = await ReadProjectMblerConfig(this.baseBuildDir);
|
|
945
1294
|
if (this.currentConfig.build)
|
|
946
1295
|
this.buildConfig = this.currentConfig.build;
|
|
947
|
-
this.cacheManager = new BuildCacheManager(this.baseBuildDir, this.buildConfig?.cache, this.isWatch);
|
|
1296
|
+
this.cacheManager = new BuildCacheManager(this.baseBuildDir, this.buildConfig?.cache, this.isWatch, this.buildConfig?.cachePath);
|
|
948
1297
|
if (this.buildConfig?.onStart)
|
|
949
1298
|
await this.buildConfig.onStart(this.currentConfig);
|
|
950
1299
|
this.loadData();
|
|
@@ -954,38 +1303,48 @@ class Build {
|
|
|
954
1303
|
await this.handlerManifest();
|
|
955
1304
|
if (!this.isWatch)
|
|
956
1305
|
progress.update(30);
|
|
957
|
-
const
|
|
958
|
-
if (
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
1306
|
+
const isBundle = this.currentConfig.build?.bundle !== false;
|
|
1307
|
+
if (this.currentConfig.script) {
|
|
1308
|
+
if (isBundle) {
|
|
1309
|
+
const rBuild = (await this.createRollup());
|
|
1310
|
+
if (!this.rollupPlugin || !this.outdirs) {
|
|
1311
|
+
throw new Error(`[build addon]: can't resolve rollup instance`);
|
|
1312
|
+
}
|
|
1313
|
+
if (!this.isWatch)
|
|
1314
|
+
progress.update(50);
|
|
1315
|
+
// write script
|
|
1316
|
+
let output = this.currentConfig.script?.main;
|
|
1317
|
+
if (!output)
|
|
1318
|
+
output = 'index.js';
|
|
1319
|
+
if (path__default.extname(output) !== 'js')
|
|
1320
|
+
output =
|
|
1321
|
+
output.slice(0, output.length - path__default.extname(output).length) + '.js';
|
|
1322
|
+
if (this.buildConfig?.outputFilename)
|
|
1323
|
+
output = this.buildConfig.outputFilename;
|
|
1324
|
+
const outputDir = this.buildConfig?.outputDir || 'scripts';
|
|
1325
|
+
await rBuild.write({
|
|
1326
|
+
file: join(path__default.join(this.outdirs.behavior, outputDir), output),
|
|
977
1327
|
format: 'esm',
|
|
978
1328
|
sourcemap: false,
|
|
979
|
-
chunkFileNames: '[name].js',
|
|
980
1329
|
});
|
|
981
|
-
|
|
1330
|
+
}
|
|
1331
|
+
else {
|
|
1332
|
+
// bundle: false – skip rollup, copy source scripts directly
|
|
1333
|
+
const srcScriptDir = path__default.join(this.srcDirs.behavior, 'scripts');
|
|
1334
|
+
const outputDir = this.buildConfig?.outputDir || 'scripts';
|
|
1335
|
+
const outPath = path__default.join(this.outdirs.behavior, outputDir);
|
|
1336
|
+
if (await FileExsit(srcScriptDir)) {
|
|
1337
|
+
await fs.cp(srcScriptDir, outPath, { recursive: true, force: true });
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
982
1341
|
if (!this.isWatch)
|
|
983
1342
|
progress.update(70);
|
|
984
1343
|
if (!this.outdirs || !this.module)
|
|
985
1344
|
throw new Error(`[build addon]: can't resolve outdirs`);
|
|
986
1345
|
await generateRelease({
|
|
987
1346
|
outdirs: this.outdirs,
|
|
988
|
-
module: this.module
|
|
1347
|
+
module: this.module,
|
|
989
1348
|
});
|
|
990
1349
|
if (!this.isWatch)
|
|
991
1350
|
progress.update(80);
|
|
@@ -1011,13 +1370,7 @@ class Build {
|
|
|
1011
1370
|
if (!(await FileExsit(main))) {
|
|
1012
1371
|
throw new Error(`[build addon]: main script ${main} is not exist: can't resolve entry`);
|
|
1013
1372
|
}
|
|
1014
|
-
const plugin = [
|
|
1015
|
-
jsonPlugin(),
|
|
1016
|
-
resolvePlugin({
|
|
1017
|
-
extensions: ['.ts', '.js', '.json'],
|
|
1018
|
-
}),
|
|
1019
|
-
commonjs()
|
|
1020
|
-
];
|
|
1373
|
+
const plugin = [];
|
|
1021
1374
|
const moduleDir = path__default.join(this.baseBuildDir, 'node_modules');
|
|
1022
1375
|
if (!(await FileExsit(moduleDir))) {
|
|
1023
1376
|
throw new Error(`[build addon]: node_modules is not exist in project root: can't resolve node_modules for rollup: ${moduleDir}`);
|
|
@@ -1035,23 +1388,6 @@ class Build {
|
|
|
1035
1388
|
if (this.buildConfig?.rollupPlugins) {
|
|
1036
1389
|
plugin.push(...this.buildConfig.rollupPlugins);
|
|
1037
1390
|
}
|
|
1038
|
-
if (this.currentConfig.script.lang == "ts") {
|
|
1039
|
-
const tsconfigPath = path__default.join(this.baseBuildDir, 'tsconfig.json');
|
|
1040
|
-
if (!(await FileExsit(tsconfigPath))) {
|
|
1041
|
-
throw new Error(`[build addon]: ts-lang: tsconfig.json is not exist in project root: can't resolve tsconfig for rollup: ${tsconfigPath}`);
|
|
1042
|
-
}
|
|
1043
|
-
plugin.push(typescript({
|
|
1044
|
-
sourceMap: false,
|
|
1045
|
-
tsconfig: tsconfigPath,
|
|
1046
|
-
exclude: [
|
|
1047
|
-
this.outdirs.behavior,
|
|
1048
|
-
this.outdirs.resources
|
|
1049
|
-
],
|
|
1050
|
-
include: [
|
|
1051
|
-
this.srcDirs.behavior
|
|
1052
|
-
]
|
|
1053
|
-
}));
|
|
1054
|
-
}
|
|
1055
1391
|
if (this.currentConfig.script?.lang == 'mcx') {
|
|
1056
1392
|
try {
|
|
1057
1393
|
const tsconfigPath = path__default.join(this.baseBuildDir, 'tsconfig.json');
|
|
@@ -1063,38 +1399,50 @@ class Build {
|
|
|
1063
1399
|
tsconfigPath: tsconfigPath,
|
|
1064
1400
|
sourcemap: false,
|
|
1065
1401
|
ts: this.mcxTs,
|
|
1066
|
-
mcxLanguagePlugin: this.mcxLanguagePluginCreator
|
|
1067
1402
|
};
|
|
1068
1403
|
if (this.mcxLanguagePluginCreator) {
|
|
1069
1404
|
pluginConfig.mcxLanguagePlugin = this.mcxLanguagePluginCreator;
|
|
1070
1405
|
}
|
|
1071
|
-
plugin.push(mcxDef.
|
|
1406
|
+
plugin.push(mcxDef.rolldownPlugin(pluginConfig, this.outdirs));
|
|
1072
1407
|
}
|
|
1073
1408
|
catch (err) {
|
|
1074
|
-
throw new Error(`[build addon]: mcx plugin is required but '@mbler/mcx-core' could not be loaded: ${err}
|
|
1409
|
+
throw new Error(`[build addon]: mcx plugin is required but '@mbler/mcx-core' could not be loaded: ${err}`, { cause: err });
|
|
1075
1410
|
}
|
|
1076
1411
|
}
|
|
1077
1412
|
// save plugin array for watcher re-use
|
|
1078
1413
|
this.rollupPlugin = plugin;
|
|
1079
1414
|
const rollupOption = {
|
|
1080
1415
|
input: main,
|
|
1081
|
-
external: [
|
|
1416
|
+
external: [
|
|
1417
|
+
'@minecraft/server',
|
|
1418
|
+
'@minecraft/server-ui',
|
|
1419
|
+
...(this.buildConfig?.rollupExternal ?? []),
|
|
1420
|
+
],
|
|
1082
1421
|
plugins: plugin,
|
|
1083
|
-
|
|
1422
|
+
experimental: {
|
|
1423
|
+
...(this.cacheManager?.shouldUseIncrementalBuild()
|
|
1424
|
+
? { incrementalBuild: true }
|
|
1425
|
+
: {}),
|
|
1426
|
+
},
|
|
1084
1427
|
};
|
|
1085
|
-
if (this.buildConfig?.onWarn)
|
|
1086
|
-
|
|
1087
|
-
|
|
1428
|
+
if (this.buildConfig?.onWarn) {
|
|
1429
|
+
const onWarn = (warning, _defaultHandler) => {
|
|
1430
|
+
const msg = typeof warning === 'string'
|
|
1431
|
+
? warning
|
|
1432
|
+
: warning.message || 'Unknown warning';
|
|
1433
|
+
this.buildConfig?.onWarn?.(this.currentConfig, new Error(msg));
|
|
1088
1434
|
};
|
|
1435
|
+
rollupOption.onwarn = onWarn;
|
|
1436
|
+
}
|
|
1089
1437
|
if (this.buildConfig?.onEnd) {
|
|
1090
1438
|
plugin.push({
|
|
1091
1439
|
name: 'build-end-plugin',
|
|
1092
1440
|
buildEnd: () => {
|
|
1093
1441
|
return this.buildConfig?.onEnd?.(this.currentConfig);
|
|
1094
|
-
}
|
|
1442
|
+
},
|
|
1095
1443
|
});
|
|
1096
1444
|
}
|
|
1097
|
-
return await
|
|
1445
|
+
return await rolldown(rollupOption);
|
|
1098
1446
|
}
|
|
1099
1447
|
/**
|
|
1100
1448
|
* Internal helper invoked by {@link watch}.
|
|
@@ -1105,7 +1453,7 @@ class Build {
|
|
|
1105
1453
|
if (!this.init) {
|
|
1106
1454
|
await this.build();
|
|
1107
1455
|
}
|
|
1108
|
-
this.createWatcher();
|
|
1456
|
+
await this.createWatcher();
|
|
1109
1457
|
// watchers field is populated by createWatcher
|
|
1110
1458
|
}
|
|
1111
1459
|
isParent(parent, dir) {
|
|
@@ -1128,7 +1476,7 @@ class Build {
|
|
|
1128
1476
|
}
|
|
1129
1477
|
return false;
|
|
1130
1478
|
}
|
|
1131
|
-
createRollupWatcher() {
|
|
1479
|
+
async createRollupWatcher() {
|
|
1132
1480
|
if (!this.srcDirs ||
|
|
1133
1481
|
!this.outdirs ||
|
|
1134
1482
|
!this.currentConfig ||
|
|
@@ -1136,24 +1484,31 @@ class Build {
|
|
|
1136
1484
|
throw new Error(`[build addon]: can't first can this method`);
|
|
1137
1485
|
let output = this.currentConfig.script?.main;
|
|
1138
1486
|
if (!output)
|
|
1139
|
-
output =
|
|
1140
|
-
if (path__default.extname(output) !==
|
|
1141
|
-
output =
|
|
1142
|
-
|
|
1487
|
+
output = 'index.js';
|
|
1488
|
+
if (path__default.extname(output) !== 'js')
|
|
1489
|
+
output =
|
|
1490
|
+
output.slice(0, output.length - path__default.extname(output).length) + '.js';
|
|
1491
|
+
if (this.buildConfig?.outputFilename)
|
|
1492
|
+
output = this.buildConfig.outputFilename;
|
|
1493
|
+
const outputDir = this.buildConfig?.outputDir || 'scripts';
|
|
1494
|
+
const rollupWatcher = watch$1({
|
|
1143
1495
|
input: path__default.join(this.srcDirs.behavior, 'scripts', this.currentConfig?.script?.main || ''),
|
|
1144
|
-
external: [
|
|
1496
|
+
external: [
|
|
1497
|
+
'@minecraft/server',
|
|
1498
|
+
'@minecraft/server-ui',
|
|
1499
|
+
...(this.buildConfig?.rollupExternal ?? []),
|
|
1500
|
+
],
|
|
1145
1501
|
plugins: this.rollupPlugin,
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1502
|
+
experimental: {
|
|
1503
|
+
...(this.cacheManager?.shouldUseIncrementalBuild()
|
|
1504
|
+
? { incrementalBuild: true }
|
|
1505
|
+
: {}),
|
|
1506
|
+
},
|
|
1507
|
+
output: {
|
|
1508
|
+
file: join(path__default.join(this.outdirs.behavior, outputDir), output),
|
|
1152
1509
|
format: 'esm',
|
|
1153
|
-
chunkFileNames: '[name].js',
|
|
1154
1510
|
sourcemap: false,
|
|
1155
1511
|
},
|
|
1156
|
-
cache: this.cacheManager?.getWatchCacheOption() ?? true,
|
|
1157
1512
|
watch: {
|
|
1158
1513
|
clearScreen: false,
|
|
1159
1514
|
include: path__default.join(this.srcDirs.behavior, 'scripts/**/*'),
|
|
@@ -1179,28 +1534,32 @@ class Build {
|
|
|
1179
1534
|
else if (event.code === 'END') {
|
|
1180
1535
|
Logger.i('Watcher', `rebuild success`);
|
|
1181
1536
|
}
|
|
1182
|
-
else if (event.code === 'BUNDLE_END')
|
|
1183
|
-
await this.cacheManager?.saveRollupCache(event.result?.cache);
|
|
1184
|
-
}
|
|
1537
|
+
else if (event.code === 'BUNDLE_END') ;
|
|
1185
1538
|
});
|
|
1186
1539
|
return rollupWatcher;
|
|
1187
1540
|
}
|
|
1188
1541
|
async onChange(filePath) {
|
|
1542
|
+
const isBundle = this.currentConfig?.build?.bundle !== false;
|
|
1189
1543
|
if (!this.srcDirs ||
|
|
1190
1544
|
!this.outdirs ||
|
|
1191
1545
|
!this.currentConfig ||
|
|
1192
|
-
!this.rollupPlugin ||
|
|
1546
|
+
(isBundle && !this.rollupPlugin) ||
|
|
1193
1547
|
!this.watchers)
|
|
1194
1548
|
throw new Error(`[build addon]: can't first can this method`);
|
|
1195
|
-
const isConfigChange = path__default.relative(path__default.join(this.baseBuildDir,
|
|
1196
|
-
const
|
|
1549
|
+
const isConfigChange = path__default.relative(path__default.join(this.baseBuildDir, BuildConfig.ConfigFile), filePath) === '';
|
|
1550
|
+
const isPkgChange = path__default.relative(path__default.join(this.baseBuildDir, 'package.json'), filePath) ===
|
|
1551
|
+
'';
|
|
1552
|
+
const isScriptsChange = !isBundle &&
|
|
1553
|
+
this.isParent(path__default.join(this.srcDirs.behavior, 'scripts'), filePath);
|
|
1554
|
+
const isBehaviorChange = this.isParent(this.srcDirs.behavior, filePath) &&
|
|
1555
|
+
!this.isParent(path__default.join(this.srcDirs.behavior, 'scripts'), filePath);
|
|
1197
1556
|
const isResourcesChange = this.isParent(this.srcDirs.resources, filePath);
|
|
1198
|
-
if (isConfigChange) {
|
|
1557
|
+
if (isConfigChange || isPkgChange) {
|
|
1199
1558
|
const oldConfig = this.currentConfig;
|
|
1200
|
-
Logger.i('Watcher', 'detected
|
|
1559
|
+
Logger.i('Watcher', 'detected config change, reload config');
|
|
1201
1560
|
this.currentConfig = await ReadProjectMblerConfig(this.baseBuildDir);
|
|
1202
1561
|
this.buildConfig = this.currentConfig.build || null;
|
|
1203
|
-
this.cacheManager = new BuildCacheManager(this.baseBuildDir, this.buildConfig?.cache, this.isWatch);
|
|
1562
|
+
this.cacheManager = new BuildCacheManager(this.baseBuildDir, this.buildConfig?.cache, this.isWatch, this.buildConfig?.cachePath);
|
|
1204
1563
|
this.loadData();
|
|
1205
1564
|
if (this.isChange(oldConfig, this.currentConfig, [
|
|
1206
1565
|
'name',
|
|
@@ -1210,12 +1569,31 @@ class Build {
|
|
|
1210
1569
|
])) {
|
|
1211
1570
|
await this.handlerManifest();
|
|
1212
1571
|
}
|
|
1213
|
-
if (this.isChange(oldConfig, this.currentConfig, ['script', 'outdir'])) {
|
|
1214
|
-
this.
|
|
1215
|
-
|
|
1216
|
-
|
|
1572
|
+
if (this.isChange(oldConfig, this.currentConfig, ['script', 'outdir', 'build'])) {
|
|
1573
|
+
const newIsBundle = this.currentConfig.build?.bundle !== false;
|
|
1574
|
+
if (newIsBundle && this.watchers.rollup) {
|
|
1575
|
+
this.watchers.rollup.close();
|
|
1576
|
+
await this.createRollup();
|
|
1577
|
+
this.watchers.rollup = await this.createRollupWatcher();
|
|
1578
|
+
}
|
|
1579
|
+
else if (newIsBundle) {
|
|
1580
|
+
await this.createRollup();
|
|
1581
|
+
this.watchers.rollup = await this.createRollupWatcher();
|
|
1582
|
+
}
|
|
1583
|
+
else {
|
|
1584
|
+
if (this.watchers.rollup) {
|
|
1585
|
+
this.watchers.rollup.close();
|
|
1586
|
+
}
|
|
1587
|
+
this.watchers.rollup = null;
|
|
1588
|
+
}
|
|
1217
1589
|
}
|
|
1218
1590
|
}
|
|
1591
|
+
// if bundle: false and a script file changed, copy it directly
|
|
1592
|
+
if (isScriptsChange) {
|
|
1593
|
+
const outputDir = this.buildConfig?.outputDir || 'scripts';
|
|
1594
|
+
const relativePath = path__default.relative(path__default.join(this.srcDirs.behavior, 'scripts'), filePath);
|
|
1595
|
+
await fs.cp(filePath, path__default.join(this.outdirs.behavior, outputDir, relativePath), { recursive: true, force: true });
|
|
1596
|
+
}
|
|
1219
1597
|
// if behavior or resources change, we can just copy the changed file instead of copy all files again.
|
|
1220
1598
|
if (isBehaviorChange || isResourcesChange) {
|
|
1221
1599
|
const handlerBP = async () => {
|
|
@@ -1245,10 +1623,11 @@ class Build {
|
|
|
1245
1623
|
}
|
|
1246
1624
|
showText(`[${chalk.green('mbler')}] ${chalk.bgYellow(`file changed: ${filePath}`)}`);
|
|
1247
1625
|
}
|
|
1248
|
-
createWatcher() {
|
|
1249
|
-
|
|
1626
|
+
async createWatcher() {
|
|
1627
|
+
const isBundle = this.currentConfig?.build?.bundle !== false;
|
|
1628
|
+
if (!this.srcDirs || !this.outdirs || (isBundle && !this.rollupPlugin))
|
|
1250
1629
|
throw new Error(`[build addon]: can't first can this method`);
|
|
1251
|
-
const chokidar = watch$
|
|
1630
|
+
const chokidar = watch$2(this.baseBuildDir, {
|
|
1252
1631
|
ignored: [
|
|
1253
1632
|
this.outdirs.behavior,
|
|
1254
1633
|
this.outdirs.resources,
|
|
@@ -1262,11 +1641,19 @@ class Build {
|
|
|
1262
1641
|
await this.onChange(filePath);
|
|
1263
1642
|
};
|
|
1264
1643
|
chokidar.on('change', onChange);
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1644
|
+
if (isBundle && this.currentConfig?.script) {
|
|
1645
|
+
const rollupWatcher = await this.createRollupWatcher();
|
|
1646
|
+
this.watchers = {
|
|
1647
|
+
chokidar,
|
|
1648
|
+
rollup: rollupWatcher,
|
|
1649
|
+
};
|
|
1650
|
+
}
|
|
1651
|
+
else {
|
|
1652
|
+
this.watchers = {
|
|
1653
|
+
chokidar,
|
|
1654
|
+
rollup: null,
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1270
1657
|
}
|
|
1271
1658
|
async handlerManifest() {
|
|
1272
1659
|
if (!this.currentConfig || !this.outdirs || !this.srcDirs || !this.module)
|
|
@@ -1301,7 +1688,7 @@ class Build {
|
|
|
1301
1688
|
const json = JSON.parse(content);
|
|
1302
1689
|
otherManifestOption.behavior = json;
|
|
1303
1690
|
}
|
|
1304
|
-
catch (
|
|
1691
|
+
catch (_err) {
|
|
1305
1692
|
Logger.w('Build', 'invalid manifest.json in behavior');
|
|
1306
1693
|
}
|
|
1307
1694
|
}
|
|
@@ -1315,7 +1702,7 @@ class Build {
|
|
|
1315
1702
|
const json = JSON.parse(content);
|
|
1316
1703
|
otherManifestOption.resources = json;
|
|
1317
1704
|
}
|
|
1318
|
-
catch (
|
|
1705
|
+
catch (_err) {
|
|
1319
1706
|
Logger.w('Build', 'invalid manifest.json in resources');
|
|
1320
1707
|
}
|
|
1321
1708
|
}
|
|
@@ -1441,5 +1828,5 @@ function watch(cliParam, work) {
|
|
|
1441
1828
|
});
|
|
1442
1829
|
}
|
|
1443
1830
|
|
|
1444
|
-
export { Build, runTSC as McxTsc, build, watch };
|
|
1831
|
+
export { Build, runTSC as McxTsc, Sapi, build, watch };
|
|
1445
1832
|
//# sourceMappingURL=build.esm.mjs.map
|