@velarscript/cli 0.12.0 → 0.13.0
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 +4 -12
- package/dist/browser-process-owner.d.ts +23 -0
- package/dist/browser-process-owner.d.ts.map +1 -1
- package/dist/browser-process-owner.js +46 -2
- package/dist/browser-process-owner.js.map +1 -1
- package/dist/browser-test-runner.d.ts.map +1 -1
- package/dist/browser-test-runner.js +110 -14
- package/dist/browser-test-runner.js.map +1 -1
- package/dist/cli.js +131 -68
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +28 -4
- package/dist/config.js.map +1 -1
- package/dist/dev-server.d.ts +18 -0
- package/dist/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +168 -8
- package/dist/dev-server.js.map +1 -1
- package/dist/extension-metadata.d.ts +6 -0
- package/dist/extension-metadata.d.ts.map +1 -1
- package/dist/extension-metadata.js +70 -4
- package/dist/extension-metadata.js.map +1 -1
- package/dist/format-guard.d.ts +20 -0
- package/dist/format-guard.d.ts.map +1 -0
- package/dist/format-guard.js +13 -0
- package/dist/format-guard.js.map +1 -0
- package/dist/framework-host.d.ts.map +1 -1
- package/dist/framework-host.js +15 -2
- package/dist/framework-host.js.map +1 -1
- package/dist/language-server-bundle-entry.js +0 -2
- package/dist/language-server-bundle-entry.js.map +1 -1
- package/dist/language-server-tool.d.ts.map +1 -1
- package/dist/language-server-tool.js +0 -2
- package/dist/language-server-tool.js.map +1 -1
- package/dist/language-server.d.ts +1 -1
- package/dist/language-server.d.ts.map +1 -1
- package/dist/language-server.js +87 -293
- package/dist/language-server.js.map +1 -1
- package/dist/local-request-guard.d.ts +18 -0
- package/dist/local-request-guard.d.ts.map +1 -0
- package/dist/local-request-guard.js +75 -0
- package/dist/local-request-guard.js.map +1 -0
- package/dist/mechanical-fixer.d.ts.map +1 -1
- package/dist/mechanical-fixer.js +116 -2
- package/dist/mechanical-fixer.js.map +1 -1
- package/dist/module-assets.d.ts +23 -0
- package/dist/module-assets.d.ts.map +1 -1
- package/dist/module-assets.js +216 -14
- package/dist/module-assets.js.map +1 -1
- package/dist/node-application.d.ts +7 -2
- package/dist/node-application.d.ts.map +1 -1
- package/dist/node-application.js +44 -14
- package/dist/node-application.js.map +1 -1
- package/dist/node-runtime-dependencies.d.ts +2 -0
- package/dist/node-runtime-dependencies.d.ts.map +1 -0
- package/dist/node-runtime-dependencies.js +24 -0
- package/dist/node-runtime-dependencies.js.map +1 -0
- package/dist/npm.d.ts +29 -0
- package/dist/npm.d.ts.map +1 -1
- package/dist/npm.js +39 -2
- package/dist/npm.js.map +1 -1
- package/dist/ownership-graph.d.ts.map +1 -1
- package/dist/ownership-graph.js +155 -38
- package/dist/ownership-graph.js.map +1 -1
- package/dist/package-manager.d.ts.map +1 -1
- package/dist/package-manager.js +4 -1
- package/dist/package-manager.js.map +1 -1
- package/dist/preview-server.d.ts.map +1 -1
- package/dist/preview-server.js +12 -4
- package/dist/preview-server.js.map +1 -1
- package/dist/production-build.d.ts.map +1 -1
- package/dist/production-build.js +24 -6
- package/dist/production-build.js.map +1 -1
- package/dist/production-verifier.js +3 -0
- package/dist/production-verifier.js.map +1 -1
- package/dist/project-check.d.ts +14 -1
- package/dist/project-check.d.ts.map +1 -1
- package/dist/project-check.js +17 -4
- package/dist/project-check.js.map +1 -1
- package/dist/project-format.d.ts +9 -0
- package/dist/project-format.d.ts.map +1 -1
- package/dist/project-format.js +13 -0
- package/dist/project-format.js.map +1 -1
- package/dist/project-semantic.d.ts.map +1 -1
- package/dist/project-semantic.js +15 -4
- package/dist/project-semantic.js.map +1 -1
- package/dist/project.d.ts +25 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +341 -42
- package/dist/project.js.map +1 -1
- package/dist/reproduction.d.ts +18 -0
- package/dist/reproduction.d.ts.map +1 -1
- package/dist/reproduction.js +47 -6
- package/dist/reproduction.js.map +1 -1
- package/dist/stable-order.d.ts +17 -0
- package/dist/stable-order.d.ts.map +1 -0
- package/dist/stable-order.js +19 -0
- package/dist/stable-order.js.map +1 -0
- package/dist/standard-modules.d.ts +2 -2
- package/dist/standard-modules.d.ts.map +1 -1
- package/dist/standard-modules.js +2 -2
- package/dist/standard-modules.js.map +1 -1
- package/dist/static-deployment.d.ts.map +1 -1
- package/dist/static-deployment.js +27 -0
- package/dist/static-deployment.js.map +1 -1
- package/dist/test-runner.d.ts.map +1 -1
- package/dist/test-runner.js +196 -100
- package/dist/test-runner.js.map +1 -1
- package/dist/test-worker.d.ts +64 -0
- package/dist/test-worker.d.ts.map +1 -0
- package/dist/test-worker.js +161 -0
- package/dist/test-worker.js.map +1 -0
- package/dist/typescript-declarations.d.ts +1 -1
- package/dist/typescript-declarations.d.ts.map +1 -1
- package/dist/typescript-declarations.js +233 -21
- package/dist/typescript-declarations.js.map +1 -1
- package/dist/unowned-errors.d.ts +15 -2
- package/dist/unowned-errors.d.ts.map +1 -1
- package/dist/unowned-errors.js +13 -2
- package/dist/unowned-errors.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace-index.d.ts.map +1 -1
- package/dist/workspace-index.js +42 -17
- package/dist/workspace-index.js.map +1 -1
- package/package.json +7 -8
- package/skill/ai-skill-node.md +91 -12
- package/skill/ai-skill-web.md +51 -1
- package/skill/ai-skill.md +36 -13
- package/dist/official-script-language-service.d.ts +0 -2
- package/dist/official-script-language-service.d.ts.map +0 -1
- package/dist/official-script-language-service.js +0 -10
- package/dist/official-script-language-service.js.map +0 -1
- package/dist/official-tool-assets.d.ts +0 -3
- package/dist/official-tool-assets.d.ts.map +0 -1
- package/dist/official-tool-assets.js +0 -60
- package/dist/official-tool-assets.js.map +0 -1
- package/dist/script-language-service.d.ts +0 -82
- package/dist/script-language-service.d.ts.map +0 -1
- package/dist/script-language-service.js +0 -18
- package/dist/script-language-service.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -7,12 +7,10 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
7
7
|
}
|
|
8
8
|
return path;
|
|
9
9
|
};
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { tmpdir } from "node:os";
|
|
10
|
+
import { lstat, mkdir, mkdtemp, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
|
|
11
|
+
import { basename, dirname, extname, isAbsolute, join, parse as parsePath, relative, resolve } from "node:path";
|
|
12
|
+
import { homedir, tmpdir } from "node:os";
|
|
14
13
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
15
|
-
import { formatSource } from "@velarscript/compiler";
|
|
16
14
|
import { createVelarProject, parseCreateArguments } from "create-velar";
|
|
17
15
|
import { projectImportKey } from "./project.js";
|
|
18
16
|
import { checkResolvedProject, discoverVelarSources, formatCheckOutput, projectTestModules } from "./project-check.js";
|
|
@@ -21,10 +19,11 @@ import { runDevServer } from "./dev-server.js";
|
|
|
21
19
|
import { nodeApplicationConfig, nodeApplicationEntry, nodeApplicationLauncherSource, runNodeApplication, runNodeDevelopment, } from "./node-application.js";
|
|
22
20
|
import { createFrameworkArtifacts } from "./framework-host.js";
|
|
23
21
|
import { resolveVelarProject } from "./config.js";
|
|
24
|
-
import {
|
|
22
|
+
import { standardModuleClosure, standardModuleSource, standardModuleSources } from "./standard-modules.js";
|
|
25
23
|
import { runTests } from "./test-runner.js";
|
|
26
24
|
import { runProgram } from "./program-runner.js";
|
|
27
|
-
import { buildProductionFramework, writeProductionManifest } from "./production-build.js";
|
|
25
|
+
import { buildProductionFramework, PRODUCTION_MANIFEST_NAME, writeProductionManifest } from "./production-build.js";
|
|
26
|
+
import { formatSourceChecked } from "./format-guard.js";
|
|
28
27
|
import { VELAR_VERSION } from "./version.js";
|
|
29
28
|
import { assertRequiredPublicAssets, copyPublicAssets, writeStaticDeployment } from "./static-deployment.js";
|
|
30
29
|
import { verifyProductionBuild } from "./production-verifier.js";
|
|
@@ -37,8 +36,8 @@ import { loadApplicationPackageHost, validateApplicationPackageResult } from "./
|
|
|
37
36
|
import { buildLanguageServerTool } from "./language-server-tool.js";
|
|
38
37
|
import { applyProjectMechanicalFixes } from "./mechanical-fixer.js";
|
|
39
38
|
import { bundleStandaloneJavaScript, needsStandaloneJavaScriptBundle } from "./standalone-build.js";
|
|
40
|
-
import { resolveInstalledPackageRoot } from "./installed-package.js";
|
|
41
39
|
import { BUILD_STAGING_MARKER } from "./build-staging.js";
|
|
40
|
+
import { writeWebSocketDependency } from "./node-runtime-dependencies.js";
|
|
42
41
|
import { assertUniqueEmbeddedModuleOutputs, embeddedModuleFileContents, embeddedModuleOutputPath, VELAR_EMBEDDED_MODULE_MARKER, } from "./embedded-modules.js";
|
|
43
42
|
import { resourceOutputRelativePath, writeBuildResourcePackageManifests, writeProjectResources } from "./resource-output.js";
|
|
44
43
|
async function main(arguments_) {
|
|
@@ -338,10 +337,19 @@ async function main(arguments_) {
|
|
|
338
337
|
return 1;
|
|
339
338
|
}
|
|
340
339
|
const changed = [];
|
|
340
|
+
const unstable = [];
|
|
341
341
|
try {
|
|
342
342
|
for (const input of inputs) {
|
|
343
343
|
const source = await readVelarSourceFile(input);
|
|
344
|
-
const formatted =
|
|
344
|
+
const { text: formatted, stable } = formatSourceChecked(source, { extensions: formattingExtensions });
|
|
345
|
+
// Formatting is idempotent by contract. A result the formatter would
|
|
346
|
+
// change again is a formatter defect, and writing it would replace a
|
|
347
|
+
// module that compiles with one that may not, so the file keeps the
|
|
348
|
+
// bytes the author wrote and the command reports the defect.
|
|
349
|
+
if (!stable) {
|
|
350
|
+
unstable.push(input);
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
345
353
|
if (formatted === source)
|
|
346
354
|
continue;
|
|
347
355
|
changed.push(input);
|
|
@@ -353,6 +361,12 @@ async function main(arguments_) {
|
|
|
353
361
|
process.stderr.write(`velar format: ${hostErrorMessage(error)}\n`);
|
|
354
362
|
return 1;
|
|
355
363
|
}
|
|
364
|
+
if (unstable.length > 0) {
|
|
365
|
+
for (const input of unstable) {
|
|
366
|
+
process.stderr.write(`velar format: ${displayPath(input)}: the formatter did not reach a fixed point; the file was left unchanged\n`);
|
|
367
|
+
}
|
|
368
|
+
return 1;
|
|
369
|
+
}
|
|
356
370
|
if (parsed.check && changed.length > 0) {
|
|
357
371
|
for (const input of changed)
|
|
358
372
|
process.stderr.write(`${displayPath(input)} is not formatted\n`);
|
|
@@ -442,7 +456,7 @@ async function main(arguments_) {
|
|
|
442
456
|
}
|
|
443
457
|
return runTests(projectConfig, parsed.input);
|
|
444
458
|
}
|
|
445
|
-
const parsed = command === "package" ? parsePackageArguments(rest) : parseCommandArguments(rest);
|
|
459
|
+
const parsed = command === "package" ? parsePackageArguments(rest) : parseCommandArguments(rest, command === "build");
|
|
446
460
|
if (typeof parsed === "string") {
|
|
447
461
|
process.stderr.write(`velar ${command}: ${parsed}\n`);
|
|
448
462
|
return 2;
|
|
@@ -470,7 +484,13 @@ async function main(arguments_) {
|
|
|
470
484
|
}
|
|
471
485
|
if (command === "check") {
|
|
472
486
|
const count = checked.compiled.size;
|
|
473
|
-
|
|
487
|
+
// D89: a passing check that carried advisories says how many. Folding them
|
|
488
|
+
// into a silent "checked N modules" would hide the one thing the advisory
|
|
489
|
+
// channel exists to make impossible to miss; the exit code stays 0 either
|
|
490
|
+
// way, because an advisory is not a failure.
|
|
491
|
+
const advisories = checked.advisories.length;
|
|
492
|
+
process.stdout.write(`Checked ${count} module${count === 1 ? "" : "s"} from ${displayInput(parsed.input, projectConfig)}`
|
|
493
|
+
+ `${advisories > 0 ? ` — ${advisories} advisor${advisories === 1 ? "y" : "ies"}` : ""}\n`);
|
|
474
494
|
return 0;
|
|
475
495
|
}
|
|
476
496
|
if (command === "package") {
|
|
@@ -490,7 +510,7 @@ async function main(arguments_) {
|
|
|
490
510
|
if (buildRequests > 1)
|
|
491
511
|
throw new Error("application package host requested more than one framework build");
|
|
492
512
|
const outputDirectory = packageFrameworkOutput(projectConfig.root, requestedOutput);
|
|
493
|
-
frameworkBuild = writeFrameworkProductionApplication(project, outputDirectory);
|
|
513
|
+
frameworkBuild = writeFrameworkProductionApplication(project, outputDirectory, { forced: false, declared: false });
|
|
494
514
|
await frameworkBuild;
|
|
495
515
|
},
|
|
496
516
|
});
|
|
@@ -535,9 +555,15 @@ async function main(arguments_) {
|
|
|
535
555
|
return 0;
|
|
536
556
|
}
|
|
537
557
|
const outputDirectory = parsed.outputDirectory ? resolve(parsed.outputDirectory) : projectConfig.outDir;
|
|
558
|
+
// `outDir` is the project manifest's own declaration of a directory velar
|
|
559
|
+
// owns, and config.ts already refuses one that is the project root or that
|
|
560
|
+
// overlaps the entry or the public directory. `--out-dir` carries no such
|
|
561
|
+
// declaration, so a path it names has to prove ownership before the build
|
|
562
|
+
// replaces what is there.
|
|
563
|
+
const replacement = { forced: parsed.force, declared: outputDirectory === projectConfig.outDir };
|
|
538
564
|
if (project.framework) {
|
|
539
565
|
try {
|
|
540
|
-
await writeFrameworkProductionApplication(project, outputDirectory);
|
|
566
|
+
await writeFrameworkProductionApplication(project, outputDirectory, replacement);
|
|
541
567
|
}
|
|
542
568
|
catch (error) {
|
|
543
569
|
process.stderr.write(`velar build: ${hostErrorMessage(error)}\n`);
|
|
@@ -549,7 +575,7 @@ async function main(arguments_) {
|
|
|
549
575
|
const nodeConfig = nodeApplicationConfig(projectConfig);
|
|
550
576
|
if (nodeConfig) {
|
|
551
577
|
try {
|
|
552
|
-
await writeNodeProductionApplication(project, outputDirectory, nodeConfig);
|
|
578
|
+
await writeNodeProductionApplication(project, outputDirectory, nodeConfig, replacement);
|
|
553
579
|
}
|
|
554
580
|
catch (error) {
|
|
555
581
|
process.stderr.write(`velar build: ${hostErrorMessage(error)}\n`);
|
|
@@ -558,7 +584,14 @@ async function main(arguments_) {
|
|
|
558
584
|
process.stdout.write(`Built production Node app -> ${outputDirectory}\n`);
|
|
559
585
|
return 0;
|
|
560
586
|
}
|
|
561
|
-
|
|
587
|
+
let staging;
|
|
588
|
+
try {
|
|
589
|
+
staging = await prepareBuildStaging(outputDirectory, replacement);
|
|
590
|
+
}
|
|
591
|
+
catch (error) {
|
|
592
|
+
process.stderr.write(`velar build: ${hostErrorMessage(error)}\n`);
|
|
593
|
+
return 1;
|
|
594
|
+
}
|
|
562
595
|
try {
|
|
563
596
|
assertUniqueEmbeddedModuleOutputs(project.modules.map((module) => ({
|
|
564
597
|
ownerPath: join(staging, module.relativePath.replace(/\.vel$/, ".js")),
|
|
@@ -582,12 +615,12 @@ async function main(arguments_) {
|
|
|
582
615
|
process.stdout.write(`Built ${project.modules.length} module${project.modules.length === 1 ? "" : "s"} -> ${outputDirectory}\n`);
|
|
583
616
|
return 0;
|
|
584
617
|
}
|
|
585
|
-
async function writeFrameworkProductionApplication(project, outputDirectory) {
|
|
618
|
+
async function writeFrameworkProductionApplication(project, outputDirectory, replacement) {
|
|
586
619
|
if (!project.framework)
|
|
587
620
|
throw new Error("the checked project has no framework host");
|
|
588
621
|
const framework = project.framework;
|
|
589
622
|
await assertRequiredPublicAssets(project.publicRoot, project.projectRoot, framework.host.requiredPublicAssets?.(framework.config) ?? []);
|
|
590
|
-
const staging = await prepareBuildStaging(outputDirectory);
|
|
623
|
+
const staging = await prepareBuildStaging(outputDirectory, replacement);
|
|
591
624
|
try {
|
|
592
625
|
await copyPublicAssets(project.publicRoot, staging);
|
|
593
626
|
const production = await buildProductionFramework(project, staging);
|
|
@@ -608,9 +641,12 @@ async function writeFrameworkProductionApplication(project, outputDirectory) {
|
|
|
608
641
|
throw error;
|
|
609
642
|
}
|
|
610
643
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
644
|
+
/** The receipt a node build leaves in its output; it also proves velar owns the directory. */
|
|
645
|
+
const NODE_BUILD_MANIFEST_NAME = "velar-node.json";
|
|
646
|
+
async function writeNodeProductionApplication(project, outputDirectory, config, replacement) {
|
|
647
|
+
const application = nodeApplicationEntry(project, config);
|
|
648
|
+
const entry = application.entry;
|
|
649
|
+
const staging = await prepareBuildStaging(outputDirectory, replacement);
|
|
614
650
|
try {
|
|
615
651
|
assertUniqueEmbeddedModuleOutputs(project.modules.map((module) => ({
|
|
616
652
|
ownerPath: join(staging, module.relativePath.replace(/\.vel$/u, ".js")),
|
|
@@ -627,9 +663,9 @@ async function writeNodeProductionApplication(project, outputDirectory, config)
|
|
|
627
663
|
await copyPublicAssets(project.publicRoot, join(staging, "public"), true);
|
|
628
664
|
const entryPath = `./${relative(project.sourceRoot, entry.inputPath).replace(/\.vel$/u, ".js").replaceAll("\\", "/")}`;
|
|
629
665
|
const launcher = ".velar-node-entry.mjs";
|
|
630
|
-
await writeFile(join(staging, launcher), nodeApplicationLauncherSource(entryPath, config, {}, false), "utf8");
|
|
666
|
+
await writeFile(join(staging, launcher), nodeApplicationLauncherSource(entryPath, config, {}, false, application.kind), "utf8");
|
|
631
667
|
await writeFile(join(staging, "package.json"), `${JSON.stringify({ name: "velar-node-build", private: true, type: "module" }, null, 2)}\n`, "utf8");
|
|
632
|
-
await writeFile(join(staging,
|
|
668
|
+
await writeFile(join(staging, NODE_BUILD_MANIFEST_NAME), `${JSON.stringify({
|
|
633
669
|
formatVersion: 1,
|
|
634
670
|
kind: "velar-node-build",
|
|
635
671
|
entry: launcher,
|
|
@@ -661,8 +697,9 @@ function packageFrameworkOutput(root, input) {
|
|
|
661
697
|
* output. A process cut can happen before or after either rename, so recovery
|
|
662
698
|
* also finishes restoring the previous output when installation never began.
|
|
663
699
|
*/
|
|
664
|
-
async function prepareBuildStaging(outputDirectory) {
|
|
700
|
+
async function prepareBuildStaging(outputDirectory, replacement) {
|
|
665
701
|
const normalizedOutput = resolve(outputDirectory);
|
|
702
|
+
await assertReplaceableBuildOutput(normalizedOutput, replacement);
|
|
666
703
|
const parent = dirname(normalizedOutput);
|
|
667
704
|
await mkdir(parent, { recursive: true });
|
|
668
705
|
await recoverInterruptedBuilds(normalizedOutput);
|
|
@@ -677,6 +714,67 @@ async function prepareBuildStaging(outputDirectory) {
|
|
|
677
714
|
await writeFile(join(staging, BUILD_STAGING_MARKER), `${JSON.stringify(ownership, null, 2)}\n`, "utf8");
|
|
678
715
|
return staging;
|
|
679
716
|
}
|
|
717
|
+
/**
|
|
718
|
+
* A build replaces its output directory wholesale, so the path is accepted only
|
|
719
|
+
* when velar owns it: absent, empty, carrying a manifest a previous build wrote,
|
|
720
|
+
* or named by the project manifest's own `outDir`. Every other destructive path
|
|
721
|
+
* in this repository makes the same test first — `assertReplaceableReleaseOutput`
|
|
722
|
+
* in scripts/release-toolchain.mjs, `prepareDirectory` in reproduction.ts, and
|
|
723
|
+
* `createVelarProject` — and `--out-dir` was the one an author runs daily that
|
|
724
|
+
* did not. `--force` waives the ownership test and nothing else: the home
|
|
725
|
+
* directory, the filesystem root and a symbolic link stay refused.
|
|
726
|
+
*/
|
|
727
|
+
async function assertReplaceableBuildOutput(outputDirectory, replacement) {
|
|
728
|
+
const directory = resolve(outputDirectory);
|
|
729
|
+
if (directory === parsePath(directory).root || directory === resolve(homedir())) {
|
|
730
|
+
throw new Error(`refusing to replace '${directory}': a build output cannot be the filesystem root or the home directory`);
|
|
731
|
+
}
|
|
732
|
+
let metadata;
|
|
733
|
+
try {
|
|
734
|
+
metadata = await lstat(directory);
|
|
735
|
+
}
|
|
736
|
+
catch (error) {
|
|
737
|
+
if (isHostErrorCode(error, "ENOENT") || isHostErrorCode(error, "ENOTDIR"))
|
|
738
|
+
return;
|
|
739
|
+
throw error;
|
|
740
|
+
}
|
|
741
|
+
if (metadata.isSymbolicLink())
|
|
742
|
+
throw new Error(`refusing to replace '${directory}': it is a symbolic link`);
|
|
743
|
+
if (!metadata.isDirectory())
|
|
744
|
+
throw new Error(`refusing to replace '${directory}': it is not a directory`);
|
|
745
|
+
if (replacement.forced || replacement.declared)
|
|
746
|
+
return;
|
|
747
|
+
if ((await readdir(directory)).length === 0)
|
|
748
|
+
return;
|
|
749
|
+
if (await isBuildOutputDirectory(directory))
|
|
750
|
+
return;
|
|
751
|
+
throw new Error(`refusing to replace '${directory}': it is not empty and was not produced by velar build (pass --force to overwrite)`);
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* The three build shapes leave three different receipts: a framework build
|
|
755
|
+
* writes `velar-build.json`, a node build writes `velar-node.json`, and a build
|
|
756
|
+
* cut between the two renames leaves the staging marker naming this same output.
|
|
757
|
+
*/
|
|
758
|
+
async function isBuildOutputDirectory(directory) {
|
|
759
|
+
if (await buildStagingOwnership(directory, directory, null))
|
|
760
|
+
return true;
|
|
761
|
+
return await buildManifestKind(join(directory, PRODUCTION_MANIFEST_NAME)) === "velar-framework-build"
|
|
762
|
+
|| await buildManifestKind(join(directory, NODE_BUILD_MANIFEST_NAME)) === "velar-node-build";
|
|
763
|
+
}
|
|
764
|
+
async function buildManifestKind(path) {
|
|
765
|
+
try {
|
|
766
|
+
const metadata = await lstat(path);
|
|
767
|
+
if (!metadata.isFile() || metadata.isSymbolicLink())
|
|
768
|
+
return null;
|
|
769
|
+
const parsed = JSON.parse(await readFile(path, "utf8"));
|
|
770
|
+
return Number.isSafeInteger(parsed.formatVersion) && typeof parsed.kind === "string" ? parsed.kind : null;
|
|
771
|
+
}
|
|
772
|
+
catch (error) {
|
|
773
|
+
if (isHostErrorCode(error, "ENOENT") || isHostErrorCode(error, "ENOTDIR") || error instanceof SyntaxError)
|
|
774
|
+
return null;
|
|
775
|
+
throw error;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
680
778
|
async function recoverInterruptedBuilds(outputDirectory) {
|
|
681
779
|
const parent = dirname(outputDirectory);
|
|
682
780
|
const prefix = `.velar-${basename(outputDirectory)}-`;
|
|
@@ -789,7 +887,6 @@ async function writeNodeStandardModules(outputRoot, project, replaceExisting = f
|
|
|
789
887
|
await writeNodeStandardModulePackage(packageRoot, used, project);
|
|
790
888
|
if (used.has("velar/websocket"))
|
|
791
889
|
await writeWebSocketDependency(dirname(packageRoot));
|
|
792
|
-
await writeAdapterDependencies(dirname(packageRoot), used);
|
|
793
890
|
return;
|
|
794
891
|
}
|
|
795
892
|
const ownership = await generatedRuntimePackageOwnership(packageRoot);
|
|
@@ -810,50 +907,12 @@ async function writeNodeStandardModules(outputRoot, project, replaceExisting = f
|
|
|
810
907
|
await rename(staging, packageRoot);
|
|
811
908
|
if (used.has("velar/websocket"))
|
|
812
909
|
await writeWebSocketDependency(dirname(packageRoot));
|
|
813
|
-
await writeAdapterDependencies(dirname(packageRoot), used);
|
|
814
910
|
}
|
|
815
911
|
catch (error) {
|
|
816
912
|
await rm(staging, { recursive: true, force: true });
|
|
817
913
|
throw error;
|
|
818
914
|
}
|
|
819
915
|
}
|
|
820
|
-
async function writeWebSocketDependency(nodeModulesRoot) {
|
|
821
|
-
const target = join(nodeModulesRoot, "ws");
|
|
822
|
-
try {
|
|
823
|
-
const manifest = JSON.parse(await readFile(join(target, "package.json"), "utf8"));
|
|
824
|
-
if (manifest.name !== "ws" || manifest.version !== "8.21.1")
|
|
825
|
-
throw new Error(`Refusing to use incompatible WebSocket runtime package '${target}'`);
|
|
826
|
-
return;
|
|
827
|
-
}
|
|
828
|
-
catch (error) {
|
|
829
|
-
if (!isHostErrorCode(error, "ENOENT"))
|
|
830
|
-
throw error;
|
|
831
|
-
}
|
|
832
|
-
const require = createRequire(import.meta.url);
|
|
833
|
-
const source = dirname(require.resolve("ws/package.json"));
|
|
834
|
-
await cp(source, target, { recursive: true, errorOnExist: true });
|
|
835
|
-
}
|
|
836
|
-
async function writeAdapterDependencies(nodeModulesRoot, used) {
|
|
837
|
-
const require = createRequire(import.meta.url);
|
|
838
|
-
for (const [moduleName, dependency] of STANDARD_MODULE_ADAPTER_DEPENDENCIES) {
|
|
839
|
-
if (!used.has(moduleName))
|
|
840
|
-
continue;
|
|
841
|
-
const target = join(nodeModulesRoot, dependency.packageName);
|
|
842
|
-
try {
|
|
843
|
-
const manifest = JSON.parse(await readFile(join(target, "package.json"), "utf8"));
|
|
844
|
-
if (manifest.name !== dependency.packageName || manifest.version !== dependency.version) {
|
|
845
|
-
throw new Error(`Refusing to use incompatible ${moduleName} runtime package '${target}'`);
|
|
846
|
-
}
|
|
847
|
-
continue;
|
|
848
|
-
}
|
|
849
|
-
catch (error) {
|
|
850
|
-
if (!isHostErrorCode(error, "ENOENT"))
|
|
851
|
-
throw error;
|
|
852
|
-
}
|
|
853
|
-
const source = await resolveInstalledPackageRoot(dependency.packageName, dependency.packageName, require);
|
|
854
|
-
await cp(source, target, { recursive: true, errorOnExist: true });
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
916
|
function requiredNodeStandardModules(project) {
|
|
858
917
|
const sources = standardModuleSources(project.compilerExtensions);
|
|
859
918
|
const roots = new Set(project.modules.flatMap((module) => module.result.dependencies
|
|
@@ -1018,13 +1077,17 @@ function parseFormatArguments(arguments_) {
|
|
|
1018
1077
|
}
|
|
1019
1078
|
return { input, check };
|
|
1020
1079
|
}
|
|
1021
|
-
function parseCommandArguments(arguments_) {
|
|
1080
|
+
function parseCommandArguments(arguments_, allowForce = false) {
|
|
1022
1081
|
let input = null;
|
|
1023
1082
|
let output = null;
|
|
1024
1083
|
let outputDirectory = null;
|
|
1084
|
+
let force = false;
|
|
1025
1085
|
for (let index = 0; index < arguments_.length; index += 1) {
|
|
1026
1086
|
const argument = arguments_[index];
|
|
1027
|
-
if (
|
|
1087
|
+
if (allowForce && argument === "--force") {
|
|
1088
|
+
force = true;
|
|
1089
|
+
}
|
|
1090
|
+
else if (argument === "--out" || argument === "--out-dir") {
|
|
1028
1091
|
const value = arguments_[index + 1];
|
|
1029
1092
|
if (!value || value.startsWith("--")) {
|
|
1030
1093
|
return `${argument} requires a path`;
|
|
@@ -1049,7 +1112,7 @@ function parseCommandArguments(arguments_) {
|
|
|
1049
1112
|
input = argument;
|
|
1050
1113
|
}
|
|
1051
1114
|
}
|
|
1052
|
-
return { input, output, outputDirectory };
|
|
1115
|
+
return { input, output, outputDirectory, force };
|
|
1053
1116
|
}
|
|
1054
1117
|
function parseReproArguments(arguments_) {
|
|
1055
1118
|
let input = null;
|
|
@@ -1089,7 +1152,7 @@ function parsePackageArguments(arguments_) {
|
|
|
1089
1152
|
return `unexpected extra input '${arguments_[1]}'`;
|
|
1090
1153
|
if (arguments_[0]?.startsWith("-"))
|
|
1091
1154
|
return `unknown option '${arguments_[0]}'`;
|
|
1092
|
-
return { input: arguments_[0] ?? null, output: null, outputDirectory: null };
|
|
1155
|
+
return { input: arguments_[0] ?? null, output: null, outputDirectory: null, force: false };
|
|
1093
1156
|
}
|
|
1094
1157
|
function parseDevArguments(arguments_) {
|
|
1095
1158
|
let input = null;
|
|
@@ -1304,7 +1367,7 @@ function printHelp(output = process.stdout) {
|
|
|
1304
1367
|
" velar update [package...]",
|
|
1305
1368
|
" velar dev [entry.vel | project-directory] [--port <port>]",
|
|
1306
1369
|
" velar serve [project-directory] [--host <host>] [--port <port>]",
|
|
1307
|
-
" velar build [entry.vel | project-directory] [--out-dir <directory>]",
|
|
1370
|
+
" velar build [entry.vel | project-directory] [--out-dir <directory>] [--force]",
|
|
1308
1371
|
" velar run [entry.vel | project-directory] [--stack] [-- <program-arguments>...]",
|
|
1309
1372
|
" velar verify [project-directory | build-directory]",
|
|
1310
1373
|
" velar preview [project-directory | build-directory] [--port <port>]",
|
|
@@ -1336,7 +1399,7 @@ function printCommandHelp(command, output = process.stdout) {
|
|
|
1336
1399
|
update: ["Usage: velar update [package...]", "Updates all or selected direct dependencies within package.json ranges through npm."],
|
|
1337
1400
|
dev: ["Usage: velar dev [entry.vel | project-directory] [--port <1-65535>]", "Watches a framework app or last-good Node ServeApp; Web defaults to 5173 and Node reads node.port."],
|
|
1338
1401
|
serve: ["Usage: velar serve [project-directory] [--host <host>] [--port <1-65535>]", "Checks and runs a Node ServeApp with production runtime behavior; node.host and node.port provide the defaults."],
|
|
1339
|
-
build: ["Usage: velar build [entry.vel | project-directory] [--out-dir <directory>]", " velar build <single.vel> --out <file.js>", "Builds isolated Web/Desktop output, a standalone Node application, or JavaScript modules."],
|
|
1402
|
+
build: ["Usage: velar build [entry.vel | project-directory] [--out-dir <directory>] [--force]", " velar build <single.vel> --out <file.js>", "Builds isolated Web/Desktop output, a standalone Node application, or JavaScript modules.", "--out-dir refuses a directory that is not empty and was not produced by a previous build; --force replaces one anyway."],
|
|
1340
1403
|
package: ["Usage: velar package [project-directory]", "Packages an application through its target-owned native packaging host."],
|
|
1341
1404
|
run: ["Usage: velar run [entry.vel | project-directory] [--stack] [-- <program-arguments>...]", "Compiles the resolved Core project and executes its entry module once on Node.js; arguments after '--' reach the program.", "--stack prints the full Node.js trace behind an uncaught program error instead of the VelarScript frames."],
|
|
1342
1405
|
verify: ["Usage: velar verify [project-directory | build-directory]", "Verifies the exact production manifest, inventory, sizes, hashes, and relationships."],
|