@bonsae/nrg 0.18.5 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/package.json +1 -1
- package/server/index.cjs +86 -9
- package/server/resources/nrg-client.js +2020 -1987
- package/test/client/component/config.js +11 -0
- package/test/client/component/index.js +218 -235
- package/test/client/component/nrg.css +1 -0
- package/test/client/component/setup.js +1549 -140
- package/test/client/e2e/index.js +706 -368
- package/test/client/unit/index.js +204 -16
- package/test/client/unit/setup.js +209 -19
- package/test/server/unit/index.js +25 -4
- package/tsconfig/core/client.json +1 -1
- package/tsconfig/test/client/component.json +1 -1
- package/types/client.d.ts +98 -18
- package/types/server.d.ts +50 -12
- package/types/shims/brands.d.ts +32 -0
- package/types/shims/{form → client/form}/components/node-red-editor-input.vue.d.ts +1 -1
- package/types/shims/{form → client/form}/components/node-red-json-schema-form.vue.d.ts +21 -2
- package/types/shims/{form → client/form}/components/node-red-select-input.vue.d.ts +1 -0
- package/types/shims/{form → client/form}/components/node-red-typed-input.vue.d.ts +1 -0
- package/types/shims/client/types.d.ts +206 -0
- package/types/shims/components.d.ts +8 -8
- package/types/shims/constants.d.ts +4 -0
- package/types/shims/schema-options.d.ts +23 -10
- package/types/shims/typebox.d.ts +2 -2
- package/types/test-client-component.d.ts +170 -55
- package/types/test-client-e2e.d.ts +50 -0
- package/types/test-client-unit.d.ts +86 -22
- package/types/test-server-unit.d.ts +3 -1
- package/types/vite.d.ts +25 -9
- package/vite/index.js +648 -499
- /package/types/shims/{form → client/form}/components/node-red-config-input.vue.d.ts +0 -0
- /package/types/shims/{form → client/form}/components/node-red-input-label.vue.d.ts +0 -0
- /package/types/shims/{form → client/form}/components/node-red-input.vue.d.ts +0 -0
- /package/types/shims/{form → client/form}/components/node-red-toggle.vue.d.ts +0 -0
- /package/types/shims/{globals.d.ts → client/globals.d.ts} +0 -0
package/vite/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/vite/plugin.ts
|
|
2
|
-
import
|
|
2
|
+
import path14 from "path";
|
|
3
3
|
|
|
4
4
|
// src/vite/defaults.ts
|
|
5
5
|
var DEFAULT_OUTPUT_DIR = "./dist";
|
|
@@ -106,17 +106,8 @@ function mergeOptions(defaults, overrides) {
|
|
|
106
106
|
return result;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
// src/vite/node-red-launcher.ts
|
|
110
|
-
import
|
|
111
|
-
import getPort from "get-port";
|
|
112
|
-
import detect from "detect-port";
|
|
113
|
-
import { builtinModules, createRequire } from "module";
|
|
114
|
-
import treeKill from "tree-kill";
|
|
115
|
-
import fs2 from "fs";
|
|
116
|
-
import os from "os";
|
|
117
|
-
import path2 from "path";
|
|
118
|
-
import { pathToFileURL } from "url";
|
|
119
|
-
import { build as esbuild } from "esbuild";
|
|
109
|
+
// src/vite/node-red-launcher/index.ts
|
|
110
|
+
import fs4 from "fs";
|
|
120
111
|
|
|
121
112
|
// src/vite/async-utils.ts
|
|
122
113
|
function debounce(fn, delay) {
|
|
@@ -259,203 +250,376 @@ var Logger = class _Logger {
|
|
|
259
250
|
};
|
|
260
251
|
var logger = new Logger({ name: "vite-plugin-node-red" });
|
|
261
252
|
|
|
262
|
-
// src/vite/node-red-launcher.ts
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
253
|
+
// src/vite/node-red-launcher/entry-point.ts
|
|
254
|
+
import { exec } from "child_process";
|
|
255
|
+
import { randomUUID } from "crypto";
|
|
256
|
+
import { createRequire } from "module";
|
|
257
|
+
import fs2 from "fs";
|
|
258
|
+
import os from "os";
|
|
259
|
+
import path2 from "path";
|
|
260
|
+
function getNodeRedCommand(version) {
|
|
261
|
+
return version ? `node-red@${version}` : "node-red";
|
|
262
|
+
}
|
|
263
|
+
function resolveNodeRedFromLocalNodeModules() {
|
|
264
|
+
try {
|
|
265
|
+
const require_ = createRequire(path2.join(process.cwd(), "package.json"));
|
|
266
|
+
const pkgJsonPath = require_.resolve("node-red/package.json");
|
|
267
|
+
const pkgDir = path2.dirname(pkgJsonPath);
|
|
268
|
+
const pkg = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
|
|
269
|
+
const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.["node-red"];
|
|
270
|
+
if (!bin) return null;
|
|
271
|
+
const entry = path2.resolve(pkgDir, bin);
|
|
272
|
+
return fs2.existsSync(entry) ? entry : null;
|
|
273
|
+
} catch {
|
|
274
|
+
return null;
|
|
279
275
|
}
|
|
280
|
-
|
|
281
|
-
|
|
276
|
+
}
|
|
277
|
+
async function resolveNodeRed(options) {
|
|
278
|
+
const { version, npxTimeoutMs = 3e5, logger: logger2 } = options;
|
|
279
|
+
if (version && !/^[\w.^~<>=*-]+$/.test(version)) {
|
|
280
|
+
throw new NodeRedStartError(
|
|
281
|
+
new Error(`Invalid node-red version "${version}"`)
|
|
282
|
+
);
|
|
282
283
|
}
|
|
283
|
-
|
|
284
|
-
|
|
284
|
+
const nodeRedCommand = getNodeRedCommand(version);
|
|
285
|
+
logger2.info(`Resolving ${nodeRedCommand} entry point...`);
|
|
286
|
+
const hasExplicitVersion = version !== void 0 && version !== "latest";
|
|
287
|
+
if (!hasExplicitVersion) {
|
|
288
|
+
const localEntry = resolveNodeRedFromLocalNodeModules();
|
|
289
|
+
if (localEntry) {
|
|
290
|
+
logger2.info(`Resolved from local node_modules: ${localEntry}`);
|
|
291
|
+
return localEntry;
|
|
292
|
+
}
|
|
285
293
|
}
|
|
286
|
-
|
|
287
|
-
|
|
294
|
+
logger2.info(
|
|
295
|
+
hasExplicitVersion ? `Using configured version (${version}), downloading via npx...` : `Not found locally, downloading via npx (this may take a while)...`
|
|
296
|
+
);
|
|
297
|
+
const resolverScript = path2.join(
|
|
298
|
+
os.tmpdir(),
|
|
299
|
+
`nrg-resolve-node-red-${process.pid}-${randomUUID()}.cjs`
|
|
300
|
+
);
|
|
301
|
+
fs2.writeFileSync(
|
|
302
|
+
resolverScript,
|
|
303
|
+
`const fs = require("fs");
|
|
304
|
+
const path = require("path");
|
|
305
|
+
const isWin = process.platform === "win32";
|
|
306
|
+
const binName = isWin ? "node-red.cmd" : "node-red";
|
|
307
|
+
const dirs = process.env.PATH.split(path.delimiter);
|
|
308
|
+
for (const d of dirs) {
|
|
309
|
+
const f = path.join(d, binName);
|
|
310
|
+
if (fs.existsSync(f)) {
|
|
311
|
+
if (isWin) {
|
|
312
|
+
const nodeRedDir = path.resolve(d, "..", "node-red");
|
|
313
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(nodeRedDir, "package.json"), "utf-8"));
|
|
314
|
+
const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin["node-red"];
|
|
315
|
+
process.stdout.write(path.resolve(nodeRedDir, bin));
|
|
316
|
+
} else {
|
|
317
|
+
process.stdout.write(fs.realpathSync(f));
|
|
318
|
+
}
|
|
319
|
+
break;
|
|
288
320
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
321
|
+
}`
|
|
322
|
+
);
|
|
323
|
+
try {
|
|
324
|
+
const stdout = await new Promise((resolve, reject) => {
|
|
325
|
+
exec(
|
|
326
|
+
`npx --yes -p ${nodeRedCommand} node "${resolverScript}"`,
|
|
327
|
+
{ timeout: npxTimeoutMs },
|
|
328
|
+
(error, stdout2) => {
|
|
329
|
+
if (error) reject(error);
|
|
330
|
+
else resolve(stdout2);
|
|
331
|
+
}
|
|
332
|
+
);
|
|
333
|
+
});
|
|
334
|
+
const entryPoint = stdout.trim();
|
|
335
|
+
if (!entryPoint || !fs2.existsSync(entryPoint)) {
|
|
336
|
+
throw new NodeRedStartError(
|
|
337
|
+
new Error(
|
|
338
|
+
`Could not resolve node-red entry point: ${entryPoint || "(empty)"}`
|
|
339
|
+
)
|
|
340
|
+
);
|
|
293
341
|
}
|
|
294
|
-
|
|
295
|
-
|
|
342
|
+
logger2.info(`Resolved via npx: ${entryPoint}`);
|
|
343
|
+
return entryPoint;
|
|
344
|
+
} finally {
|
|
345
|
+
try {
|
|
346
|
+
fs2.unlinkSync(resolverScript);
|
|
347
|
+
} catch {
|
|
296
348
|
}
|
|
297
|
-
return "node-red";
|
|
298
349
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// src/vite/node-red-launcher/settings.ts
|
|
353
|
+
import { builtinModules } from "module";
|
|
354
|
+
import fs3 from "fs";
|
|
355
|
+
import os2 from "os";
|
|
356
|
+
import path3 from "path";
|
|
357
|
+
import { pathToFileURL } from "url";
|
|
358
|
+
import { build as esbuild } from "esbuild";
|
|
359
|
+
function findUserRuntimeSettingsFilepath(settingsFilepath, logger2) {
|
|
360
|
+
if (settingsFilepath) {
|
|
361
|
+
const resolved2 = path3.resolve(settingsFilepath);
|
|
362
|
+
if (fs3.existsSync(resolved2)) {
|
|
363
|
+
return resolved2;
|
|
312
364
|
}
|
|
365
|
+
logger2.warn(`Settings file not found: ${settingsFilepath}`);
|
|
313
366
|
return null;
|
|
314
367
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
368
|
+
const resolved = path3.resolve("node-red.settings.ts");
|
|
369
|
+
if (fs3.existsSync(resolved)) {
|
|
370
|
+
return resolved;
|
|
371
|
+
}
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
async function compileRuntimeSettingsFile(runtimeSettingsFilepath, port) {
|
|
375
|
+
const compiledRuntimeSettingsFilepath = path3.join(
|
|
376
|
+
os2.tmpdir(),
|
|
377
|
+
`node-red.settings.${process.pid}-${port}.cjs`
|
|
378
|
+
);
|
|
379
|
+
const nodeBuiltins2 = [
|
|
380
|
+
...builtinModules,
|
|
381
|
+
...builtinModules.map((m) => `node:${m}`)
|
|
382
|
+
];
|
|
383
|
+
const settingsDir = path3.dirname(runtimeSettingsFilepath).split(path3.sep).join("/");
|
|
384
|
+
const settingsFile = runtimeSettingsFilepath.split(path3.sep).join("/");
|
|
385
|
+
await esbuild({
|
|
386
|
+
entryPoints: [runtimeSettingsFilepath],
|
|
387
|
+
outfile: compiledRuntimeSettingsFilepath,
|
|
388
|
+
format: "cjs",
|
|
389
|
+
platform: "node",
|
|
390
|
+
target: "node18",
|
|
391
|
+
bundle: true,
|
|
392
|
+
define: {
|
|
393
|
+
"import.meta.dirname": JSON.stringify(settingsDir),
|
|
394
|
+
"import.meta.filename": JSON.stringify(settingsFile),
|
|
395
|
+
"import.meta.url": JSON.stringify(pathToFileURL(settingsFile).href)
|
|
396
|
+
},
|
|
397
|
+
external: [...nodeBuiltins2, "node-red", "@node-red/*"]
|
|
398
|
+
});
|
|
399
|
+
return compiledRuntimeSettingsFilepath;
|
|
400
|
+
}
|
|
401
|
+
async function generateRuntimeSettings(options) {
|
|
402
|
+
const { outDir, port, settingsFilepath, logger: logger2 } = options;
|
|
403
|
+
const tempFiles = [];
|
|
404
|
+
const userRuntimeSettingsFilepath = findUserRuntimeSettingsFilepath(
|
|
405
|
+
settingsFilepath,
|
|
406
|
+
logger2
|
|
407
|
+
);
|
|
408
|
+
let compiledRuntimeSettingsFilepath = null;
|
|
409
|
+
if (userRuntimeSettingsFilepath) {
|
|
410
|
+
compiledRuntimeSettingsFilepath = await compileRuntimeSettingsFile(
|
|
411
|
+
userRuntimeSettingsFilepath,
|
|
412
|
+
port
|
|
319
413
|
);
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
target: "node18",
|
|
332
|
-
bundle: true,
|
|
333
|
-
define: {
|
|
334
|
-
"import.meta.dirname": JSON.stringify(settingsDir),
|
|
335
|
-
"import.meta.filename": JSON.stringify(settingsFile),
|
|
336
|
-
"import.meta.url": JSON.stringify(pathToFileURL(settingsFile).href)
|
|
337
|
-
},
|
|
338
|
-
external: [...nodeBuiltins2, "node-red", "@node-red/*"]
|
|
339
|
-
});
|
|
340
|
-
this.compiledRuntimeSettingsFilepath = compiledRuntimeSettingsFilepath;
|
|
341
|
-
return compiledRuntimeSettingsFilepath;
|
|
342
|
-
}
|
|
343
|
-
async generateRuntimeSettingsFile() {
|
|
344
|
-
const userRuntimeSettingsFilepath = this.findRuntimeSettingsFilepath();
|
|
345
|
-
let compiledRuntimeSettingsFilepath = null;
|
|
346
|
-
if (userRuntimeSettingsFilepath) {
|
|
347
|
-
compiledRuntimeSettingsFilepath = await this.compileRuntimeSettingsFile(
|
|
348
|
-
userRuntimeSettingsFilepath
|
|
349
|
-
);
|
|
350
|
-
}
|
|
351
|
-
const outDir = path2.resolve(this.outDir).split(path2.sep).join("/");
|
|
352
|
-
const cwd = process.cwd().split(path2.sep).join("/");
|
|
353
|
-
const userDir = path2.resolve(cwd, ".node-red").split(path2.sep).join("/");
|
|
354
|
-
const finalRuntimeSettingsFile = compiledRuntimeSettingsFilepath ? `
|
|
355
|
-
const compiledRuntimeSettings = require("${compiledRuntimeSettingsFilepath.split(path2.sep).join("/")}");
|
|
414
|
+
tempFiles.push(compiledRuntimeSettingsFilepath);
|
|
415
|
+
}
|
|
416
|
+
const normalizedOutDir = path3.resolve(outDir).split(path3.sep).join("/");
|
|
417
|
+
const cwd = process.cwd().split(path3.sep).join("/");
|
|
418
|
+
const userDir = path3.resolve(cwd, ".node-red").split(path3.sep).join("/");
|
|
419
|
+
const userDirLiteral = JSON.stringify(userDir);
|
|
420
|
+
const outDirLiteral = JSON.stringify(normalizedOutDir);
|
|
421
|
+
const finalRuntimeSettingsFile = compiledRuntimeSettingsFilepath ? `
|
|
422
|
+
const compiledRuntimeSettings = require(${JSON.stringify(
|
|
423
|
+
compiledRuntimeSettingsFilepath.split(path3.sep).join("/")
|
|
424
|
+
)});
|
|
356
425
|
const settings = compiledRuntimeSettings.default || compiledRuntimeSettings;
|
|
357
|
-
settings.uiPort = ${
|
|
426
|
+
settings.uiPort = ${port};
|
|
358
427
|
if(!settings.userDir){
|
|
359
|
-
settings.userDir =
|
|
428
|
+
settings.userDir = ${userDirLiteral};
|
|
360
429
|
}
|
|
361
430
|
settings.nodesDir = settings.nodesDir || [];
|
|
362
|
-
if (!settings.nodesDir.includes(
|
|
363
|
-
settings.nodesDir.push(
|
|
431
|
+
if (!settings.nodesDir.includes(${outDirLiteral})) {
|
|
432
|
+
settings.nodesDir.push(${outDirLiteral});
|
|
364
433
|
}
|
|
365
434
|
if(!settings.flowFile){
|
|
366
435
|
settings.flowFile = "flows.json";
|
|
367
436
|
}
|
|
437
|
+
// the welcome tour overlay intercepts pointer events \u2014 fatal for e2e and
|
|
438
|
+
// noise for dev; explicit user settings still win
|
|
439
|
+
settings.editorTheme = settings.editorTheme || {};
|
|
440
|
+
if (settings.editorTheme.tours === undefined) {
|
|
441
|
+
settings.editorTheme.tours = false;
|
|
442
|
+
}
|
|
368
443
|
module.exports = settings;
|
|
369
444
|
` : `
|
|
370
445
|
const settings = {
|
|
371
|
-
uiPort: ${
|
|
372
|
-
userDir:
|
|
446
|
+
uiPort: ${port},
|
|
447
|
+
userDir: ${userDirLiteral},
|
|
373
448
|
flowFile: "flows.json",
|
|
374
|
-
nodesDir: [
|
|
449
|
+
nodesDir: [${outDirLiteral}],
|
|
450
|
+
// the welcome tour overlay intercepts pointer events \u2014 fatal for e2e
|
|
451
|
+
editorTheme: { tours: false },
|
|
375
452
|
};
|
|
376
453
|
module.exports = settings;
|
|
377
454
|
`;
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
455
|
+
const finalRuntimeSettingsFilepath = path3.join(
|
|
456
|
+
os2.tmpdir(),
|
|
457
|
+
`node-red-settings-final-${process.pid}-${port}.cjs`
|
|
458
|
+
);
|
|
459
|
+
fs3.writeFileSync(finalRuntimeSettingsFilepath, finalRuntimeSettingsFile);
|
|
460
|
+
tempFiles.push(finalRuntimeSettingsFilepath);
|
|
461
|
+
return { filepath: finalRuntimeSettingsFilepath, tempFiles };
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// src/vite/node-red-launcher/process.ts
|
|
465
|
+
import { spawn } from "child_process";
|
|
466
|
+
import detect from "detect-port";
|
|
467
|
+
import getPort from "get-port";
|
|
468
|
+
import treeKill from "tree-kill";
|
|
469
|
+
var READY_MARKERS = ["Started flows", "Server now running"];
|
|
470
|
+
function start(options) {
|
|
471
|
+
const { entryPoint, settingsPath, args, onLine } = options;
|
|
472
|
+
const child = spawn(
|
|
473
|
+
process.execPath,
|
|
474
|
+
[entryPoint, "-s", settingsPath, ...args],
|
|
475
|
+
{
|
|
476
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
398
477
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
478
|
+
);
|
|
479
|
+
let isReady = false;
|
|
480
|
+
let resolveReady;
|
|
481
|
+
let rejectReady;
|
|
482
|
+
const ready = new Promise((resolve, reject) => {
|
|
483
|
+
resolveReady = resolve;
|
|
484
|
+
rejectReady = reject;
|
|
485
|
+
});
|
|
486
|
+
const emitLine = (rawLine, source) => {
|
|
487
|
+
const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
|
|
488
|
+
if (!line) return;
|
|
489
|
+
onLine(line, source, isReady);
|
|
490
|
+
if (source === "stdout" && READY_MARKERS.some((marker) => line.includes(marker))) {
|
|
491
|
+
isReady = true;
|
|
492
|
+
resolveReady();
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
const remainders = { stdout: "", stderr: "" };
|
|
496
|
+
const handleData = (data, source) => {
|
|
497
|
+
const lines = (remainders[source] + data.toString()).split("\n");
|
|
498
|
+
remainders[source] = lines.pop() ?? "";
|
|
499
|
+
for (const line of lines) {
|
|
500
|
+
emitLine(line, source);
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
const flushRemainders = () => {
|
|
504
|
+
for (const source of ["stdout", "stderr"]) {
|
|
505
|
+
const rest = remainders[source];
|
|
506
|
+
remainders[source] = "";
|
|
507
|
+
if (rest) {
|
|
508
|
+
emitLine(rest, source);
|
|
408
509
|
}
|
|
409
510
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const dirs = process.env.PATH.split(path.delimiter);
|
|
424
|
-
for (const d of dirs) {
|
|
425
|
-
const f = path.join(d, binName);
|
|
426
|
-
if (fs.existsSync(f)) {
|
|
427
|
-
if (isWin) {
|
|
428
|
-
const nodeRedDir = path.resolve(d, "..", "node-red");
|
|
429
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(nodeRedDir, "package.json"), "utf-8"));
|
|
430
|
-
const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin["node-red"];
|
|
431
|
-
process.stdout.write(path.resolve(nodeRedDir, bin));
|
|
432
|
-
} else {
|
|
433
|
-
process.stdout.write(fs.realpathSync(f));
|
|
511
|
+
};
|
|
512
|
+
child.stdout?.on("data", (data) => handleData(data, "stdout"));
|
|
513
|
+
child.stderr?.on("data", (data) => handleData(data, "stderr"));
|
|
514
|
+
child.on("error", (error) => {
|
|
515
|
+
rejectReady(new NodeRedStartError(error));
|
|
516
|
+
});
|
|
517
|
+
child.on("exit", (code) => {
|
|
518
|
+
flushRemainders();
|
|
519
|
+
if (!isReady && code !== 0 && code !== null) {
|
|
520
|
+
rejectReady(
|
|
521
|
+
new NodeRedStartError(new Error(`Process exited with code ${code}`))
|
|
522
|
+
);
|
|
523
|
+
return;
|
|
434
524
|
}
|
|
435
|
-
|
|
525
|
+
resolveReady();
|
|
526
|
+
});
|
|
527
|
+
return { child, ready };
|
|
528
|
+
}
|
|
529
|
+
function kill(pid) {
|
|
530
|
+
return new Promise((resolve) => {
|
|
531
|
+
treeKill(pid, "SIGKILL", () => resolve());
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
async function stop(options) {
|
|
535
|
+
const { child, pid, gracefulTimeoutMs = 1e4, logger: logger2 } = options;
|
|
536
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
537
|
+
return;
|
|
436
538
|
}
|
|
437
|
-
|
|
438
|
-
);
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
new Error(
|
|
447
|
-
`Could not resolve node-red entry point: ${entryPoint || "(empty)"}`
|
|
448
|
-
)
|
|
449
|
-
);
|
|
450
|
-
}
|
|
451
|
-
this.logger.info(`Resolved via npx: ${entryPoint}`);
|
|
452
|
-
return entryPoint;
|
|
453
|
-
} finally {
|
|
454
|
-
try {
|
|
455
|
-
fs2.unlinkSync(resolverScript);
|
|
456
|
-
} catch {
|
|
539
|
+
const exited = new Promise((resolve) => {
|
|
540
|
+
child.once("exit", () => resolve());
|
|
541
|
+
treeKill(pid, "SIGTERM", (error) => {
|
|
542
|
+
if (error) {
|
|
543
|
+
try {
|
|
544
|
+
process.kill(pid, "SIGTERM");
|
|
545
|
+
} catch {
|
|
546
|
+
resolve();
|
|
547
|
+
}
|
|
457
548
|
}
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
try {
|
|
552
|
+
await withTimeout(exited, gracefulTimeoutMs);
|
|
553
|
+
} catch {
|
|
554
|
+
logger2.warn("Graceful shutdown timed out, force killing...");
|
|
555
|
+
await kill(pid);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
async function acquirePort(options) {
|
|
559
|
+
const { preferredPort, retryDelay = 2e3, logger: logger2 } = options;
|
|
560
|
+
const available = await detect(preferredPort);
|
|
561
|
+
if (available === preferredPort) {
|
|
562
|
+
return preferredPort;
|
|
563
|
+
}
|
|
564
|
+
logger2.warn(`Port ${preferredPort} is still in use, waiting...`);
|
|
565
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
566
|
+
const retryAvailable = await detect(preferredPort);
|
|
567
|
+
if (retryAvailable === preferredPort) {
|
|
568
|
+
return preferredPort;
|
|
569
|
+
}
|
|
570
|
+
const fallbackPort = await getPort({ port: preferredPort });
|
|
571
|
+
logger2.warn(
|
|
572
|
+
`Port ${preferredPort} still occupied, using port ${fallbackPort}`
|
|
573
|
+
);
|
|
574
|
+
return fallbackPort;
|
|
575
|
+
}
|
|
576
|
+
async function waitForPortRelease(port, options = {}) {
|
|
577
|
+
const { attempts = 10, delay = 300 } = options;
|
|
578
|
+
const checkPortUsage = async () => {
|
|
579
|
+
const availablePort = await detect(port);
|
|
580
|
+
if (availablePort !== port) {
|
|
581
|
+
throw new Error("Port still in use");
|
|
458
582
|
}
|
|
583
|
+
};
|
|
584
|
+
try {
|
|
585
|
+
await retry(checkPortUsage, { attempts, delay });
|
|
586
|
+
return true;
|
|
587
|
+
} catch {
|
|
588
|
+
return false;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// src/vite/node-red-launcher/index.ts
|
|
593
|
+
var NodeRedLauncher = class {
|
|
594
|
+
operationQueue = Promise.resolve();
|
|
595
|
+
process = null;
|
|
596
|
+
unwatchExit = null;
|
|
597
|
+
nodeRedEntryPoint = null;
|
|
598
|
+
tempFiles = [];
|
|
599
|
+
bufferedLogs = [];
|
|
600
|
+
port = null;
|
|
601
|
+
outDir;
|
|
602
|
+
options;
|
|
603
|
+
logger;
|
|
604
|
+
constructor(outDir, options) {
|
|
605
|
+
this.outDir = outDir;
|
|
606
|
+
this.options = options;
|
|
607
|
+
this.logger = new Logger({
|
|
608
|
+
name: "vite-plugin-node-red",
|
|
609
|
+
prefix: "node-red"
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
get preferredPort() {
|
|
613
|
+
return this.options.runtime?.port ?? 1880;
|
|
614
|
+
}
|
|
615
|
+
get restartDelay() {
|
|
616
|
+
return this.options.restartDelay ?? 1e3;
|
|
617
|
+
}
|
|
618
|
+
get pid() {
|
|
619
|
+
return this.process?.child.pid ?? null;
|
|
620
|
+
}
|
|
621
|
+
get nodeRedCommand() {
|
|
622
|
+
return getNodeRedCommand(this.options.runtime?.version);
|
|
459
623
|
}
|
|
460
624
|
log(line) {
|
|
461
625
|
if (line.includes("Server now running at")) {
|
|
@@ -463,150 +627,121 @@ for (const d of dirs) {
|
|
|
463
627
|
}
|
|
464
628
|
this.logger.raw(line);
|
|
465
629
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
630
|
+
handleProcessLine(line, source, ready) {
|
|
631
|
+
if (!ready) {
|
|
632
|
+
this.bufferedLogs.push(line);
|
|
633
|
+
} else if (source === "stderr") {
|
|
634
|
+
this.logger.error(line);
|
|
470
635
|
} else {
|
|
636
|
+
this.log(line);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
async killProcess() {
|
|
640
|
+
if (!this.process) return;
|
|
641
|
+
this.stopWatchingExit();
|
|
642
|
+
const pid = this.process.child.pid;
|
|
643
|
+
if (pid) {
|
|
644
|
+
await kill(pid);
|
|
645
|
+
}
|
|
646
|
+
this.process = null;
|
|
647
|
+
}
|
|
648
|
+
watchForUnexpectedExit(managed) {
|
|
649
|
+
const onExit = (code, signal) => {
|
|
650
|
+
this.unwatchExit = null;
|
|
651
|
+
this.process = null;
|
|
471
652
|
this.logger.warn(
|
|
472
|
-
`
|
|
653
|
+
`Node-RED exited unexpectedly (${signal ?? `code ${code}`})`
|
|
473
654
|
);
|
|
474
|
-
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
475
|
-
const retryAvailable = await detect(this.preferredPort);
|
|
476
|
-
if (retryAvailable === this.preferredPort) {
|
|
477
|
-
this.port = this.preferredPort;
|
|
478
|
-
} else {
|
|
479
|
-
this.logger.warn(
|
|
480
|
-
`Port ${this.preferredPort} still occupied, using port ${retryAvailable}`
|
|
481
|
-
);
|
|
482
|
-
this.port = await getPort({ port: this.preferredPort });
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
const nodeRedEntryPoint = this.resolveNodeRedEntryPoint();
|
|
486
|
-
const startProcess = () => {
|
|
487
|
-
return new Promise(async (resolve, reject) => {
|
|
488
|
-
try {
|
|
489
|
-
const settingsPath = await this.generateRuntimeSettingsFile();
|
|
490
|
-
const args = this.options.args ?? [];
|
|
491
|
-
this.bufferedLogs = [];
|
|
492
|
-
this.isReady = false;
|
|
493
|
-
this.process = spawn(
|
|
494
|
-
process.execPath,
|
|
495
|
-
[nodeRedEntryPoint, "-s", settingsPath, ...args],
|
|
496
|
-
{
|
|
497
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
498
|
-
}
|
|
499
|
-
);
|
|
500
|
-
this.process.stdout?.on("data", (data) => {
|
|
501
|
-
const lines = data.toString().split("\n").filter(Boolean);
|
|
502
|
-
for (const line of lines) {
|
|
503
|
-
if (this.isReady) {
|
|
504
|
-
this.log(line);
|
|
505
|
-
} else {
|
|
506
|
-
this.bufferedLogs.push(line);
|
|
507
|
-
}
|
|
508
|
-
if (line.includes("Started flows") || line.includes("Server now running")) {
|
|
509
|
-
this.isReady = true;
|
|
510
|
-
resolve(void 0);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
});
|
|
514
|
-
this.process.stderr?.on("data", (data) => {
|
|
515
|
-
const lines = data.toString().split("\n").filter(Boolean);
|
|
516
|
-
for (const line of lines) {
|
|
517
|
-
if (this.isReady) {
|
|
518
|
-
this.logger.error(`${line}`);
|
|
519
|
-
} else {
|
|
520
|
-
this.bufferedLogs.push(line);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
});
|
|
524
|
-
this.process.on("error", (error) => {
|
|
525
|
-
reject(new NodeRedStartError(error));
|
|
526
|
-
});
|
|
527
|
-
this.process.on("exit", (code) => {
|
|
528
|
-
if (!this.isReady && code !== 0 && code !== null) {
|
|
529
|
-
reject(
|
|
530
|
-
new NodeRedStartError(
|
|
531
|
-
new Error(`Process exited with code ${code}`)
|
|
532
|
-
)
|
|
533
|
-
);
|
|
534
|
-
}
|
|
535
|
-
resolve(void 0);
|
|
536
|
-
});
|
|
537
|
-
} catch (error) {
|
|
538
|
-
reject(new NodeRedStartError(error));
|
|
539
|
-
}
|
|
540
|
-
});
|
|
541
655
|
};
|
|
656
|
+
managed.child.once("exit", onExit);
|
|
657
|
+
this.unwatchExit = () => managed.child.off("exit", onExit);
|
|
658
|
+
}
|
|
659
|
+
stopWatchingExit() {
|
|
660
|
+
this.unwatchExit?.();
|
|
661
|
+
this.unwatchExit = null;
|
|
662
|
+
}
|
|
663
|
+
// start/stop interleaving (e.g. SIGINT while Node-RED is booting) would
|
|
664
|
+
// race on process/port state and could leak a spawned process, so all
|
|
665
|
+
// lifecycle operations run strictly one at a time
|
|
666
|
+
enqueue(operation) {
|
|
667
|
+
const result = this.operationQueue.then(operation, operation);
|
|
668
|
+
this.operationQueue = result.catch(() => {
|
|
669
|
+
});
|
|
670
|
+
return result;
|
|
671
|
+
}
|
|
672
|
+
async start() {
|
|
673
|
+
return this.enqueue(() => this.doStart());
|
|
674
|
+
}
|
|
675
|
+
async stop(skipPortUsageCheck = false) {
|
|
676
|
+
return this.enqueue(() => this.doStop(skipPortUsageCheck));
|
|
677
|
+
}
|
|
678
|
+
async doStart() {
|
|
542
679
|
try {
|
|
680
|
+
this.port = await acquirePort({
|
|
681
|
+
preferredPort: this.preferredPort,
|
|
682
|
+
logger: this.logger
|
|
683
|
+
});
|
|
684
|
+
if (!this.nodeRedEntryPoint || !fs4.existsSync(this.nodeRedEntryPoint)) {
|
|
685
|
+
this.nodeRedEntryPoint = await resolveNodeRed({
|
|
686
|
+
version: this.options.runtime?.version,
|
|
687
|
+
logger: this.logger
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
const nodeRedEntryPoint = this.nodeRedEntryPoint;
|
|
691
|
+
const settings = await generateRuntimeSettings({
|
|
692
|
+
outDir: this.outDir,
|
|
693
|
+
port: this.port,
|
|
694
|
+
settingsFilepath: this.options.runtime?.settingsFilepath,
|
|
695
|
+
logger: this.logger
|
|
696
|
+
});
|
|
697
|
+
for (const file of settings.tempFiles) {
|
|
698
|
+
if (!this.tempFiles.includes(file)) {
|
|
699
|
+
this.tempFiles.push(file);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
const startProcess = async () => {
|
|
703
|
+
await this.killProcess();
|
|
704
|
+
this.bufferedLogs = [];
|
|
705
|
+
this.process = start({
|
|
706
|
+
entryPoint: nodeRedEntryPoint,
|
|
707
|
+
settingsPath: settings.filepath,
|
|
708
|
+
args: this.options.args ?? [],
|
|
709
|
+
onLine: (line, source, ready) => this.handleProcessLine(line, source, ready)
|
|
710
|
+
});
|
|
711
|
+
await this.process.ready;
|
|
712
|
+
};
|
|
543
713
|
await retry(startProcess, { attempts: 3, delay: 100 });
|
|
714
|
+
this.watchForUnexpectedExit(this.process);
|
|
544
715
|
return this.port;
|
|
545
716
|
} catch (error) {
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
if (pid) {
|
|
549
|
-
treeKill(pid, "SIGKILL");
|
|
550
|
-
}
|
|
551
|
-
this.process = null;
|
|
552
|
-
}
|
|
553
|
-
throw new NodeRedStartError(error);
|
|
717
|
+
await this.killProcess();
|
|
718
|
+
throw error instanceof NodeRedStartError ? error : new NodeRedStartError(error);
|
|
554
719
|
}
|
|
555
720
|
}
|
|
556
|
-
async
|
|
721
|
+
async doStop(skipPortUsageCheck) {
|
|
557
722
|
if (!this.process) return;
|
|
558
|
-
|
|
723
|
+
this.stopWatchingExit();
|
|
724
|
+
const pid = this.process.child.pid;
|
|
559
725
|
const currentPort = this.port;
|
|
560
726
|
if (!pid) {
|
|
561
727
|
this.process = null;
|
|
728
|
+
this.port = null;
|
|
562
729
|
return;
|
|
563
730
|
}
|
|
564
|
-
|
|
565
|
-
this.process.
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
});
|
|
569
|
-
treeKill(pid, "SIGTERM", (error) => {
|
|
570
|
-
if (error) {
|
|
571
|
-
try {
|
|
572
|
-
process.kill(pid, "SIGTERM");
|
|
573
|
-
} catch {
|
|
574
|
-
this.process = null;
|
|
575
|
-
resolve(void 0);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
});
|
|
731
|
+
await stop({
|
|
732
|
+
child: this.process.child,
|
|
733
|
+
pid,
|
|
734
|
+
logger: this.logger
|
|
579
735
|
});
|
|
580
|
-
|
|
581
|
-
await withTimeout(stopProcess, 1e4);
|
|
582
|
-
} catch {
|
|
583
|
-
this.logger.warn("Graceful shutdown timed out, force killing...");
|
|
584
|
-
await new Promise((resolve) => {
|
|
585
|
-
treeKill(pid, "SIGKILL", () => {
|
|
586
|
-
this.process = null;
|
|
587
|
-
resolve(void 0);
|
|
588
|
-
});
|
|
589
|
-
});
|
|
590
|
-
}
|
|
736
|
+
this.process = null;
|
|
591
737
|
if (!skipPortUsageCheck && currentPort) {
|
|
592
|
-
const
|
|
593
|
-
|
|
594
|
-
if (availablePort !== currentPort) {
|
|
595
|
-
throw new Error("Port still in use");
|
|
596
|
-
}
|
|
597
|
-
};
|
|
598
|
-
try {
|
|
599
|
-
await retry(checkPortUsage, { attempts: 10, delay: 300 });
|
|
600
|
-
} catch {
|
|
738
|
+
const released = await waitForPortRelease(currentPort);
|
|
739
|
+
if (!released) {
|
|
601
740
|
this.logger.warn(
|
|
602
741
|
`Port ${currentPort} still in use after stop. Force killing...`
|
|
603
742
|
);
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
treeKill(pid, "SIGKILL", () => resolve());
|
|
607
|
-
});
|
|
608
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
609
|
-
}
|
|
743
|
+
await kill(pid);
|
|
744
|
+
await waitForPortRelease(currentPort);
|
|
610
745
|
}
|
|
611
746
|
}
|
|
612
747
|
this.port = null;
|
|
@@ -618,32 +753,35 @@ for (const d of dirs) {
|
|
|
618
753
|
this.bufferedLogs = [];
|
|
619
754
|
}
|
|
620
755
|
cleanup() {
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
756
|
+
for (const file of this.tempFiles) {
|
|
757
|
+
try {
|
|
758
|
+
fs4.unlinkSync(file);
|
|
759
|
+
} catch {
|
|
760
|
+
}
|
|
624
761
|
}
|
|
762
|
+
this.tempFiles = [];
|
|
625
763
|
}
|
|
626
764
|
};
|
|
627
765
|
|
|
628
766
|
// src/vite/plugins/server.ts
|
|
629
767
|
import chokidar from "chokidar";
|
|
630
768
|
import treeKill2 from "tree-kill";
|
|
631
|
-
import
|
|
769
|
+
import path13 from "path";
|
|
632
770
|
|
|
633
771
|
// src/vite/server/build.ts
|
|
634
772
|
import { build as viteBuild } from "vite";
|
|
635
|
-
import
|
|
636
|
-
import
|
|
773
|
+
import fs7 from "fs";
|
|
774
|
+
import path6 from "path";
|
|
637
775
|
|
|
638
776
|
// src/vite/server/plugins/type-generator.ts
|
|
639
777
|
import dts from "vite-plugin-dts";
|
|
640
|
-
import
|
|
641
|
-
import
|
|
778
|
+
import fs5 from "fs";
|
|
779
|
+
import path4 from "path";
|
|
642
780
|
import ts from "typescript";
|
|
643
781
|
function collectTsFiles(dir) {
|
|
644
|
-
if (!
|
|
645
|
-
return
|
|
646
|
-
const full =
|
|
782
|
+
if (!fs5.existsSync(dir)) return [];
|
|
783
|
+
return fs5.readdirSync(dir, { withFileTypes: true }).flatMap((dirent) => {
|
|
784
|
+
const full = path4.join(dir, dirent.name);
|
|
647
785
|
if (dirent.isDirectory()) return collectTsFiles(full);
|
|
648
786
|
if (dirent.isFile() && dirent.name.endsWith(".ts") && !dirent.name.endsWith(".d.ts"))
|
|
649
787
|
return [full];
|
|
@@ -658,7 +796,7 @@ var BASE_CLASS_SLOTS = {
|
|
|
658
796
|
ConfigNode: ["Config", "Credentials", "Settings"]
|
|
659
797
|
};
|
|
660
798
|
function getNodeTypeExports(filePath) {
|
|
661
|
-
const content =
|
|
799
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
662
800
|
const source = ts.createSourceFile(
|
|
663
801
|
filePath,
|
|
664
802
|
content,
|
|
@@ -720,7 +858,7 @@ var SCHEMA_PROP_SEMANTICS = {
|
|
|
720
858
|
settingsSchema: "SettingsSchema"
|
|
721
859
|
};
|
|
722
860
|
function getSchemaReferences(filePath) {
|
|
723
|
-
const content =
|
|
861
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
724
862
|
const source = ts.createSourceFile(
|
|
725
863
|
filePath,
|
|
726
864
|
content,
|
|
@@ -812,7 +950,7 @@ function getSchemaReferences(filePath) {
|
|
|
812
950
|
return result;
|
|
813
951
|
}
|
|
814
952
|
function getFactoryInfo(filePath) {
|
|
815
|
-
const content =
|
|
953
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
816
954
|
const source = ts.createSourceFile(
|
|
817
955
|
filePath,
|
|
818
956
|
content,
|
|
@@ -846,13 +984,13 @@ function buildTypeArg(schemaMap, semanticName, portNameMap) {
|
|
|
846
984
|
return `[${names.map((n) => `Infer<typeof ${n}>`).join(", ")}]`;
|
|
847
985
|
}
|
|
848
986
|
function buildNodeReexports(srcDir, entryFile) {
|
|
849
|
-
const nodesDir =
|
|
987
|
+
const nodesDir = path4.join(srcDir, "nodes");
|
|
850
988
|
const nodeFiles = collectTsFiles(nodesDir);
|
|
851
989
|
return nodeFiles.map((file) => {
|
|
852
|
-
const rel =
|
|
990
|
+
const rel = path4.relative(path4.dirname(entryFile), file).replace(/\\/g, "/");
|
|
853
991
|
const relPath = rel.startsWith(".") ? rel : `./${rel}`;
|
|
854
992
|
const specifier = relPath.replace(/\.ts$/, "");
|
|
855
|
-
const ns = toPascalCase(
|
|
993
|
+
const ns = toPascalCase(path4.basename(file, ".ts"));
|
|
856
994
|
const schemaRefs = getSchemaReferences(file);
|
|
857
995
|
const factoryInfo = getFactoryInfo(file);
|
|
858
996
|
const lines = [];
|
|
@@ -879,9 +1017,9 @@ function buildNodeReexports(srcDir, entryFile) {
|
|
|
879
1017
|
if (hasSchemas) {
|
|
880
1018
|
const bySource2 = /* @__PURE__ */ new Map();
|
|
881
1019
|
for (const ref of schemaRefs) {
|
|
882
|
-
const resolvedSource =
|
|
883
|
-
|
|
884
|
-
|
|
1020
|
+
const resolvedSource = path4.relative(
|
|
1021
|
+
path4.dirname(entryFile),
|
|
1022
|
+
path4.resolve(path4.dirname(file), ref.importSource)
|
|
885
1023
|
).replace(/\\/g, "/");
|
|
886
1024
|
const sourceSpecifier = resolvedSource.startsWith(".") ? resolvedSource : `./${resolvedSource}`;
|
|
887
1025
|
if (!bySource2.has(sourceSpecifier))
|
|
@@ -927,9 +1065,9 @@ function buildNodeReexports(srcDir, entryFile) {
|
|
|
927
1065
|
}
|
|
928
1066
|
const bySource = /* @__PURE__ */ new Map();
|
|
929
1067
|
for (const ref of schemaRefs) {
|
|
930
|
-
const resolvedSource =
|
|
931
|
-
|
|
932
|
-
|
|
1068
|
+
const resolvedSource = path4.relative(
|
|
1069
|
+
path4.dirname(entryFile),
|
|
1070
|
+
path4.resolve(path4.dirname(file), ref.importSource)
|
|
933
1071
|
).replace(/\\/g, "/");
|
|
934
1072
|
const sourceSpecifier = resolvedSource.startsWith(".") ? resolvedSource : `./${resolvedSource}`;
|
|
935
1073
|
if (!bySource.has(sourceSpecifier)) bySource.set(sourceSpecifier, []);
|
|
@@ -943,12 +1081,12 @@ function buildNodeReexports(srcDir, entryFile) {
|
|
|
943
1081
|
}
|
|
944
1082
|
function typeGenerator(options) {
|
|
945
1083
|
const { srcDir, outDir, entryFiles } = options;
|
|
946
|
-
const serverTsconfig =
|
|
947
|
-
const rootTsconfig =
|
|
948
|
-
const userTsconfig =
|
|
949
|
-
const clientDir =
|
|
1084
|
+
const serverTsconfig = path4.resolve(srcDir, "tsconfig.json");
|
|
1085
|
+
const rootTsconfig = path4.resolve("tsconfig.json");
|
|
1086
|
+
const userTsconfig = fs5.existsSync(serverTsconfig) ? serverTsconfig : rootTsconfig;
|
|
1087
|
+
const clientDir = path4.relative(
|
|
950
1088
|
process.cwd(),
|
|
951
|
-
|
|
1089
|
+
path4.join(path4.dirname(srcDir), "client")
|
|
952
1090
|
);
|
|
953
1091
|
const augmentedContents = /* @__PURE__ */ new Map();
|
|
954
1092
|
let origReadFile = null;
|
|
@@ -960,9 +1098,9 @@ function typeGenerator(options) {
|
|
|
960
1098
|
for (const entryFile of entryFiles) {
|
|
961
1099
|
const reexports = buildNodeReexports(srcDir, entryFile);
|
|
962
1100
|
if (!reexports) continue;
|
|
963
|
-
const original =
|
|
1101
|
+
const original = fs5.readFileSync(entryFile, "utf-8");
|
|
964
1102
|
augmentedContents.set(
|
|
965
|
-
|
|
1103
|
+
path4.resolve(entryFile),
|
|
966
1104
|
`${original}
|
|
967
1105
|
${reexports}
|
|
968
1106
|
`
|
|
@@ -971,7 +1109,7 @@ ${reexports}
|
|
|
971
1109
|
if (augmentedContents.size === 0) return;
|
|
972
1110
|
origReadFile = ts.sys.readFile.bind(ts.sys);
|
|
973
1111
|
ts.sys.readFile = (fileName, encoding) => {
|
|
974
|
-
const resolved =
|
|
1112
|
+
const resolved = path4.resolve(fileName);
|
|
975
1113
|
return augmentedContents.get(resolved) ?? origReadFile(fileName, encoding);
|
|
976
1114
|
};
|
|
977
1115
|
},
|
|
@@ -995,7 +1133,7 @@ ${reexports}
|
|
|
995
1133
|
}
|
|
996
1134
|
},
|
|
997
1135
|
outDir,
|
|
998
|
-
...
|
|
1136
|
+
...fs5.existsSync(userTsconfig) && { tsconfigPath: userTsconfig },
|
|
999
1137
|
compilerOptions: {
|
|
1000
1138
|
noEmit: false,
|
|
1001
1139
|
declaration: true,
|
|
@@ -1068,8 +1206,8 @@ function esmWrapper() {
|
|
|
1068
1206
|
}
|
|
1069
1207
|
|
|
1070
1208
|
// src/vite/server/plugins/package-json-generator.ts
|
|
1071
|
-
import
|
|
1072
|
-
import
|
|
1209
|
+
import fs6 from "fs";
|
|
1210
|
+
import path5 from "path";
|
|
1073
1211
|
import { builtinModules as builtinModules2 } from "node:module";
|
|
1074
1212
|
var nodeBuiltins = /* @__PURE__ */ new Set([
|
|
1075
1213
|
...builtinModules2,
|
|
@@ -1158,13 +1296,13 @@ function packageJsonGenerator(options) {
|
|
|
1158
1296
|
}
|
|
1159
1297
|
},
|
|
1160
1298
|
closeBundle() {
|
|
1161
|
-
const rootPackageJsonPath =
|
|
1162
|
-
if (!
|
|
1299
|
+
const rootPackageJsonPath = path5.resolve("./package.json");
|
|
1300
|
+
if (!fs6.existsSync(rootPackageJsonPath)) {
|
|
1163
1301
|
logger.warn(`package.json not found: ${rootPackageJsonPath}`);
|
|
1164
1302
|
return;
|
|
1165
1303
|
}
|
|
1166
1304
|
const rootPackageJson = JSON.parse(
|
|
1167
|
-
|
|
1305
|
+
fs6.readFileSync(rootPackageJsonPath, "utf-8")
|
|
1168
1306
|
);
|
|
1169
1307
|
const sourceDeps = rootPackageJson.dependencies ?? {};
|
|
1170
1308
|
const peerDeps = rootPackageJson.peerDependencies ?? {};
|
|
@@ -1176,12 +1314,12 @@ function packageJsonGenerator(options) {
|
|
|
1176
1314
|
if (sourceDeps[dep]) {
|
|
1177
1315
|
distDependencies[dep] = sourceDeps[dep];
|
|
1178
1316
|
} else {
|
|
1179
|
-
const dependencyPackageJsonPath =
|
|
1317
|
+
const dependencyPackageJsonPath = path5.resolve(
|
|
1180
1318
|
`./node_modules/${dep}/package.json`
|
|
1181
1319
|
);
|
|
1182
|
-
if (
|
|
1320
|
+
if (fs6.existsSync(dependencyPackageJsonPath)) {
|
|
1183
1321
|
const dependencyPackageJson = JSON.parse(
|
|
1184
|
-
|
|
1322
|
+
fs6.readFileSync(dependencyPackageJsonPath, "utf-8")
|
|
1185
1323
|
);
|
|
1186
1324
|
distDependencies[dep] = `^${dependencyPackageJson.version}`;
|
|
1187
1325
|
}
|
|
@@ -1218,11 +1356,11 @@ function packageJsonGenerator(options) {
|
|
|
1218
1356
|
}
|
|
1219
1357
|
}
|
|
1220
1358
|
}
|
|
1221
|
-
if (!
|
|
1222
|
-
|
|
1359
|
+
if (!fs6.existsSync(outDir)) {
|
|
1360
|
+
fs6.mkdirSync(outDir, { recursive: true });
|
|
1223
1361
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1362
|
+
fs6.writeFileSync(
|
|
1363
|
+
path5.join(outDir, "package.json"),
|
|
1226
1364
|
JSON.stringify(distPackageJson, null, 2)
|
|
1227
1365
|
);
|
|
1228
1366
|
}
|
|
@@ -1241,11 +1379,11 @@ async function build(serverOpts, buildContext) {
|
|
|
1241
1379
|
nodeTarget = "node22"
|
|
1242
1380
|
} = serverOpts;
|
|
1243
1381
|
const entries = Array.isArray(entry) ? entry : [entry];
|
|
1244
|
-
const resolvedSrcDir =
|
|
1382
|
+
const resolvedSrcDir = path6.resolve(srcDir);
|
|
1245
1383
|
const entryPoints = {};
|
|
1246
1384
|
for (const entry2 of entries) {
|
|
1247
|
-
const entryFilePath =
|
|
1248
|
-
if (
|
|
1385
|
+
const entryFilePath = path6.join(resolvedSrcDir, entry2);
|
|
1386
|
+
if (fs7.existsSync(entryFilePath)) {
|
|
1249
1387
|
const fileName = entry2.replace(/\.ts$/, "");
|
|
1250
1388
|
entryPoints[fileName] = entryFilePath;
|
|
1251
1389
|
}
|
|
@@ -1321,7 +1459,7 @@ module.exports = function (RED) {
|
|
|
1321
1459
|
});
|
|
1322
1460
|
};
|
|
1323
1461
|
`;
|
|
1324
|
-
|
|
1462
|
+
fs7.writeFileSync(path6.join(buildContext.outDir, "index.js"), bridgeCode);
|
|
1325
1463
|
}
|
|
1326
1464
|
} catch (error) {
|
|
1327
1465
|
throw new BuildError("server", error);
|
|
@@ -1331,12 +1469,12 @@ module.exports = function (RED) {
|
|
|
1331
1469
|
// src/vite/client/build.ts
|
|
1332
1470
|
import { build as viteBuild2 } from "vite";
|
|
1333
1471
|
import vue from "@vitejs/plugin-vue";
|
|
1334
|
-
import
|
|
1335
|
-
import
|
|
1472
|
+
import fs13 from "fs";
|
|
1473
|
+
import path12 from "path";
|
|
1336
1474
|
|
|
1337
1475
|
// src/vite/client/plugins/help-generator.ts
|
|
1338
|
-
import
|
|
1339
|
-
import
|
|
1476
|
+
import fs8 from "fs";
|
|
1477
|
+
import path7 from "path";
|
|
1340
1478
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
1341
1479
|
import { createRequire as createRequire2 } from "module";
|
|
1342
1480
|
|
|
@@ -1658,9 +1796,9 @@ ${table}
|
|
|
1658
1796
|
`;
|
|
1659
1797
|
}
|
|
1660
1798
|
function loadNodeLabels(labelPath) {
|
|
1661
|
-
if (!
|
|
1799
|
+
if (!fs8.existsSync(labelPath)) return {};
|
|
1662
1800
|
try {
|
|
1663
|
-
const raw = JSON.parse(
|
|
1801
|
+
const raw = JSON.parse(fs8.readFileSync(labelPath, "utf-8"));
|
|
1664
1802
|
return {
|
|
1665
1803
|
description: raw.description,
|
|
1666
1804
|
configs: raw.configs,
|
|
@@ -1702,10 +1840,10 @@ function generateHelpDoc(nodeClass, labels, t) {
|
|
|
1702
1840
|
if (inputSection) lines.push(inputSection);
|
|
1703
1841
|
}
|
|
1704
1842
|
if (nodeClass.outputsSchema) {
|
|
1705
|
-
const
|
|
1706
|
-
if (Array.isArray(
|
|
1843
|
+
const os3 = nodeClass.outputsSchema;
|
|
1844
|
+
if (Array.isArray(os3)) {
|
|
1707
1845
|
const portSections = [];
|
|
1708
|
-
|
|
1846
|
+
os3.forEach((schema, i) => {
|
|
1709
1847
|
const title = `${t.sections.port} ${i + 1}`;
|
|
1710
1848
|
const portPropLabels = labels.outputs?.[i];
|
|
1711
1849
|
const section = generateSchemaSection({
|
|
@@ -1724,9 +1862,9 @@ function generateHelpDoc(nodeClass, labels, t) {
|
|
|
1724
1862
|
${portSections.join("\n")}`
|
|
1725
1863
|
);
|
|
1726
1864
|
}
|
|
1727
|
-
} else if (!("type" in
|
|
1865
|
+
} else if (!("type" in os3 || "properties" in os3)) {
|
|
1728
1866
|
const portSections = [];
|
|
1729
|
-
for (const [portName, schema] of Object.entries(
|
|
1867
|
+
for (const [portName, schema] of Object.entries(os3)) {
|
|
1730
1868
|
const portPropLabels = labels.outputs?.[portName];
|
|
1731
1869
|
const section = generateSchemaSection({
|
|
1732
1870
|
title: portName,
|
|
@@ -1748,7 +1886,7 @@ ${portSections.join("\n")}`
|
|
|
1748
1886
|
const outputPropLabels = labels.outputs?.[0];
|
|
1749
1887
|
const section = generateSchemaSection({
|
|
1750
1888
|
title: t.sections.output,
|
|
1751
|
-
schema:
|
|
1889
|
+
schema: os3,
|
|
1752
1890
|
t,
|
|
1753
1891
|
labels: outputPropLabels,
|
|
1754
1892
|
includeDefault: false
|
|
@@ -1759,9 +1897,9 @@ ${portSections.join("\n")}`
|
|
|
1759
1897
|
return lines.join("\n").trim();
|
|
1760
1898
|
}
|
|
1761
1899
|
function discoverLanguages(labelsDir, nodeType) {
|
|
1762
|
-
const nodeLabelsDir =
|
|
1763
|
-
if (!
|
|
1764
|
-
return
|
|
1900
|
+
const nodeLabelsDir = path7.join(labelsDir, nodeType);
|
|
1901
|
+
if (!fs8.existsSync(nodeLabelsDir)) return [];
|
|
1902
|
+
return fs8.readdirSync(nodeLabelsDir).filter((f) => f.endsWith(".json")).map((f) => path7.basename(f, ".json"));
|
|
1765
1903
|
}
|
|
1766
1904
|
function helpGenerator(options) {
|
|
1767
1905
|
const { outDir, localesOutDir, docsDir, labelsDir } = options;
|
|
@@ -1770,15 +1908,15 @@ function helpGenerator(options) {
|
|
|
1770
1908
|
apply: "build",
|
|
1771
1909
|
enforce: "post",
|
|
1772
1910
|
async closeBundle() {
|
|
1773
|
-
const esmPath =
|
|
1774
|
-
const cjsPath =
|
|
1911
|
+
const esmPath = path7.resolve(outDir, "index.mjs");
|
|
1912
|
+
const cjsPath = path7.resolve(outDir, "index.js");
|
|
1775
1913
|
let packageFn;
|
|
1776
1914
|
try {
|
|
1777
|
-
if (
|
|
1915
|
+
if (fs8.existsSync(esmPath)) {
|
|
1778
1916
|
const fileUrl = pathToFileURL2(esmPath).href + `?t=${Date.now()}`;
|
|
1779
1917
|
const mod = await import(fileUrl);
|
|
1780
1918
|
packageFn = mod?.default ?? mod;
|
|
1781
|
-
} else if (
|
|
1919
|
+
} else if (fs8.existsSync(cjsPath)) {
|
|
1782
1920
|
const require2 = createRequire2(import.meta.url);
|
|
1783
1921
|
delete require2.cache[cjsPath];
|
|
1784
1922
|
const rawMod = require2(cjsPath);
|
|
@@ -1795,10 +1933,10 @@ function helpGenerator(options) {
|
|
|
1795
1933
|
const languages = discoverLanguages(labelsDir, type);
|
|
1796
1934
|
if (!languages.includes("en-US")) languages.push("en-US");
|
|
1797
1935
|
for (const lang of languages) {
|
|
1798
|
-
const manualMd =
|
|
1799
|
-
const manualHtml =
|
|
1800
|
-
if (
|
|
1801
|
-
const labelPath =
|
|
1936
|
+
const manualMd = path7.join(docsDir, type, `${lang}.md`);
|
|
1937
|
+
const manualHtml = path7.join(docsDir, type, `${lang}.html`);
|
|
1938
|
+
if (fs8.existsSync(manualMd) || fs8.existsSync(manualHtml)) continue;
|
|
1939
|
+
const labelPath = path7.join(labelsDir, type, `${lang}.json`);
|
|
1802
1940
|
const labels = loadNodeLabels(labelPath);
|
|
1803
1941
|
const t = getHelpTranslations(lang);
|
|
1804
1942
|
const content = generateHelpDoc(NodeClass, labels, t);
|
|
@@ -1812,11 +1950,11 @@ ${content}
|
|
|
1812
1950
|
}
|
|
1813
1951
|
}
|
|
1814
1952
|
for (const [lang, scripts] of helpByLang) {
|
|
1815
|
-
const langDir =
|
|
1816
|
-
|
|
1817
|
-
const indexPath =
|
|
1818
|
-
const existing =
|
|
1819
|
-
|
|
1953
|
+
const langDir = path7.join(localesOutDir, lang);
|
|
1954
|
+
fs8.mkdirSync(langDir, { recursive: true });
|
|
1955
|
+
const indexPath = path7.join(langDir, "index.html");
|
|
1956
|
+
const existing = fs8.existsSync(indexPath) ? fs8.readFileSync(indexPath, "utf-8") : "";
|
|
1957
|
+
fs8.writeFileSync(
|
|
1820
1958
|
indexPath,
|
|
1821
1959
|
existing + (existing ? "\n" : "") + scripts.join("\n"),
|
|
1822
1960
|
"utf-8"
|
|
@@ -1828,8 +1966,8 @@ ${content}
|
|
|
1828
1966
|
|
|
1829
1967
|
// src/vite/client/plugins/html-generator.ts
|
|
1830
1968
|
import mime from "mime-types";
|
|
1831
|
-
import
|
|
1832
|
-
import
|
|
1969
|
+
import fs9 from "fs";
|
|
1970
|
+
import path8 from "path";
|
|
1833
1971
|
function htmlGenerator(options) {
|
|
1834
1972
|
const { packageName, licensePath } = options;
|
|
1835
1973
|
return {
|
|
@@ -1839,7 +1977,7 @@ function htmlGenerator(options) {
|
|
|
1839
1977
|
generateBundle(_, bundle) {
|
|
1840
1978
|
const resourcesTags = Object.keys(bundle).map((fileName) => {
|
|
1841
1979
|
const asset = bundle[fileName];
|
|
1842
|
-
const srcPath =
|
|
1980
|
+
const srcPath = path8.join(
|
|
1843
1981
|
"resources",
|
|
1844
1982
|
packageName,
|
|
1845
1983
|
fileName.replace(/^resources\/?/, "")
|
|
@@ -1867,8 +2005,8 @@ function htmlGenerator(options) {
|
|
|
1867
2005
|
return null;
|
|
1868
2006
|
}
|
|
1869
2007
|
}).filter(Boolean).join("\n");
|
|
1870
|
-
const licenseBanner = licensePath &&
|
|
1871
|
-
${
|
|
2008
|
+
const licenseBanner = licensePath && fs9.existsSync(licensePath) ? `<!--
|
|
2009
|
+
${fs9.readFileSync(licensePath, "utf-8")}
|
|
1872
2010
|
-->` : "";
|
|
1873
2011
|
this.emitFile({
|
|
1874
2012
|
type: "asset",
|
|
@@ -1881,8 +2019,8 @@ ${resourcesTags}`
|
|
|
1881
2019
|
}
|
|
1882
2020
|
|
|
1883
2021
|
// src/vite/client/plugins/locales-generator.ts
|
|
1884
|
-
import
|
|
1885
|
-
import
|
|
2022
|
+
import fs10 from "fs";
|
|
2023
|
+
import path9 from "path";
|
|
1886
2024
|
import { merge } from "es-toolkit";
|
|
1887
2025
|
function localesGenerator(options) {
|
|
1888
2026
|
const { outDir, docsDir, labelsDir } = options;
|
|
@@ -1900,103 +2038,113 @@ function localesGenerator(options) {
|
|
|
1900
2038
|
];
|
|
1901
2039
|
const frameworkLabels = {
|
|
1902
2040
|
"en-US": {
|
|
1903
|
-
configs: { name: "Name" },
|
|
2041
|
+
configs: { name: "Name", returnProperty: "Return key" },
|
|
1904
2042
|
toggles: {
|
|
1905
2043
|
validateInput: "Validate Input",
|
|
1906
2044
|
validateOutput: "Validate Output",
|
|
1907
2045
|
errorPort: "Error Port",
|
|
1908
2046
|
completePort: "Complete Port",
|
|
1909
|
-
statusPort: "Status Port"
|
|
2047
|
+
statusPort: "Status Port",
|
|
2048
|
+
returnPropertyOverride: "Override return prop key"
|
|
1910
2049
|
}
|
|
1911
2050
|
},
|
|
1912
2051
|
de: {
|
|
1913
|
-
configs: { name: "Name" },
|
|
2052
|
+
configs: { name: "Name", returnProperty: "R\xFCckgabe-Schl\xFCssel" },
|
|
1914
2053
|
toggles: {
|
|
1915
2054
|
validateInput: "Eingabe validieren",
|
|
1916
2055
|
validateOutput: "Ausgabe validieren",
|
|
1917
2056
|
errorPort: "Fehler-Port",
|
|
1918
2057
|
completePort: "Abschluss-Port",
|
|
1919
|
-
statusPort: "Status-Port"
|
|
2058
|
+
statusPort: "Status-Port",
|
|
2059
|
+
returnPropertyOverride: "R\xFCckgabe-Schl\xFCssel \xFCberschreiben"
|
|
1920
2060
|
}
|
|
1921
2061
|
},
|
|
1922
2062
|
"es-ES": {
|
|
1923
|
-
configs: { name: "Nombre" },
|
|
2063
|
+
configs: { name: "Nombre", returnProperty: "Clave de retorno" },
|
|
1924
2064
|
toggles: {
|
|
1925
2065
|
validateInput: "Validar entrada",
|
|
1926
2066
|
validateOutput: "Validar salida",
|
|
1927
2067
|
errorPort: "Puerto de error",
|
|
1928
2068
|
completePort: "Puerto de completado",
|
|
1929
|
-
statusPort: "Puerto de estado"
|
|
2069
|
+
statusPort: "Puerto de estado",
|
|
2070
|
+
returnPropertyOverride: "Sobrescribir clave de retorno"
|
|
1930
2071
|
}
|
|
1931
2072
|
},
|
|
1932
2073
|
fr: {
|
|
1933
|
-
configs: { name: "Nom" },
|
|
2074
|
+
configs: { name: "Nom", returnProperty: "Cl\xE9 de retour" },
|
|
1934
2075
|
toggles: {
|
|
1935
2076
|
validateInput: "Valider l'entr\xE9e",
|
|
1936
2077
|
validateOutput: "Valider la sortie",
|
|
1937
2078
|
errorPort: "Port d'erreur",
|
|
1938
2079
|
completePort: "Port de compl\xE9tion",
|
|
1939
|
-
statusPort: "Port de statut"
|
|
2080
|
+
statusPort: "Port de statut",
|
|
2081
|
+
returnPropertyOverride: "Remplacer la cl\xE9 de retour"
|
|
1940
2082
|
}
|
|
1941
2083
|
},
|
|
1942
2084
|
ko: {
|
|
1943
|
-
configs: { name: "\uC774\uB984" },
|
|
2085
|
+
configs: { name: "\uC774\uB984", returnProperty: "\uBC18\uD658 \uD0A4" },
|
|
1944
2086
|
toggles: {
|
|
1945
2087
|
validateInput: "\uC785\uB825 \uAC80\uC99D",
|
|
1946
2088
|
validateOutput: "\uCD9C\uB825 \uAC80\uC99D",
|
|
1947
2089
|
errorPort: "\uC624\uB958 \uD3EC\uD2B8",
|
|
1948
2090
|
completePort: "\uC644\uB8CC \uD3EC\uD2B8",
|
|
1949
|
-
statusPort: "\uC0C1\uD0DC \uD3EC\uD2B8"
|
|
2091
|
+
statusPort: "\uC0C1\uD0DC \uD3EC\uD2B8",
|
|
2092
|
+
returnPropertyOverride: "\uBC18\uD658 \uD0A4 \uC7AC\uC815\uC758"
|
|
1950
2093
|
}
|
|
1951
2094
|
},
|
|
1952
2095
|
"pt-BR": {
|
|
1953
|
-
configs: { name: "Nome" },
|
|
2096
|
+
configs: { name: "Nome", returnProperty: "Chave de retorno" },
|
|
1954
2097
|
toggles: {
|
|
1955
2098
|
validateInput: "Validar Entrada",
|
|
1956
2099
|
validateOutput: "Validar Sa\xEDda",
|
|
1957
2100
|
errorPort: "Porta de Erro",
|
|
1958
2101
|
completePort: "Porta de Conclus\xE3o",
|
|
1959
|
-
statusPort: "Porta de Status"
|
|
2102
|
+
statusPort: "Porta de Status",
|
|
2103
|
+
returnPropertyOverride: "Sobrescrever chave de retorno"
|
|
1960
2104
|
}
|
|
1961
2105
|
},
|
|
1962
2106
|
ru: {
|
|
1963
|
-
configs: { name: "\u0418\u043C\u044F" },
|
|
2107
|
+
configs: { name: "\u0418\u043C\u044F", returnProperty: "\u041A\u043B\u044E\u0447 \u0432\u043E\u0437\u0432\u0440\u0430\u0442\u0430" },
|
|
1964
2108
|
toggles: {
|
|
1965
2109
|
validateInput: "\u041F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0432\u0445\u043E\u0434",
|
|
1966
2110
|
validateOutput: "\u041F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0432\u044B\u0445\u043E\u0434",
|
|
1967
2111
|
errorPort: "\u041F\u043E\u0440\u0442 \u043E\u0448\u0438\u0431\u043A\u0438",
|
|
1968
2112
|
completePort: "\u041F\u043E\u0440\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F",
|
|
1969
|
-
statusPort: "\u041F\u043E\u0440\u0442 \u0441\u0442\u0430\u0442\u0443\u0441\u0430"
|
|
2113
|
+
statusPort: "\u041F\u043E\u0440\u0442 \u0441\u0442\u0430\u0442\u0443\u0441\u0430",
|
|
2114
|
+
returnPropertyOverride: "\u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u044C \u043A\u043B\u044E\u0447 \u0432\u043E\u0437\u0432\u0440\u0430\u0442\u0430"
|
|
1970
2115
|
}
|
|
1971
2116
|
},
|
|
1972
2117
|
ja: {
|
|
1973
|
-
configs: { name: "\u540D\u524D" },
|
|
2118
|
+
configs: { name: "\u540D\u524D", returnProperty: "\u623B\u308A\u30AD\u30FC" },
|
|
1974
2119
|
toggles: {
|
|
1975
2120
|
validateInput: "\u5165\u529B\u691C\u8A3C",
|
|
1976
2121
|
validateOutput: "\u51FA\u529B\u691C\u8A3C",
|
|
1977
2122
|
errorPort: "\u30A8\u30E9\u30FC\u30DD\u30FC\u30C8",
|
|
1978
2123
|
completePort: "\u5B8C\u4E86\u30DD\u30FC\u30C8",
|
|
1979
|
-
statusPort: "\u30B9\u30C6\u30FC\u30BF\u30B9\u30DD\u30FC\u30C8"
|
|
2124
|
+
statusPort: "\u30B9\u30C6\u30FC\u30BF\u30B9\u30DD\u30FC\u30C8",
|
|
2125
|
+
returnPropertyOverride: "\u623B\u308A\u30AD\u30FC\u3092\u4E0A\u66F8\u304D"
|
|
1980
2126
|
}
|
|
1981
2127
|
},
|
|
1982
2128
|
"zh-CN": {
|
|
1983
|
-
configs: { name: "\u540D\u79F0" },
|
|
2129
|
+
configs: { name: "\u540D\u79F0", returnProperty: "\u8FD4\u56DE\u952E" },
|
|
1984
2130
|
toggles: {
|
|
1985
2131
|
validateInput: "\u9A8C\u8BC1\u8F93\u5165",
|
|
1986
2132
|
validateOutput: "\u9A8C\u8BC1\u8F93\u51FA",
|
|
1987
2133
|
errorPort: "\u9519\u8BEF\u7AEF\u53E3",
|
|
1988
2134
|
completePort: "\u5B8C\u6210\u7AEF\u53E3",
|
|
1989
|
-
statusPort: "\u72B6\u6001\u7AEF\u53E3"
|
|
2135
|
+
statusPort: "\u72B6\u6001\u7AEF\u53E3",
|
|
2136
|
+
returnPropertyOverride: "\u8986\u76D6\u8FD4\u56DE\u952E"
|
|
1990
2137
|
}
|
|
1991
2138
|
},
|
|
1992
2139
|
"zh-TW": {
|
|
1993
|
-
configs: { name: "\u540D\u7A31" },
|
|
2140
|
+
configs: { name: "\u540D\u7A31", returnProperty: "\u8FD4\u56DE\u9375" },
|
|
1994
2141
|
toggles: {
|
|
1995
2142
|
validateInput: "\u9A57\u8B49\u8F38\u5165",
|
|
1996
2143
|
validateOutput: "\u9A57\u8B49\u8F38\u51FA",
|
|
1997
2144
|
errorPort: "\u932F\u8AA4\u7AEF\u53E3",
|
|
1998
2145
|
completePort: "\u5B8C\u6210\u7AEF\u53E3",
|
|
1999
|
-
statusPort: "\u72C0\u614B\u7AEF\u53E3"
|
|
2146
|
+
statusPort: "\u72C0\u614B\u7AEF\u53E3",
|
|
2147
|
+
returnPropertyOverride: "\u8986\u84CB\u8FD4\u56DE\u9375"
|
|
2000
2148
|
}
|
|
2001
2149
|
}
|
|
2002
2150
|
};
|
|
@@ -2015,17 +2163,17 @@ Supported: ${languages.join(", ")}`
|
|
|
2015
2163
|
}
|
|
2016
2164
|
function forEachFile(baseDir, fileExtensions, processFile) {
|
|
2017
2165
|
const langMap = /* @__PURE__ */ new Map();
|
|
2018
|
-
if (!
|
|
2019
|
-
const nodeDirs =
|
|
2166
|
+
if (!fs10.existsSync(baseDir)) return langMap;
|
|
2167
|
+
const nodeDirs = fs10.readdirSync(baseDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
2020
2168
|
for (const nodeDir of nodeDirs) {
|
|
2021
2169
|
const nodeType = nodeDir.name;
|
|
2022
|
-
const nodePath =
|
|
2023
|
-
const files =
|
|
2170
|
+
const nodePath = path9.join(baseDir, nodeType);
|
|
2171
|
+
const files = fs10.readdirSync(nodePath);
|
|
2024
2172
|
for (const file of files) {
|
|
2025
|
-
const ext =
|
|
2173
|
+
const ext = path9.extname(file);
|
|
2026
2174
|
if (!fileExtensions.includes(ext)) continue;
|
|
2027
|
-
const lang =
|
|
2028
|
-
const filePath =
|
|
2175
|
+
const lang = path9.basename(file, ext);
|
|
2176
|
+
const filePath = path9.join(nodePath, file);
|
|
2029
2177
|
validateLanguage(lang, filePath);
|
|
2030
2178
|
const value = processFile({ ext, filePath, nodeType });
|
|
2031
2179
|
if (value == null) continue;
|
|
@@ -2043,10 +2191,10 @@ Supported: ${languages.join(", ")}`
|
|
|
2043
2191
|
}
|
|
2044
2192
|
function writeOutput(langMap, fileName, serialize) {
|
|
2045
2193
|
for (const [lang, data] of langMap.entries()) {
|
|
2046
|
-
const langOutDir =
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2194
|
+
const langOutDir = path9.join(outDir, lang);
|
|
2195
|
+
fs10.mkdirSync(langOutDir, { recursive: true });
|
|
2196
|
+
fs10.writeFileSync(
|
|
2197
|
+
path9.join(langOutDir, fileName),
|
|
2050
2198
|
serialize(data),
|
|
2051
2199
|
"utf-8"
|
|
2052
2200
|
);
|
|
@@ -2058,7 +2206,7 @@ Supported: ${languages.join(", ")}`
|
|
|
2058
2206
|
({ ext, filePath, nodeType }) => {
|
|
2059
2207
|
const type = ext === ".html" ? "text/html" : ext === ".md" ? "text/markdown" : null;
|
|
2060
2208
|
if (!type) return null;
|
|
2061
|
-
const content =
|
|
2209
|
+
const content = fs10.readFileSync(filePath, "utf-8");
|
|
2062
2210
|
return [
|
|
2063
2211
|
`<script type="${type}" data-help-name="${nodeType}">
|
|
2064
2212
|
${content}
|
|
@@ -2075,7 +2223,7 @@ ${content}
|
|
|
2075
2223
|
labelsDir,
|
|
2076
2224
|
[".json"],
|
|
2077
2225
|
({ filePath, nodeType }) => {
|
|
2078
|
-
const parsed = JSON.parse(
|
|
2226
|
+
const parsed = JSON.parse(fs10.readFileSync(filePath, "utf-8"));
|
|
2079
2227
|
if (parsed[nodeType] && typeof parsed[nodeType] === "object") {
|
|
2080
2228
|
console.warn(
|
|
2081
2229
|
`[locales] Warning: "${filePath}" uses nested format (root key "${nodeType}"). Label files should be flat \u2014 the node type is added automatically. See https://bonsaedev.github.io/nrg/guide/building-and-running`
|
|
@@ -2125,8 +2273,8 @@ function minifier() {
|
|
|
2125
2273
|
// src/vite/client/plugins/node-definitions-inliner.ts
|
|
2126
2274
|
import { createRequire as createRequire3 } from "module";
|
|
2127
2275
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
2128
|
-
import
|
|
2129
|
-
import
|
|
2276
|
+
import path10 from "path";
|
|
2277
|
+
import fs11 from "fs";
|
|
2130
2278
|
import mime2 from "mime-types";
|
|
2131
2279
|
var VIRTUAL_ID = "virtual:nrg/node-definitions";
|
|
2132
2280
|
var RESOLVED_ID = "\0" + VIRTUAL_ID;
|
|
@@ -2157,9 +2305,9 @@ function getCredentialsFromSchema(schema) {
|
|
|
2157
2305
|
return result;
|
|
2158
2306
|
}
|
|
2159
2307
|
function resolveIcon(iconsDir, type) {
|
|
2160
|
-
if (!
|
|
2161
|
-
return
|
|
2162
|
-
if (
|
|
2308
|
+
if (!fs11.existsSync(iconsDir)) return void 0;
|
|
2309
|
+
return fs11.readdirSync(iconsDir).find((f) => {
|
|
2310
|
+
if (path10.basename(f, path10.extname(f)) !== type) return false;
|
|
2163
2311
|
const mimeType = mime2.lookup(f);
|
|
2164
2312
|
return mimeType !== false && mimeType.startsWith("image/");
|
|
2165
2313
|
});
|
|
@@ -2167,7 +2315,7 @@ function resolveIcon(iconsDir, type) {
|
|
|
2167
2315
|
function nodeDefinitionsInliner(serverOutDir, entryPath, iconsDir, componentsDir, nodesDir, hasUserEntry = true) {
|
|
2168
2316
|
let _nodeTypes = [];
|
|
2169
2317
|
let _definitions = {};
|
|
2170
|
-
const cacheDir =
|
|
2318
|
+
const cacheDir = path10.resolve("node_modules", ".nrg", "client");
|
|
2171
2319
|
return {
|
|
2172
2320
|
name: "vite-plugin-node-red:client:node-definitions-inliner",
|
|
2173
2321
|
enforce: "pre",
|
|
@@ -2176,14 +2324,14 @@ function nodeDefinitionsInliner(serverOutDir, entryPath, iconsDir, componentsDir
|
|
|
2176
2324
|
async buildStart() {
|
|
2177
2325
|
_nodeTypes = [];
|
|
2178
2326
|
_definitions = {};
|
|
2179
|
-
const esmEntryPath =
|
|
2180
|
-
const cjsEntryPath =
|
|
2327
|
+
const esmEntryPath = path10.resolve(serverOutDir, "index.mjs");
|
|
2328
|
+
const cjsEntryPath = path10.resolve(serverOutDir, "index.js");
|
|
2181
2329
|
let packageFn;
|
|
2182
|
-
if (
|
|
2330
|
+
if (fs11.existsSync(esmEntryPath)) {
|
|
2183
2331
|
const fileUrl = pathToFileURL3(esmEntryPath).href + `?t=${Date.now()}`;
|
|
2184
2332
|
const mod = await import(fileUrl);
|
|
2185
2333
|
packageFn = mod?.default ?? mod;
|
|
2186
|
-
} else if (
|
|
2334
|
+
} else if (fs11.existsSync(cjsEntryPath)) {
|
|
2187
2335
|
const require2 = createRequire3(import.meta.url);
|
|
2188
2336
|
delete require2.cache[cjsEntryPath];
|
|
2189
2337
|
const rawMod = require2(cjsEntryPath);
|
|
@@ -2224,14 +2372,14 @@ function nodeDefinitionsInliner(serverOutDir, entryPath, iconsDir, componentsDir
|
|
|
2224
2372
|
};
|
|
2225
2373
|
}
|
|
2226
2374
|
if (!hasUserEntry) {
|
|
2227
|
-
const nodesCache =
|
|
2228
|
-
if (
|
|
2229
|
-
|
|
2375
|
+
const nodesCache = path10.resolve(cacheDir, "nodes");
|
|
2376
|
+
if (fs11.existsSync(nodesCache)) {
|
|
2377
|
+
fs11.rmSync(nodesCache, { recursive: true });
|
|
2230
2378
|
}
|
|
2231
|
-
|
|
2379
|
+
fs11.mkdirSync(nodesCache, { recursive: true });
|
|
2232
2380
|
for (const type of _nodeTypes) {
|
|
2233
|
-
const userTsPath = nodesDir ?
|
|
2234
|
-
if (userTsPath &&
|
|
2381
|
+
const userTsPath = nodesDir ? path10.resolve(nodesDir, `${type}.ts`) : null;
|
|
2382
|
+
if (userTsPath && fs11.existsSync(userTsPath)) continue;
|
|
2235
2383
|
const content = [
|
|
2236
2384
|
`// auto-generated by nrg`,
|
|
2237
2385
|
`import { defineNode } from "@bonsae/nrg/client";`,
|
|
@@ -2241,13 +2389,13 @@ function nodeDefinitionsInliner(serverOutDir, entryPath, iconsDir, componentsDir
|
|
|
2241
2389
|
`});`,
|
|
2242
2390
|
``
|
|
2243
2391
|
].join("\n");
|
|
2244
|
-
|
|
2392
|
+
fs11.writeFileSync(path10.resolve(nodesCache, `${type}.ts`), content);
|
|
2245
2393
|
}
|
|
2246
2394
|
const entryContent = generateEntryCode("");
|
|
2247
|
-
|
|
2395
|
+
fs11.mkdirSync(path10.dirname(path10.resolve(cacheDir, "index.ts")), {
|
|
2248
2396
|
recursive: true
|
|
2249
2397
|
});
|
|
2250
|
-
|
|
2398
|
+
fs11.writeFileSync(path10.resolve(cacheDir, "index.ts"), entryContent);
|
|
2251
2399
|
}
|
|
2252
2400
|
},
|
|
2253
2401
|
resolveId(id) {
|
|
@@ -2270,12 +2418,12 @@ function nodeDefinitionsInliner(serverOutDir, entryPath, iconsDir, componentsDir
|
|
|
2270
2418
|
const nrgImports = /* @__PURE__ */ new Set(["__setSchemas"]);
|
|
2271
2419
|
const lines = [`import __nrgSchemas from "${VIRTUAL_ID}";`];
|
|
2272
2420
|
const postLines = [`__setSchemas(__nrgSchemas);`];
|
|
2273
|
-
if (componentsDir &&
|
|
2421
|
+
if (componentsDir && fs11.existsSync(componentsDir)) {
|
|
2274
2422
|
const formImports = [];
|
|
2275
2423
|
const formEntries = [];
|
|
2276
2424
|
for (const type of _nodeTypes) {
|
|
2277
|
-
const componentPath =
|
|
2278
|
-
if (
|
|
2425
|
+
const componentPath = path10.resolve(componentsDir, `${type}.vue`);
|
|
2426
|
+
if (fs11.existsSync(componentPath)) {
|
|
2279
2427
|
const varName = `__nrgForm_${type.replace(/-/g, "_")}`;
|
|
2280
2428
|
formImports.push(
|
|
2281
2429
|
`import ${varName} from ${JSON.stringify(componentPath)};`
|
|
@@ -2290,12 +2438,12 @@ function nodeDefinitionsInliner(serverOutDir, entryPath, iconsDir, componentsDir
|
|
|
2290
2438
|
}
|
|
2291
2439
|
}
|
|
2292
2440
|
if (!hasUserEntry) {
|
|
2293
|
-
const nodesCache =
|
|
2441
|
+
const nodesCache = path10.resolve(cacheDir, "nodes");
|
|
2294
2442
|
const defVarNames = [];
|
|
2295
2443
|
for (const type of _nodeTypes) {
|
|
2296
2444
|
const varName = `__nrgNodeDef_${type.replace(/-/g, "_")}`;
|
|
2297
|
-
const userTsPath = nodesDir ?
|
|
2298
|
-
const tsPath = userTsPath &&
|
|
2445
|
+
const userTsPath = nodesDir ? path10.resolve(nodesDir, `${type}.ts`) : null;
|
|
2446
|
+
const tsPath = userTsPath && fs11.existsSync(userTsPath) ? userTsPath : path10.resolve(nodesCache, `${type}.ts`);
|
|
2299
2447
|
lines.push(`import ${varName} from ${JSON.stringify(tsPath)};`);
|
|
2300
2448
|
defVarNames.push(varName);
|
|
2301
2449
|
}
|
|
@@ -2313,8 +2461,8 @@ function nodeDefinitionsInliner(serverOutDir, entryPath, iconsDir, componentsDir
|
|
|
2313
2461
|
}
|
|
2314
2462
|
|
|
2315
2463
|
// src/vite/client/plugins/static-copy.ts
|
|
2316
|
-
import
|
|
2317
|
-
import
|
|
2464
|
+
import fs12 from "fs";
|
|
2465
|
+
import path11 from "path";
|
|
2318
2466
|
function staticCopy(options) {
|
|
2319
2467
|
const { targets } = options;
|
|
2320
2468
|
return {
|
|
@@ -2323,23 +2471,23 @@ function staticCopy(options) {
|
|
|
2323
2471
|
enforce: "post",
|
|
2324
2472
|
closeBundle() {
|
|
2325
2473
|
for (const { src, dest } of targets) {
|
|
2326
|
-
if (!
|
|
2327
|
-
|
|
2328
|
-
const stat =
|
|
2474
|
+
if (!fs12.existsSync(src)) continue;
|
|
2475
|
+
fs12.mkdirSync(dest, { recursive: true });
|
|
2476
|
+
const stat = fs12.statSync(src);
|
|
2329
2477
|
if (stat.isDirectory()) {
|
|
2330
|
-
const files =
|
|
2478
|
+
const files = fs12.readdirSync(src);
|
|
2331
2479
|
for (const file of files) {
|
|
2332
|
-
const srcFile =
|
|
2333
|
-
const destFile =
|
|
2334
|
-
const fileStat =
|
|
2480
|
+
const srcFile = path11.join(src, file);
|
|
2481
|
+
const destFile = path11.join(dest, file);
|
|
2482
|
+
const fileStat = fs12.statSync(srcFile);
|
|
2335
2483
|
if (fileStat.isDirectory()) {
|
|
2336
|
-
|
|
2484
|
+
fs12.cpSync(srcFile, destFile, { recursive: true });
|
|
2337
2485
|
} else {
|
|
2338
|
-
|
|
2486
|
+
fs12.copyFileSync(srcFile, destFile);
|
|
2339
2487
|
}
|
|
2340
2488
|
}
|
|
2341
2489
|
} else {
|
|
2342
|
-
|
|
2490
|
+
fs12.copyFileSync(src, dest);
|
|
2343
2491
|
}
|
|
2344
2492
|
}
|
|
2345
2493
|
}
|
|
@@ -2360,74 +2508,74 @@ async function build2(clientBuildOptions, buildContext) {
|
|
|
2360
2508
|
globals = {},
|
|
2361
2509
|
manualChunks
|
|
2362
2510
|
} = clientBuildOptions;
|
|
2363
|
-
const physicalEntryPath =
|
|
2511
|
+
const physicalEntryPath = path12.resolve(srcDir, entry);
|
|
2364
2512
|
let entryPath;
|
|
2365
2513
|
let generatedEntry = false;
|
|
2366
|
-
if (
|
|
2514
|
+
if (fs13.existsSync(physicalEntryPath)) {
|
|
2367
2515
|
entryPath = physicalEntryPath;
|
|
2368
2516
|
} else {
|
|
2369
|
-
const cacheDir =
|
|
2370
|
-
const cachedEntryPath =
|
|
2371
|
-
if (!
|
|
2372
|
-
|
|
2517
|
+
const cacheDir = path12.resolve("node_modules", ".nrg", "client");
|
|
2518
|
+
const cachedEntryPath = path12.resolve(cacheDir, entry);
|
|
2519
|
+
if (!fs13.existsSync(cacheDir)) {
|
|
2520
|
+
fs13.mkdirSync(cacheDir, { recursive: true });
|
|
2373
2521
|
}
|
|
2374
|
-
|
|
2522
|
+
fs13.writeFileSync(cachedEntryPath, "// auto-generated entry\n");
|
|
2375
2523
|
entryPath = cachedEntryPath;
|
|
2376
2524
|
generatedEntry = true;
|
|
2377
2525
|
}
|
|
2378
|
-
const iconsDir =
|
|
2379
|
-
staticDirs.icons ??
|
|
2526
|
+
const iconsDir = path12.resolve(
|
|
2527
|
+
staticDirs.icons ?? path12.join(path12.dirname(path12.resolve(srcDir)), "icons")
|
|
2380
2528
|
);
|
|
2381
2529
|
const plugins = [
|
|
2382
2530
|
vue(),
|
|
2383
2531
|
nodeDefinitionsInliner(
|
|
2384
2532
|
buildContext.outDir,
|
|
2385
2533
|
entryPath,
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2534
|
+
fs13.existsSync(iconsDir) ? iconsDir : void 0,
|
|
2535
|
+
path12.resolve(srcDir, "components"),
|
|
2536
|
+
path12.resolve(srcDir, "nodes"),
|
|
2389
2537
|
!generatedEntry
|
|
2390
2538
|
)
|
|
2391
2539
|
];
|
|
2392
2540
|
plugins.push(
|
|
2393
2541
|
htmlGenerator({
|
|
2394
2542
|
packageName: buildContext.packageName,
|
|
2395
|
-
licensePath: licensePath ?
|
|
2543
|
+
licensePath: licensePath ? path12.resolve(licensePath) : void 0
|
|
2396
2544
|
})
|
|
2397
2545
|
);
|
|
2398
2546
|
if (locales) {
|
|
2399
2547
|
const { docsDir = "./locales/docs", labelsDir = "./locales/labels" } = locales;
|
|
2400
|
-
const localesOutDir =
|
|
2548
|
+
const localesOutDir = path12.join(buildContext.outDir, "locales");
|
|
2401
2549
|
plugins.push(
|
|
2402
2550
|
localesGenerator({
|
|
2403
2551
|
outDir: localesOutDir,
|
|
2404
|
-
docsDir:
|
|
2405
|
-
labelsDir:
|
|
2552
|
+
docsDir: path12.resolve(docsDir),
|
|
2553
|
+
labelsDir: path12.resolve(labelsDir)
|
|
2406
2554
|
})
|
|
2407
2555
|
);
|
|
2408
2556
|
plugins.push(
|
|
2409
2557
|
helpGenerator({
|
|
2410
2558
|
outDir: buildContext.outDir,
|
|
2411
2559
|
localesOutDir,
|
|
2412
|
-
docsDir:
|
|
2413
|
-
labelsDir:
|
|
2560
|
+
docsDir: path12.resolve(docsDir),
|
|
2561
|
+
labelsDir: path12.resolve(labelsDir)
|
|
2414
2562
|
})
|
|
2415
2563
|
);
|
|
2416
2564
|
}
|
|
2417
2565
|
const copyTargets = [];
|
|
2418
|
-
const publicDir =
|
|
2419
|
-
staticDirs.public ??
|
|
2566
|
+
const publicDir = path12.resolve(
|
|
2567
|
+
staticDirs.public ?? path12.join(srcDir, "public")
|
|
2420
2568
|
);
|
|
2421
|
-
if (
|
|
2569
|
+
if (fs13.existsSync(publicDir)) {
|
|
2422
2570
|
copyTargets.push({
|
|
2423
2571
|
src: publicDir,
|
|
2424
|
-
dest:
|
|
2572
|
+
dest: path12.join(buildContext.outDir, "resources")
|
|
2425
2573
|
});
|
|
2426
2574
|
}
|
|
2427
|
-
if (
|
|
2575
|
+
if (fs13.existsSync(iconsDir)) {
|
|
2428
2576
|
copyTargets.push({
|
|
2429
2577
|
src: iconsDir,
|
|
2430
|
-
dest:
|
|
2578
|
+
dest: path12.join(buildContext.outDir, "icons")
|
|
2431
2579
|
});
|
|
2432
2580
|
}
|
|
2433
2581
|
if (copyTargets.length > 0) {
|
|
@@ -2455,10 +2603,10 @@ async function build2(clientBuildOptions, buildContext) {
|
|
|
2455
2603
|
configFile: false,
|
|
2456
2604
|
logLevel: "warn",
|
|
2457
2605
|
base: `/resources/${buildContext.packageName}`,
|
|
2458
|
-
publicDir:
|
|
2606
|
+
publicDir: path12.resolve(srcDir, "public"),
|
|
2459
2607
|
resolve: {
|
|
2460
2608
|
alias: {
|
|
2461
|
-
"@":
|
|
2609
|
+
"@": path12.resolve(srcDir)
|
|
2462
2610
|
}
|
|
2463
2611
|
},
|
|
2464
2612
|
plugins,
|
|
@@ -2512,8 +2660,8 @@ async function build2(clientBuildOptions, buildContext) {
|
|
|
2512
2660
|
throw new BuildError("client", error);
|
|
2513
2661
|
} finally {
|
|
2514
2662
|
if (generatedEntry) {
|
|
2515
|
-
if (
|
|
2516
|
-
|
|
2663
|
+
if (fs13.existsSync(entryPath)) {
|
|
2664
|
+
fs13.unlinkSync(entryPath);
|
|
2517
2665
|
}
|
|
2518
2666
|
}
|
|
2519
2667
|
}
|
|
@@ -2558,7 +2706,7 @@ function serverPlugin(options) {
|
|
|
2558
2706
|
logger.stopSpinner("Copied extra files");
|
|
2559
2707
|
}
|
|
2560
2708
|
};
|
|
2561
|
-
const
|
|
2709
|
+
const start2 = async (clean = false) => {
|
|
2562
2710
|
if (isStarting) {
|
|
2563
2711
|
pendingStart = true;
|
|
2564
2712
|
return;
|
|
@@ -2591,7 +2739,7 @@ function serverPlugin(options) {
|
|
|
2591
2739
|
} finally {
|
|
2592
2740
|
isStarting = false;
|
|
2593
2741
|
if (pendingStart) {
|
|
2594
|
-
|
|
2742
|
+
start2(false);
|
|
2595
2743
|
}
|
|
2596
2744
|
}
|
|
2597
2745
|
};
|
|
@@ -2664,7 +2812,7 @@ function serverPlugin(options) {
|
|
|
2664
2812
|
async configureServer(viteServer) {
|
|
2665
2813
|
server = viteServer;
|
|
2666
2814
|
logger.intro();
|
|
2667
|
-
await
|
|
2815
|
+
await start2(true);
|
|
2668
2816
|
initialStartDone = true;
|
|
2669
2817
|
printServerUrls(server.config.server.port ?? 5173, {
|
|
2670
2818
|
actual: nodeRedPort,
|
|
@@ -2672,20 +2820,20 @@ function serverPlugin(options) {
|
|
|
2672
2820
|
});
|
|
2673
2821
|
logger.startGroup("Node-RED");
|
|
2674
2822
|
nodeRedLauncher.flushLogs();
|
|
2675
|
-
const serverSrcDir =
|
|
2823
|
+
const serverSrcDir = path13.resolve(
|
|
2676
2824
|
serverBuildOptions.srcDir ?? "./server"
|
|
2677
2825
|
);
|
|
2678
|
-
const clientSrcDir =
|
|
2826
|
+
const clientSrcDir = path13.resolve(
|
|
2679
2827
|
clientBuildOptions.srcDir ?? "./client"
|
|
2680
2828
|
);
|
|
2681
|
-
const localesDocsDir =
|
|
2829
|
+
const localesDocsDir = path13.resolve(
|
|
2682
2830
|
clientBuildOptions.locales?.docsDir ?? "./locales/docs"
|
|
2683
2831
|
);
|
|
2684
|
-
const localesLabelsDir =
|
|
2832
|
+
const localesLabelsDir = path13.resolve(
|
|
2685
2833
|
clientBuildOptions.locales?.labelsDir ?? "./locales/labels"
|
|
2686
2834
|
);
|
|
2687
|
-
const iconsDir =
|
|
2688
|
-
clientBuildOptions.staticDirs?.icons ??
|
|
2835
|
+
const iconsDir = path13.resolve(
|
|
2836
|
+
clientBuildOptions.staticDirs?.icons ?? path13.join(path13.dirname(clientSrcDir), "icons")
|
|
2689
2837
|
);
|
|
2690
2838
|
const watchPaths = [
|
|
2691
2839
|
serverSrcDir,
|
|
@@ -2700,12 +2848,12 @@ function serverPlugin(options) {
|
|
|
2700
2848
|
ignored: ["**/node_modules/**", "**/dist/**", "**/.node-red/**"]
|
|
2701
2849
|
});
|
|
2702
2850
|
const debounceBeforeStart = debounce(
|
|
2703
|
-
() =>
|
|
2851
|
+
() => start2(false),
|
|
2704
2852
|
nodeRedLauncher.restartDelay ?? 1e3
|
|
2705
2853
|
);
|
|
2706
2854
|
const handleFileChange = (file, event) => {
|
|
2707
2855
|
if (!initialStartDone) return;
|
|
2708
|
-
logger.info(`${event}: ${
|
|
2856
|
+
logger.info(`${event}: ${path13.relative(process.cwd(), file)}`);
|
|
2709
2857
|
debounceBeforeStart();
|
|
2710
2858
|
};
|
|
2711
2859
|
watcher.on("change", (file) => handleFileChange(file, "Changed"));
|
|
@@ -2783,22 +2931,23 @@ function buildPlugin(options) {
|
|
|
2783
2931
|
}
|
|
2784
2932
|
|
|
2785
2933
|
// src/vite/plugin.ts
|
|
2786
|
-
function
|
|
2787
|
-
const {
|
|
2934
|
+
function nrg(options = {}) {
|
|
2935
|
+
const { build: build3 = {}, server = {} } = options;
|
|
2936
|
+
const { outDir = DEFAULT_OUTPUT_DIR } = build3;
|
|
2788
2937
|
const clientBuildOptions = mergeOptions(
|
|
2789
2938
|
DEFAULT_CLIENT_BUILD_OPTIONS,
|
|
2790
|
-
|
|
2939
|
+
build3.client
|
|
2791
2940
|
);
|
|
2792
2941
|
const serverBuildOptions = mergeOptions(
|
|
2793
2942
|
DEFAULT_SERVER_BUILD_OPTIONS,
|
|
2794
|
-
|
|
2943
|
+
build3.server
|
|
2795
2944
|
);
|
|
2796
2945
|
const nodeRedLauncherOptions = mergeOptions(
|
|
2797
2946
|
DEFAULT_NODE_RED_LAUNCHER_OPTIONS,
|
|
2798
|
-
|
|
2947
|
+
server.nodeRed
|
|
2799
2948
|
);
|
|
2800
|
-
const extraFilesCopyTargets =
|
|
2801
|
-
const resolvedOutDir =
|
|
2949
|
+
const extraFilesCopyTargets = build3.extraFilesCopyTargets ?? DEFAULT_EXTRA_FILES_COPY_TARGETS;
|
|
2950
|
+
const resolvedOutDir = path14.resolve(outDir);
|
|
2802
2951
|
const buildContext = {
|
|
2803
2952
|
outDir: resolvedOutDir,
|
|
2804
2953
|
packageName: getPackageName(),
|
|
@@ -2825,5 +2974,5 @@ function nodeRed(options = {}) {
|
|
|
2825
2974
|
];
|
|
2826
2975
|
}
|
|
2827
2976
|
export {
|
|
2828
|
-
|
|
2977
|
+
nrg
|
|
2829
2978
|
};
|