jsmdcui 0.10.1 → 0.11.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/CHANGELOG.md +73 -0
- package/README.md +88 -29
- package/package.json +1 -1
- package/runmd.mjs +51 -7
- package/runtime/help/help.md +88 -29
- package/runtime/jsplugins/example/example.js +3 -1
- package/single-exe/README.md +82 -25
- package/single-exe/README.md-rpc.js +623 -0
- package/single-exe/README.md-server.js +127 -0
- package/single-exe/README.md.back.js +2 -0
- package/single-exe/README.md.front.js +27 -0
- package/single-exe/README.md.html +325 -0
- package/single-exe/compiled.js +59 -1
- package/src/build-args.js +40 -0
- package/src/index.js +237 -22
- package/src/plugins/js-bridge.js +5 -0
- package/tests/compiled-runtime.test.js +132 -1
- package/tests/demo.test.js +136 -1
- package/tests/js-plugin-prompts.test.js +30 -0
- package/tests/wui-responsive-images.test.js +21 -2
- package/tests/wui.test.js +31 -0
package/src/index.js
CHANGED
|
@@ -128,7 +128,8 @@ import { isHex3Encoding, isMdcuiEncoding } from "./runtime/encodings.js";
|
|
|
128
128
|
import { createInterface } from "node:readline/promises";
|
|
129
129
|
|
|
130
130
|
import pkg from "../package.json" with { type: "json" };
|
|
131
|
-
import { REPO_ROOT,IS_COMPILED, buildExecutable,buildEarlyExit } from "../single-exe/compiled.js";
|
|
131
|
+
import { REPO_ROOT,IS_COMPILED, buildExecutable,buildEarlyExit,stringifyNonPrimitiveDefineValues } from "../single-exe/compiled.js";
|
|
132
|
+
import { expandBuildMdAliases } from "./build-args.js";
|
|
132
133
|
|
|
133
134
|
|
|
134
135
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -186,6 +187,7 @@ const MDCUI_DEFAULT_DEMO_ENABLED = typeof MDCUI_DEFAULT_DEMO !== "undefined";
|
|
|
186
187
|
const MDCUI_DEFAULT_DEMO_WUI_ENABLED = typeof MDCUI_DEFAULT_DEMO_WUI !== "undefined";
|
|
187
188
|
const MDCUI_OVERWRITE_DEMO_ENABLED = typeof MDCUI_OVERWRITE_DEMO !== "undefined";
|
|
188
189
|
let defaultEdit = false;
|
|
190
|
+
let noRuntimeArgs = false;
|
|
189
191
|
const decoder = new TextDecoder();
|
|
190
192
|
let _activeTtyStream = null; // set in App.start() for use by the global error handler
|
|
191
193
|
|
|
@@ -1173,9 +1175,15 @@ function parseArgs(argv) {
|
|
|
1173
1175
|
}
|
|
1174
1176
|
else if (arg.startsWith("--demo-")) {
|
|
1175
1177
|
const name = arg.slice("--demo-".length);
|
|
1176
|
-
flags.demo =
|
|
1178
|
+
flags.demo = isValidDemoName(name)
|
|
1177
1179
|
? { option: arg, filename: `${name}.md`, asset: `demos/${name}.md` }
|
|
1178
|
-
: {
|
|
1180
|
+
: {
|
|
1181
|
+
option: arg,
|
|
1182
|
+
error:
|
|
1183
|
+
"demo filename must start with a Unicode letter or number "
|
|
1184
|
+
+ "and contain only Unicode letters, numbers, dots, underscores, "
|
|
1185
|
+
+ "or hyphens; whitespace is not allowed",
|
|
1186
|
+
};
|
|
1179
1187
|
}
|
|
1180
1188
|
else if (arg === "--allow-url") flags.allowUrl = true;
|
|
1181
1189
|
else if (arg === "--kitty") flags.kittyMode = "extended";
|
|
@@ -1206,6 +1214,17 @@ function parseArgs(argv) {
|
|
|
1206
1214
|
return { flags, files };
|
|
1207
1215
|
}
|
|
1208
1216
|
|
|
1217
|
+
function isValidDemoName(name) {
|
|
1218
|
+
return /^[\p{L}\p{N}][\p{L}\p{N}\p{M}._-]*$/u.test(String(name));
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
function demoNameFromMarkdownBasename(filename) {
|
|
1222
|
+
const value = String(filename);
|
|
1223
|
+
if (!value.endsWith(".md")) return "";
|
|
1224
|
+
const name = value.slice(0, -".md".length);
|
|
1225
|
+
return isValidDemoName(name) ? name : "";
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1209
1228
|
function usage() {
|
|
1210
1229
|
return [
|
|
1211
1230
|
`Usage:
|
|
@@ -1331,14 +1350,20 @@ Remote Markdown:
|
|
|
1331
1350
|
Download HTTP(S) Markdown and, with Kitty mode, its HTTP(S) images; allow its code to run
|
|
1332
1351
|
|
|
1333
1352
|
Experimental single-exe:
|
|
1353
|
+
--build-md-exe <file.md> [BUN_ARGS...]
|
|
1354
|
+
Build with <file.md> embedded as global.MDCUI_MAIN & exit
|
|
1355
|
+
--build-md-for <platform> <file.md> [BUN_ARGS...]
|
|
1356
|
+
Build for <platform> with <file.md> embedded & exit
|
|
1357
|
+
|
|
1334
1358
|
--build-exe [BUN_ARGS...]
|
|
1335
1359
|
Build a Bun single-file executable & exit
|
|
1336
1360
|
--build-for <target> [BUN_ARGS...]
|
|
1337
1361
|
Build a Bun single-file executable for target & exit
|
|
1338
1362
|
|
|
1339
1363
|
[BUN_ARGS...]
|
|
1340
|
-
--define
|
|
1341
|
-
|
|
1364
|
+
--define MDCUI_OVERWRITE_DEMO=1
|
|
1365
|
+
--define global.MDCUI_MAIN=myapp.md
|
|
1366
|
+
More info in --readme
|
|
1342
1367
|
https://bun.com/docs/bundler/executables
|
|
1343
1368
|
`
|
|
1344
1369
|
].join("\n");
|
|
@@ -1400,6 +1425,7 @@ class BufferModel {
|
|
|
1400
1425
|
this._mdcuiFenceEvents = isMdcuiEncoding(this.encoding) ? fenceEventMap(sourceText ?? tuiSourceText ?? text) : new Map();
|
|
1401
1426
|
this._mdcuiImages = isMdcuiEncoding(this.encoding) ? (mdcuiImages ?? []) : [];
|
|
1402
1427
|
this._mdcuiRenderWidth = Math.trunc(Number(mdcuiRenderWidth) || 0);
|
|
1428
|
+
this._useBundledMdcuiModules = false;
|
|
1403
1429
|
this.cursor = { x: 0, y: 0 };
|
|
1404
1430
|
this.scroll = { x: 0, y: 0, row: 0 };
|
|
1405
1431
|
this._modified = false;
|
|
@@ -4540,7 +4566,10 @@ class App {
|
|
|
4540
4566
|
) return false;
|
|
4541
4567
|
|
|
4542
4568
|
const frontPath = `${buf.path}.front.js`;
|
|
4543
|
-
|
|
4569
|
+
const useBundledMdcuiModules = Boolean(
|
|
4570
|
+
global.MDCUI_MAIN && buf._useBundledMdcuiModules,
|
|
4571
|
+
);
|
|
4572
|
+
if (!useBundledMdcuiModules && !existsSync(frontPath)) return false;
|
|
4544
4573
|
try {
|
|
4545
4574
|
const selection = globalThis.$?.(`${declaration.tag}#${id}`);
|
|
4546
4575
|
const target = {
|
|
@@ -4555,8 +4584,12 @@ class App {
|
|
|
4555
4584
|
});
|
|
4556
4585
|
const event = tuiKeyEventForFront(inputEvent, target, eventName);
|
|
4557
4586
|
const [{ evalFront }, frontMod] = await Promise.all([
|
|
4558
|
-
|
|
4559
|
-
|
|
4587
|
+
useBundledMdcuiModules
|
|
4588
|
+
? import(global.MDCUI_MAIN + "-rpc.js")
|
|
4589
|
+
: import("./cui/rpc.mjs"),
|
|
4590
|
+
useBundledMdcuiModules
|
|
4591
|
+
? import(global.MDCUI_MAIN + ".front.js")
|
|
4592
|
+
: import(localModuleUrl(frontPath)),
|
|
4560
4593
|
]);
|
|
4561
4594
|
const result = await evalFront(frontMod, code, { event });
|
|
4562
4595
|
if (result && typeof result === "object" && result.ok === false) {
|
|
@@ -4591,9 +4624,16 @@ class App {
|
|
|
4591
4624
|
{ // defaultCallback
|
|
4592
4625
|
if (payload.link && /^javascript:/i.test(payload.link) && buf?.path && !isHttpUrl(buf.path)) {
|
|
4593
4626
|
try {
|
|
4627
|
+
const useBundledMdcuiModules = Boolean(
|
|
4628
|
+
global.MDCUI_MAIN && buf._useBundledMdcuiModules,
|
|
4629
|
+
);
|
|
4594
4630
|
const [{ evalFront }, frontMod] = await Promise.all([
|
|
4595
|
-
|
|
4596
|
-
|
|
4631
|
+
useBundledMdcuiModules
|
|
4632
|
+
? import(global.MDCUI_MAIN + "-rpc.js")
|
|
4633
|
+
: import("./cui/rpc.mjs"),
|
|
4634
|
+
useBundledMdcuiModules
|
|
4635
|
+
? import(global.MDCUI_MAIN + ".front.js")
|
|
4636
|
+
: import(localModuleUrl(`${buf.path}.front.js`)),
|
|
4597
4637
|
]);
|
|
4598
4638
|
const result = await evalFront(frontMod, payload.link);
|
|
4599
4639
|
if (result && typeof result === "object" && result.ok === false) {
|
|
@@ -4991,7 +5031,7 @@ class App {
|
|
|
4991
5031
|
const name = buf?.name ?? "No name";
|
|
4992
5032
|
const filename = /^[^\s"'\\]+$/.test(name) ? name : JSON.stringify(name);
|
|
4993
5033
|
this.openCommandMode(`save ${filename}`);
|
|
4994
|
-
break;
|
|
5034
|
+
break; //"
|
|
4995
5035
|
}
|
|
4996
5036
|
case "row":
|
|
4997
5037
|
if (isTerm) {
|
|
@@ -5481,10 +5521,18 @@ class App {
|
|
|
5481
5521
|
const frontPath = buffer.path && !isHttpUrl(buffer.path)
|
|
5482
5522
|
? `${buffer.path}.front.js`
|
|
5483
5523
|
: "";
|
|
5484
|
-
|
|
5524
|
+
const useBundledMdcuiModules = Boolean(
|
|
5525
|
+
global.MDCUI_MAIN && buffer._useBundledMdcuiModules,
|
|
5526
|
+
);
|
|
5527
|
+
if (
|
|
5528
|
+
!useBundledMdcuiModules
|
|
5529
|
+
&& (!frontPath || !existsSync(frontPath))
|
|
5530
|
+
) return;
|
|
5485
5531
|
|
|
5486
5532
|
try {
|
|
5487
|
-
const frontMod =
|
|
5533
|
+
const frontMod = useBundledMdcuiModules
|
|
5534
|
+
? await import(global.MDCUI_MAIN + ".front.js")
|
|
5535
|
+
: await import(localModuleUrl(frontPath));
|
|
5488
5536
|
if (typeof frontMod.onMdcuiExit !== "function") return;
|
|
5489
5537
|
await frontMod.onMdcuiExit({
|
|
5490
5538
|
reason,
|
|
@@ -7021,6 +7069,11 @@ function makeBufferAdapter(buffer) {
|
|
|
7021
7069
|
get Name() { return buffer.Name ?? buffer.name ?? ""; },
|
|
7022
7070
|
get Modified() { return buffer.modified ?? false; },
|
|
7023
7071
|
get Settings() { return buffer.Settings; },
|
|
7072
|
+
get MdcuiModuleSource() {
|
|
7073
|
+
return global.MDCUI_MAIN && buffer._useBundledMdcuiModules
|
|
7074
|
+
? "embedded"
|
|
7075
|
+
: "external";
|
|
7076
|
+
},
|
|
7024
7077
|
Line: (...args) => buffer.Line(Number(lastArg(args))),
|
|
7025
7078
|
Insert: (...args) => insertAtLoc(buffer, decodeLoc(args.at(-2)), String(args.at(-1))),
|
|
7026
7079
|
Replace: (...args) => replaceAtLocs(buffer, decodeLoc(args.at(-3)), decodeLoc(args.at(-2)), String(args.at(-1))),
|
|
@@ -8137,11 +8190,11 @@ function printDemoList() {
|
|
|
8137
8190
|
}
|
|
8138
8191
|
|
|
8139
8192
|
async function prepareDemo(flags, rawFiles) {
|
|
8140
|
-
if (!flags.demo) return true;
|
|
8193
|
+
if (!flags.demo) return { ok: true };
|
|
8141
8194
|
if (flags.demo.error) {
|
|
8142
8195
|
console.error(`Invalid demo option ${flags.demo.option}: ${flags.demo.error}`);
|
|
8143
8196
|
process.exitCode = 2;
|
|
8144
|
-
return false;
|
|
8197
|
+
return { ok: false };
|
|
8145
8198
|
}
|
|
8146
8199
|
let demoSource;
|
|
8147
8200
|
try {
|
|
@@ -8149,29 +8202,170 @@ async function prepareDemo(flags, rawFiles) {
|
|
|
8149
8202
|
} catch {
|
|
8150
8203
|
console.error(`Unknown demo ${flags.demo.option}: ${flags.demo.asset} was not found`);
|
|
8151
8204
|
process.exitCode = 2;
|
|
8152
|
-
return false;
|
|
8205
|
+
return { ok: false };
|
|
8153
8206
|
}
|
|
8207
|
+
|
|
8154
8208
|
const demoPath = resolve(flags.demo.filename);
|
|
8155
|
-
|
|
8209
|
+
const demoFile = Bun.file(demoPath);
|
|
8210
|
+
const demoExists = await demoFile.exists();
|
|
8211
|
+
const writeBundledContent = flags.overwriteDemo || !demoExists;
|
|
8212
|
+
const bundledByteLength = Buffer.byteLength(demoSource);
|
|
8213
|
+
const demoByteLength = writeBundledContent
|
|
8214
|
+
? bundledByteLength
|
|
8215
|
+
: demoFile.size;
|
|
8216
|
+
const configuredMainBase = String(
|
|
8217
|
+
global.MDCUI_MAIN_BASE
|
|
8218
|
+
|| (global.MDCUI_MAIN ? basename(String(global.MDCUI_MAIN)) : ""),
|
|
8219
|
+
);
|
|
8220
|
+
const isConfiguredMainDemo = Boolean(
|
|
8221
|
+
global.MDCUI_MAIN
|
|
8222
|
+
&& configuredMainBase
|
|
8223
|
+
&& basename(demoPath) === configuredMainBase,
|
|
8224
|
+
);
|
|
8225
|
+
|
|
8226
|
+
if (writeBundledContent) {
|
|
8156
8227
|
await Bun.write(demoPath, demoSource);
|
|
8228
|
+
} else if (isConfiguredMainDemo && demoByteLength !== bundledByteLength) {
|
|
8229
|
+
console.error(
|
|
8230
|
+
`[mdcui] ${demoPath} differs from the bundled demo `
|
|
8231
|
+
+ `(${demoByteLength} bytes vs ${bundledByteLength} bytes). `
|
|
8232
|
+
+ "The edited demo may not work correctly if it imports companion modules "
|
|
8233
|
+
+ "instead of keeping all application code in the Markdown file.",
|
|
8234
|
+
);
|
|
8157
8235
|
}
|
|
8236
|
+
|
|
8158
8237
|
rawFiles.splice(0, rawFiles.length, demoPath);
|
|
8159
|
-
return
|
|
8238
|
+
return {
|
|
8239
|
+
ok: true,
|
|
8240
|
+
path: demoPath,
|
|
8241
|
+
useBundledModules: isConfiguredMainDemo
|
|
8242
|
+
&& demoByteLength === bundledByteLength,
|
|
8243
|
+
};
|
|
8244
|
+
}
|
|
8245
|
+
|
|
8246
|
+
function stringDefineFromArgv(argv, name) {
|
|
8247
|
+
const prefix = `${name}=`;
|
|
8248
|
+
for (let i = 0; i < argv.length; i++) {
|
|
8249
|
+
let definition = "";
|
|
8250
|
+
if (argv[i] === "--define") definition = argv[i + 1] ?? "";
|
|
8251
|
+
else if (argv[i].startsWith("--define="))
|
|
8252
|
+
definition = argv[i].slice("--define=".length);
|
|
8253
|
+
if (!definition.startsWith(prefix)) continue;
|
|
8254
|
+
try {
|
|
8255
|
+
const value = JSON.parse(definition.slice(prefix.length));
|
|
8256
|
+
return typeof value === "string" ? value : "";
|
|
8257
|
+
} catch {
|
|
8258
|
+
return "";
|
|
8259
|
+
}
|
|
8260
|
+
}
|
|
8261
|
+
return "";
|
|
8160
8262
|
}
|
|
8161
8263
|
|
|
8162
8264
|
async function main() {
|
|
8163
8265
|
addCheckpoint("Argument Parsing");
|
|
8164
|
-
|
|
8266
|
+
|
|
8267
|
+
expandBuildMdAliases(process.argv);
|
|
8268
|
+
stringifyNonPrimitiveDefineValues(process.argv, "global.MDCUI_MAIN");
|
|
8269
|
+
const argvMdcuiMain = stringDefineFromArgv(
|
|
8270
|
+
process.argv,
|
|
8271
|
+
"global.MDCUI_MAIN",
|
|
8272
|
+
);
|
|
8273
|
+
let sourceMdcuiMain = "";
|
|
8274
|
+
if (IS_COMPILED) {
|
|
8275
|
+
sourceMdcuiMain = "";
|
|
8276
|
+
} else {
|
|
8277
|
+
sourceMdcuiMain = String(argvMdcuiMain || global.MDCUI_MAIN || "");
|
|
8278
|
+
}
|
|
8279
|
+
|
|
8280
|
+
if (sourceMdcuiMain) {
|
|
8281
|
+
const mdcuiMain = resolve(sourceMdcuiMain);
|
|
8282
|
+
const mdcuiMainBase = basename(mdcuiMain);
|
|
8283
|
+
const mdcuiMainDemoName = demoNameFromMarkdownBasename(mdcuiMainBase);
|
|
8284
|
+
if (!mdcuiMainDemoName) {
|
|
8285
|
+
throw new Error(
|
|
8286
|
+
"MDCUI_MAIN basename must end with lowercase .md, start with a "
|
|
8287
|
+
+ "Unicode letter or number, and contain no whitespace; only Unicode "
|
|
8288
|
+
+ "letters, numbers, dots, underscores, and hyphens are allowed",
|
|
8289
|
+
);
|
|
8290
|
+
}
|
|
8291
|
+
const runmd = await import("../runmd.mjs");
|
|
8292
|
+
const mdcuiMainFile = Bun.file(mdcuiMain);
|
|
8293
|
+
if (!(await mdcuiMainFile.exists())) {
|
|
8294
|
+
throw new Error(`MDCUI_MAIN file not found: ${mdcuiMain}`);
|
|
8295
|
+
}
|
|
8296
|
+
let markdown = await mdcuiMainFile.text();
|
|
8297
|
+
const demoPath = join(REPO_ROOT, "demos", mdcuiMainBase);
|
|
8298
|
+
if (resolve(mdcuiMain) !== resolve(demoPath)) {
|
|
8299
|
+
await Bun.write(demoPath, markdown);
|
|
8300
|
+
}
|
|
8301
|
+
markdown = await runmd.extractJs(markdown, mdcuiMain, {
|
|
8302
|
+
bundling: true,
|
|
8303
|
+
});
|
|
8304
|
+
await runmd.createWui(markdown, mdcuiMain, {
|
|
8305
|
+
bundling: true,
|
|
8306
|
+
});
|
|
8307
|
+
|
|
8308
|
+
if (
|
|
8309
|
+
process.argv.includes("--build-for")
|
|
8310
|
+
|| process.argv.includes("--build-exe")
|
|
8311
|
+
) {
|
|
8312
|
+
if (argvMdcuiMain) {
|
|
8313
|
+
const normalizedDefine =
|
|
8314
|
+
`global.MDCUI_MAIN=${JSON.stringify(mdcuiMain)}`;
|
|
8315
|
+
for (let i = 0; i < process.argv.length; i++) {
|
|
8316
|
+
if (
|
|
8317
|
+
process.argv[i] === "--define"
|
|
8318
|
+
&& process.argv[i + 1]?.startsWith("global.MDCUI_MAIN=")
|
|
8319
|
+
) {
|
|
8320
|
+
process.argv[i + 1] = normalizedDefine;
|
|
8321
|
+
} else if (
|
|
8322
|
+
process.argv[i].startsWith("--define=global.MDCUI_MAIN=")
|
|
8323
|
+
) {
|
|
8324
|
+
process.argv[i] = `--define=${normalizedDefine}`;
|
|
8325
|
+
}
|
|
8326
|
+
}
|
|
8327
|
+
} else {
|
|
8328
|
+
process.argv.push(
|
|
8329
|
+
"--define",
|
|
8330
|
+
`global.MDCUI_MAIN=${JSON.stringify(mdcuiMain)}`,
|
|
8331
|
+
);
|
|
8332
|
+
}
|
|
8333
|
+
process.argv.push(
|
|
8334
|
+
"--define",
|
|
8335
|
+
`global.MDCUI_MAIN_BASE=${JSON.stringify(mdcuiMainBase)}`,
|
|
8336
|
+
);
|
|
8337
|
+
}
|
|
8338
|
+
}
|
|
8339
|
+
|
|
8165
8340
|
await buildEarlyExit(null,DEFAULT_BUILD_OUTFILE)
|
|
8166
8341
|
defaultEdit = await Bun.file(join(REPO_ROOT, "src", "MDCUI_DEFAULT_EDIT")).exists();
|
|
8167
8342
|
|
|
8168
8343
|
const runtimeArgs = process.argv.slice(2);
|
|
8169
|
-
|
|
8344
|
+
noRuntimeArgs = runtimeArgs.length === 0;
|
|
8170
8345
|
if (MDCUI_DEFAULT_EDIT_ENABLED) runtimeArgs.unshift("--edit");
|
|
8171
8346
|
if (noRuntimeArgs && MDCUI_DEFAULT_DEMO_ENABLED) runtimeArgs.push("--demo");
|
|
8172
8347
|
if (noRuntimeArgs && MDCUI_DEFAULT_DEMO_WUI_ENABLED) runtimeArgs.push("--wui");
|
|
8348
|
+
if (
|
|
8349
|
+
noRuntimeArgs
|
|
8350
|
+
&& (global.MDCUI_MAIN || global.MDCUI_MAIN_BASE)
|
|
8351
|
+
) {
|
|
8352
|
+
const mdcuiMainBase = String(
|
|
8353
|
+
global.MDCUI_MAIN_BASE || basename(String(global.MDCUI_MAIN)),
|
|
8354
|
+
);
|
|
8355
|
+
const demoName = demoNameFromMarkdownBasename(mdcuiMainBase);
|
|
8356
|
+
if (!demoName) {
|
|
8357
|
+
console.error(
|
|
8358
|
+
"Invalid MDCUI_MAIN_BASE: expected a lowercase .md basename with "
|
|
8359
|
+
+ "Unicode letters or numbers and no whitespace",
|
|
8360
|
+
);
|
|
8361
|
+
process.exitCode = 2;
|
|
8362
|
+
return;
|
|
8363
|
+
}
|
|
8364
|
+
runtimeArgs.push(`--demo-${demoName}`);
|
|
8365
|
+
}
|
|
8173
8366
|
if (MDCUI_OVERWRITE_DEMO_ENABLED) runtimeArgs.push("--overwrite-demo");
|
|
8174
8367
|
const { flags, files: rawFiles } = parseArgs(runtimeArgs);
|
|
8368
|
+
let demoPreparation = null;
|
|
8175
8369
|
kittyImageMode = flags.kittyMode;
|
|
8176
8370
|
allowRemoteKittyImages = flags.allowUrl;
|
|
8177
8371
|
|
|
@@ -8195,6 +8389,14 @@ async function main() {
|
|
|
8195
8389
|
console.log(" MDCUI_DEFAULT_DEMO:", MDCUI_DEFAULT_DEMO_ENABLED ? "enabled" : "disabled");
|
|
8196
8390
|
console.log(" MDCUI_DEFAULT_DEMO_WUI:", MDCUI_DEFAULT_DEMO_WUI_ENABLED ? "enabled" : "disabled");
|
|
8197
8391
|
console.log(" MDCUI_OVERWRITE_DEMO:", MDCUI_OVERWRITE_DEMO_ENABLED ? "enabled" : "disabled");
|
|
8392
|
+
console.log(
|
|
8393
|
+
" global.MDCUI_MAIN:",
|
|
8394
|
+
String(global.MDCUI_MAIN || "") || "not set",
|
|
8395
|
+
);
|
|
8396
|
+
console.log(
|
|
8397
|
+
" global.MDCUI_MAIN_BASE:",
|
|
8398
|
+
String(global.MDCUI_MAIN_BASE || "") || "not set",
|
|
8399
|
+
);
|
|
8198
8400
|
const clipboard = new ClipboardManager();
|
|
8199
8401
|
let osc52Available = false;
|
|
8200
8402
|
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
@@ -8210,12 +8412,14 @@ async function main() {
|
|
|
8210
8412
|
return;
|
|
8211
8413
|
}
|
|
8212
8414
|
if (flags.wui) {
|
|
8213
|
-
|
|
8415
|
+
demoPreparation = await prepareDemo(flags, rawFiles);
|
|
8416
|
+
if (!demoPreparation.ok) return;
|
|
8214
8417
|
const runmd = await import("../runmd.mjs");
|
|
8215
8418
|
await runmd.main(30, {
|
|
8216
8419
|
mdpath: rawFiles[0] ?? null,
|
|
8217
8420
|
overwriteDemo: flags.overwriteDemo && rawFiles.length === 0,
|
|
8218
8421
|
printUi: flags.printUi,
|
|
8422
|
+
useBundledMdcuiServer: demoPreparation.useBundledModules,
|
|
8219
8423
|
});
|
|
8220
8424
|
return;
|
|
8221
8425
|
}
|
|
@@ -8263,7 +8467,8 @@ async function main() {
|
|
|
8263
8467
|
return;
|
|
8264
8468
|
}
|
|
8265
8469
|
if (flags.demo) {
|
|
8266
|
-
|
|
8470
|
+
demoPreparation = await prepareDemo(flags, rawFiles);
|
|
8471
|
+
if (!demoPreparation.ok) return;
|
|
8267
8472
|
}
|
|
8268
8473
|
if (flags.options) {
|
|
8269
8474
|
for (const [key, value] of Object.entries(defaultAllSettings()).sort(([a], [b]) => a.localeCompare(b))) {
|
|
@@ -8411,6 +8616,16 @@ async function main() {
|
|
|
8411
8616
|
const buffers = await loadBuffers(files.map((file) =>
|
|
8412
8617
|
isHttpUrl(file) ? file : resolve(file)
|
|
8413
8618
|
), command);
|
|
8619
|
+
if (demoPreparation?.useBundledModules) {
|
|
8620
|
+
const bundledDemoBuffer = buffers.find((buffer) =>
|
|
8621
|
+
buffer.path
|
|
8622
|
+
&& !isHttpUrl(buffer.path)
|
|
8623
|
+
&& resolve(buffer.path) === demoPreparation.path
|
|
8624
|
+
);
|
|
8625
|
+
if (bundledDemoBuffer) {
|
|
8626
|
+
bundledDemoBuffer._useBundledMdcuiModules = true;
|
|
8627
|
+
}
|
|
8628
|
+
}
|
|
8414
8629
|
|
|
8415
8630
|
let historyPromise = Promise.resolve();
|
|
8416
8631
|
if (config.getGlobalOption("savehistory") !== false) {
|
package/src/plugins/js-bridge.js
CHANGED
|
@@ -1622,6 +1622,11 @@ function _makeBufAPI(buffer) {
|
|
|
1622
1622
|
get Type() { return buffer.Type; },
|
|
1623
1623
|
get Settings() { return buffer.Settings; },
|
|
1624
1624
|
get Modified() { return buffer.modified; },
|
|
1625
|
+
get MdcuiModuleSource() {
|
|
1626
|
+
return global.MDCUI_MAIN && buffer._useBundledMdcuiModules
|
|
1627
|
+
? "embedded"
|
|
1628
|
+
: "external";
|
|
1629
|
+
},
|
|
1625
1630
|
|
|
1626
1631
|
Line: (n) => buffer.Line(n),
|
|
1627
1632
|
LinesNum: () => buffer.LinesNum(),
|
|
@@ -1,8 +1,139 @@
|
|
|
1
1
|
import { expect, test } from "bun:test";
|
|
2
|
-
import {
|
|
2
|
+
import { expandBuildMdAliases } from "../src/build-args.js";
|
|
3
|
+
import {
|
|
4
|
+
isCompiledBinary as isSingleExeCompiled,
|
|
5
|
+
stringifyNonPrimitiveDefineValues,
|
|
6
|
+
} from "../single-exe/compiled.js";
|
|
3
7
|
|
|
4
8
|
test("single-exe recognizes Bun compiled virtual paths", () => {
|
|
5
9
|
expect(isSingleExeCompiled(["bun", "/$bunfs/root/app.js"])).toBe(true);
|
|
6
10
|
expect(isSingleExeCompiled(["bun", "B:/~BUN/root/app.js"])).toBe(true);
|
|
7
11
|
expect(isSingleExeCompiled(["bun", "/project/src/index.js"])).toBe(false);
|
|
8
12
|
});
|
|
13
|
+
|
|
14
|
+
test("--build-md-exe expands before the existing build flow", () => {
|
|
15
|
+
const argv = [
|
|
16
|
+
"bun",
|
|
17
|
+
"src/index.js",
|
|
18
|
+
"--build-md-exe",
|
|
19
|
+
"../中文工具.md",
|
|
20
|
+
"--sourcemap",
|
|
21
|
+
];
|
|
22
|
+
expect(expandBuildMdAliases(argv)).toBe(true);
|
|
23
|
+
expect(argv).toEqual([
|
|
24
|
+
"bun",
|
|
25
|
+
"src/index.js",
|
|
26
|
+
"--build-exe",
|
|
27
|
+
"--define",
|
|
28
|
+
"global.MDCUI_MAIN=../中文工具.md",
|
|
29
|
+
"--sourcemap",
|
|
30
|
+
]);
|
|
31
|
+
expect(expandBuildMdAliases(argv)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("--build-md-exe requires a Markdown path", () => {
|
|
35
|
+
expect(() => expandBuildMdAliases(["bun", "index.js", "--build-md-exe"]))
|
|
36
|
+
.toThrow("Missing Markdown path for --build-md-exe");
|
|
37
|
+
expect(() => expandBuildMdAliases([
|
|
38
|
+
"bun",
|
|
39
|
+
"index.js",
|
|
40
|
+
"--build-md-exe",
|
|
41
|
+
"--sourcemap",
|
|
42
|
+
])).toThrow("Missing Markdown path for --build-md-exe");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("--build-md-for expands before the existing cross-build flow", () => {
|
|
46
|
+
const argv = [
|
|
47
|
+
"bun",
|
|
48
|
+
"src/index.js",
|
|
49
|
+
"--build-md-for",
|
|
50
|
+
"bun-linux-x64",
|
|
51
|
+
"../中文工具.md",
|
|
52
|
+
"--sourcemap",
|
|
53
|
+
];
|
|
54
|
+
expect(expandBuildMdAliases(argv)).toBe(true);
|
|
55
|
+
expect(argv).toEqual([
|
|
56
|
+
"bun",
|
|
57
|
+
"src/index.js",
|
|
58
|
+
"--build-for",
|
|
59
|
+
"bun-linux-x64",
|
|
60
|
+
"--define",
|
|
61
|
+
"global.MDCUI_MAIN=../中文工具.md",
|
|
62
|
+
"--sourcemap",
|
|
63
|
+
]);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("--build-md-for requires a platform and Markdown path", () => {
|
|
67
|
+
expect(() => expandBuildMdAliases(["bun", "index.js", "--build-md-for"]))
|
|
68
|
+
.toThrow("Missing platform for --build-md-for");
|
|
69
|
+
expect(() => expandBuildMdAliases([
|
|
70
|
+
"bun",
|
|
71
|
+
"index.js",
|
|
72
|
+
"--build-md-for",
|
|
73
|
+
"bun-linux-x64",
|
|
74
|
+
])).toThrow("Missing Markdown path for --build-md-for");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("non-primitive MDCUI_MAIN define values become strings", () => {
|
|
78
|
+
const split = [
|
|
79
|
+
"bun",
|
|
80
|
+
"src/index.js",
|
|
81
|
+
"--build-exe",
|
|
82
|
+
"--define",
|
|
83
|
+
"global.MDCUI_MAIN=../中文=工具.md",
|
|
84
|
+
];
|
|
85
|
+
expect(
|
|
86
|
+
stringifyNonPrimitiveDefineValues(split, "global.MDCUI_MAIN"),
|
|
87
|
+
).toBe(split);
|
|
88
|
+
expect(split.at(-1)).toBe(
|
|
89
|
+
'global.MDCUI_MAIN="../中文=工具.md"',
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const inline = [
|
|
93
|
+
"--define=global.MDCUI_MAIN=../m.md",
|
|
94
|
+
"--define",
|
|
95
|
+
"OTHER=../other.md",
|
|
96
|
+
"--define",
|
|
97
|
+
"global.MDCUI_MAIN_BASE=m.md",
|
|
98
|
+
];
|
|
99
|
+
stringifyNonPrimitiveDefineValues(inline, "global.MDCUI_MAIN");
|
|
100
|
+
expect(inline).toEqual([
|
|
101
|
+
'--define=global.MDCUI_MAIN="../m.md"',
|
|
102
|
+
"--define",
|
|
103
|
+
"OTHER=../other.md",
|
|
104
|
+
"--define",
|
|
105
|
+
"global.MDCUI_MAIN_BASE=m.md",
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
for (const source of ["", "[]", "{}", "makePath()"]) {
|
|
109
|
+
const argv = ["--define", `global.MDCUI_MAIN=${source}`];
|
|
110
|
+
stringifyNonPrimitiveDefineValues(argv, "global.MDCUI_MAIN");
|
|
111
|
+
expect(argv[1]).toBe(
|
|
112
|
+
`global.MDCUI_MAIN=${JSON.stringify(source)}`,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("primitive MDCUI_MAIN define values keep their type", () => {
|
|
118
|
+
const cases = new Map([
|
|
119
|
+
['"../m.md"', '"../m.md"'],
|
|
120
|
+
["'../m.md'", '"../m.md"'],
|
|
121
|
+
["true", "true"],
|
|
122
|
+
["false", "false"],
|
|
123
|
+
["null", "null"],
|
|
124
|
+
["undefined", "undefined"],
|
|
125
|
+
["0", "0"],
|
|
126
|
+
["-1.5", "-1.5"],
|
|
127
|
+
["NaN", "NaN"],
|
|
128
|
+
["Infinity", "Infinity"],
|
|
129
|
+
["0xff", "0xff"],
|
|
130
|
+
["0b10", "0b10"],
|
|
131
|
+
["1_000", "1_000"],
|
|
132
|
+
]);
|
|
133
|
+
|
|
134
|
+
for (const [source, normalized] of cases) {
|
|
135
|
+
const argv = ["--define", `global.MDCUI_MAIN=${source}`];
|
|
136
|
+
stringifyNonPrimitiveDefineValues(argv, "global.MDCUI_MAIN");
|
|
137
|
+
expect(argv[1]).toBe(`global.MDCUI_MAIN=${normalized}`);
|
|
138
|
+
}
|
|
139
|
+
});
|