@velarscript/cli 0.10.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/LICENSE +201 -0
- package/README.md +117 -0
- package/dist/application-package-host.d.ts +5 -0
- package/dist/application-package-host.d.ts.map +1 -0
- package/dist/application-package-host.js +67 -0
- package/dist/application-package-host.js.map +1 -0
- package/dist/bounded-text.d.ts +2 -0
- package/dist/bounded-text.d.ts.map +1 -0
- package/dist/bounded-text.js +13 -0
- package/dist/bounded-text.js.map +1 -0
- package/dist/browser-process-owner.d.ts +15 -0
- package/dist/browser-process-owner.d.ts.map +1 -0
- package/dist/browser-process-owner.js +151 -0
- package/dist/browser-process-owner.js.map +1 -0
- package/dist/browser-test-runner.d.ts +11 -0
- package/dist/browser-test-runner.d.ts.map +1 -0
- package/dist/browser-test-runner.js +1022 -0
- package/dist/browser-test-runner.js.map +1 -0
- package/dist/build-engine-tool.d.ts +3 -0
- package/dist/build-engine-tool.d.ts.map +1 -0
- package/dist/build-engine-tool.js +34 -0
- package/dist/build-engine-tool.js.map +1 -0
- package/dist/build-staging.d.ts +3 -0
- package/dist/build-staging.d.ts.map +1 -0
- package/dist/build-staging.js +3 -0
- package/dist/build-staging.js.map +1 -0
- package/dist/bundled-application-package-host-registry.d.ts +10 -0
- package/dist/bundled-application-package-host-registry.d.ts.map +1 -0
- package/dist/bundled-application-package-host-registry.js +16 -0
- package/dist/bundled-application-package-host-registry.js.map +1 -0
- package/dist/bundled-extension-registry.d.ts +22 -0
- package/dist/bundled-extension-registry.d.ts.map +1 -0
- package/dist/bundled-extension-registry.js +10 -0
- package/dist/bundled-extension-registry.js.map +1 -0
- package/dist/canonical-path.d.ts +3 -0
- package/dist/canonical-path.d.ts.map +1 -0
- package/dist/canonical-path.js +30 -0
- package/dist/canonical-path.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1274 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +403 -0
- package/dist/config.js.map +1 -0
- package/dist/deployment-verifier.d.ts +34 -0
- package/dist/deployment-verifier.d.ts.map +1 -0
- package/dist/deployment-verifier.js +260 -0
- package/dist/deployment-verifier.js.map +1 -0
- package/dist/dev-server.d.ts +3 -0
- package/dist/dev-server.d.ts.map +1 -0
- package/dist/dev-server.js +464 -0
- package/dist/dev-server.js.map +1 -0
- package/dist/embedded-modules.d.ts +17 -0
- package/dist/embedded-modules.d.ts.map +1 -0
- package/dist/embedded-modules.js +33 -0
- package/dist/embedded-modules.js.map +1 -0
- package/dist/extension-metadata.d.ts +23 -0
- package/dist/extension-metadata.d.ts.map +1 -0
- package/dist/extension-metadata.js +254 -0
- package/dist/extension-metadata.js.map +1 -0
- package/dist/file-integrity.d.ts +7 -0
- package/dist/file-integrity.d.ts.map +1 -0
- package/dist/file-integrity.js +14 -0
- package/dist/file-integrity.js.map +1 -0
- package/dist/framework-host.d.ts +12 -0
- package/dist/framework-host.d.ts.map +1 -0
- package/dist/framework-host.js +46 -0
- package/dist/framework-host.js.map +1 -0
- package/dist/host-error.d.ts +6 -0
- package/dist/host-error.d.ts.map +1 -0
- package/dist/host-error.js +54 -0
- package/dist/host-error.js.map +1 -0
- package/dist/installed-package.d.ts +9 -0
- package/dist/installed-package.d.ts.map +1 -0
- package/dist/installed-package.js +23 -0
- package/dist/installed-package.js.map +1 -0
- package/dist/language-server-bundle-entry.d.ts +2 -0
- package/dist/language-server-bundle-entry.d.ts.map +1 -0
- package/dist/language-server-bundle-entry.js +7 -0
- package/dist/language-server-bundle-entry.js.map +1 -0
- package/dist/language-server-tool.d.ts +3 -0
- package/dist/language-server-tool.d.ts.map +1 -0
- package/dist/language-server-tool.js +30 -0
- package/dist/language-server-tool.js.map +1 -0
- package/dist/language-server.d.ts +9 -0
- package/dist/language-server.d.ts.map +1 -0
- package/dist/language-server.js +1733 -0
- package/dist/language-server.js.map +1 -0
- package/dist/mechanical-fixer.d.ts +30 -0
- package/dist/mechanical-fixer.d.ts.map +1 -0
- package/dist/mechanical-fixer.js +103 -0
- package/dist/mechanical-fixer.js.map +1 -0
- package/dist/module-assets.d.ts +11 -0
- package/dist/module-assets.d.ts.map +1 -0
- package/dist/module-assets.js +90 -0
- package/dist/module-assets.js.map +1 -0
- package/dist/npm.d.ts +23 -0
- package/dist/npm.d.ts.map +1 -0
- package/dist/npm.js +456 -0
- package/dist/npm.js.map +1 -0
- package/dist/official-language-server-extensions.d.ts +2 -0
- package/dist/official-language-server-extensions.d.ts.map +1 -0
- package/dist/official-language-server-extensions.js +38 -0
- package/dist/official-language-server-extensions.js.map +1 -0
- package/dist/official-script-language-service.d.ts +2 -0
- package/dist/official-script-language-service.d.ts.map +1 -0
- package/dist/official-script-language-service.js +10 -0
- package/dist/official-script-language-service.js.map +1 -0
- package/dist/official-tool-assets.d.ts +3 -0
- package/dist/official-tool-assets.d.ts.map +1 -0
- package/dist/official-tool-assets.js +41 -0
- package/dist/official-tool-assets.js.map +1 -0
- package/dist/ownership-graph.d.ts +46 -0
- package/dist/ownership-graph.d.ts.map +1 -0
- package/dist/ownership-graph.js +255 -0
- package/dist/ownership-graph.js.map +1 -0
- package/dist/package-manager.d.ts +20 -0
- package/dist/package-manager.d.ts.map +1 -0
- package/dist/package-manager.js +345 -0
- package/dist/package-manager.js.map +1 -0
- package/dist/packaged-official-tool.d.ts +8 -0
- package/dist/packaged-official-tool.d.ts.map +1 -0
- package/dist/packaged-official-tool.js +32 -0
- package/dist/packaged-official-tool.js.map +1 -0
- package/dist/preview-server.d.ts +11 -0
- package/dist/preview-server.d.ts.map +1 -0
- package/dist/preview-server.js +163 -0
- package/dist/preview-server.js.map +1 -0
- package/dist/production-build.d.ts +57 -0
- package/dist/production-build.d.ts.map +1 -0
- package/dist/production-build.js +332 -0
- package/dist/production-build.js.map +1 -0
- package/dist/production-verifier.d.ts +9 -0
- package/dist/production-verifier.d.ts.map +1 -0
- package/dist/production-verifier.js +268 -0
- package/dist/production-verifier.js.map +1 -0
- package/dist/program-runner.d.ts +7 -0
- package/dist/program-runner.d.ts.map +1 -0
- package/dist/program-runner.js +98 -0
- package/dist/program-runner.js.map +1 -0
- package/dist/project-check.d.ts +31 -0
- package/dist/project-check.d.ts.map +1 -0
- package/dist/project-check.js +95 -0
- package/dist/project-check.js.map +1 -0
- package/dist/project-format.d.ts +6 -0
- package/dist/project-format.d.ts.map +1 -0
- package/dist/project-format.js +21 -0
- package/dist/project-format.js.map +1 -0
- package/dist/project-semantic.d.ts +62 -0
- package/dist/project-semantic.d.ts.map +1 -0
- package/dist/project-semantic.js +1079 -0
- package/dist/project-semantic.js.map +1 -0
- package/dist/project-session.d.ts +36 -0
- package/dist/project-session.d.ts.map +1 -0
- package/dist/project-session.js +339 -0
- package/dist/project-session.js.map +1 -0
- package/dist/project-task-bundle-entry.d.ts +2 -0
- package/dist/project-task-bundle-entry.d.ts.map +1 -0
- package/dist/project-task-bundle-entry.js +18 -0
- package/dist/project-task-bundle-entry.js.map +1 -0
- package/dist/project-task-invocation.d.ts +16 -0
- package/dist/project-task-invocation.d.ts.map +1 -0
- package/dist/project-task-invocation.js +72 -0
- package/dist/project-task-invocation.js.map +1 -0
- package/dist/project-task-tool.d.ts +3 -0
- package/dist/project-task-tool.d.ts.map +1 -0
- package/dist/project-task-tool.js +61 -0
- package/dist/project-task-tool.js.map +1 -0
- package/dist/project.d.ts +71 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +1750 -0
- package/dist/project.js.map +1 -0
- package/dist/reproduction.d.ts +50 -0
- package/dist/reproduction.d.ts.map +1 -0
- package/dist/reproduction.js +321 -0
- package/dist/reproduction.js.map +1 -0
- package/dist/script-language-service.d.ts +82 -0
- package/dist/script-language-service.d.ts.map +1 -0
- package/dist/script-language-service.js +18 -0
- package/dist/script-language-service.js.map +1 -0
- package/dist/source-limits.d.ts +5 -0
- package/dist/source-limits.d.ts.map +1 -0
- package/dist/source-limits.js +19 -0
- package/dist/source-limits.js.map +1 -0
- package/dist/standalone-build.d.ts +15 -0
- package/dist/standalone-build.d.ts.map +1 -0
- package/dist/standalone-build.js +76 -0
- package/dist/standalone-build.js.map +1 -0
- package/dist/standard-modules.d.ts +22 -0
- package/dist/standard-modules.d.ts.map +1 -0
- package/dist/standard-modules.js +3066 -0
- package/dist/standard-modules.js.map +1 -0
- package/dist/static-deployment.d.ts +48 -0
- package/dist/static-deployment.d.ts.map +1 -0
- package/dist/static-deployment.js +142 -0
- package/dist/static-deployment.js.map +1 -0
- package/dist/test-output.d.ts +20 -0
- package/dist/test-output.d.ts.map +1 -0
- package/dist/test-output.js +119 -0
- package/dist/test-output.js.map +1 -0
- package/dist/test-runner.d.ts +13 -0
- package/dist/test-runner.d.ts.map +1 -0
- package/dist/test-runner.js +226 -0
- package/dist/test-runner.js.map +1 -0
- package/dist/typescript-declarations.d.ts +20 -0
- package/dist/typescript-declarations.d.ts.map +1 -0
- package/dist/typescript-declarations.js +1609 -0
- package/dist/typescript-declarations.js.map +1 -0
- package/dist/uncaught-program-error.d.ts +24 -0
- package/dist/uncaught-program-error.d.ts.map +1 -0
- package/dist/uncaught-program-error.js +105 -0
- package/dist/uncaught-program-error.js.map +1 -0
- package/dist/unowned-errors.d.ts +56 -0
- package/dist/unowned-errors.d.ts.map +1 -0
- package/dist/unowned-errors.js +82 -0
- package/dist/unowned-errors.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/dist/workspace-index.d.ts +78 -0
- package/dist/workspace-index.d.ts.map +1 -0
- package/dist/workspace-index.js +493 -0
- package/dist/workspace-index.js.map +1 -0
- package/package.json +45 -0
- package/skill/ai-skill.md +749 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,1274 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
3
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
4
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
5
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
return path;
|
|
9
|
+
};
|
|
10
|
+
import { cp, lstat, mkdir, mkdtemp, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
|
|
11
|
+
import { createRequire } from "node:module";
|
|
12
|
+
import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
13
|
+
import { tmpdir } from "node:os";
|
|
14
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
15
|
+
import { formatSource } from "@velarscript/compiler";
|
|
16
|
+
import { createVelarProject, parseCreateArguments } from "create-velar";
|
|
17
|
+
import { projectImportKey } from "./project.js";
|
|
18
|
+
import { checkResolvedProject, discoverVelarSources, formatCheckOutput, projectTestModules } from "./project-check.js";
|
|
19
|
+
import { reproductionHint, writeReproduction } from "./reproduction.js";
|
|
20
|
+
import { runDevServer } from "./dev-server.js";
|
|
21
|
+
import { createFrameworkArtifacts } from "./framework-host.js";
|
|
22
|
+
import { resolveVelarProject } from "./config.js";
|
|
23
|
+
import { STANDARD_MODULE_ADAPTER_DEPENDENCIES, standardModuleClosure, standardModuleSource, standardModuleSources } from "./standard-modules.js";
|
|
24
|
+
import { runTests } from "./test-runner.js";
|
|
25
|
+
import { runProgram } from "./program-runner.js";
|
|
26
|
+
import { buildProductionFramework, writeProductionManifest } from "./production-build.js";
|
|
27
|
+
import { VELAR_VERSION } from "./version.js";
|
|
28
|
+
import { assertRequiredPublicAssets, copyPublicAssets, writeStaticDeployment } from "./static-deployment.js";
|
|
29
|
+
import { verifyProductionBuild } from "./production-verifier.js";
|
|
30
|
+
import { runProductionPreview } from "./preview-server.js";
|
|
31
|
+
import { createDeploymentVerificationReport, verifyRemoteDeployment } from "./deployment-verifier.js";
|
|
32
|
+
import { readVelarSourceFile } from "./source-limits.js";
|
|
33
|
+
import { parseDependencyArguments, runDependencyCommand } from "./package-manager.js";
|
|
34
|
+
import { hostErrorMessage, isHostErrorCode } from "./host-error.js";
|
|
35
|
+
import { loadApplicationPackageHost, validateApplicationPackageResult } from "./application-package-host.js";
|
|
36
|
+
import { buildLanguageServerTool, VELAR_LANGUAGE_SERVER_TOOL_ID } from "./language-server-tool.js";
|
|
37
|
+
import { buildProjectTaskTool, VELAR_PROJECT_TASK_TOOL_ID } from "./project-task-tool.js";
|
|
38
|
+
import { buildBuildEngineTool, VELAR_BUILD_ENGINE_TOOL_ID } from "./build-engine-tool.js";
|
|
39
|
+
import { applyProjectMechanicalFixes } from "./mechanical-fixer.js";
|
|
40
|
+
import { bundleStandaloneJavaScript, needsStandaloneJavaScriptBundle } from "./standalone-build.js";
|
|
41
|
+
import { resolveInstalledPackageRoot } from "./installed-package.js";
|
|
42
|
+
import { BUILD_STAGING_MARKER } from "./build-staging.js";
|
|
43
|
+
import { assertUniqueEmbeddedModuleOutputs, embeddedModuleFileContents, embeddedModuleOutputPath, VELAR_EMBEDDED_MODULE_MARKER, } from "./embedded-modules.js";
|
|
44
|
+
async function main(arguments_) {
|
|
45
|
+
const [command, ...rest] = arguments_;
|
|
46
|
+
if (!command || command === "--help" || command === "-h") {
|
|
47
|
+
if (rest.length > 0) {
|
|
48
|
+
process.stderr.write("velar help: unexpected arguments after the top-level help option\n");
|
|
49
|
+
return 2;
|
|
50
|
+
}
|
|
51
|
+
printHelp();
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
if (command === "help") {
|
|
55
|
+
if (rest.length === 0) {
|
|
56
|
+
printHelp();
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
if (rest.length !== 1 || !commandNames.has(rest[0])) {
|
|
60
|
+
process.stderr.write(`velar help: unknown command '${rest[0] ?? ""}'\n`);
|
|
61
|
+
return 2;
|
|
62
|
+
}
|
|
63
|
+
printCommandHelp(rest[0]);
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
if (command === "--version" || command === "-v") {
|
|
67
|
+
if (rest.length > 0) {
|
|
68
|
+
process.stderr.write("velar --version: this option does not accept arguments\n");
|
|
69
|
+
return 2;
|
|
70
|
+
}
|
|
71
|
+
process.stdout.write(`velar ${VELAR_VERSION}\n`);
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
if (commandNames.has(command) && helpRequested(command, rest)) {
|
|
75
|
+
printCommandHelp(command);
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
if (command === "lsp") {
|
|
79
|
+
if (rest.length > 0) {
|
|
80
|
+
process.stderr.write("velar lsp: this command does not accept arguments\n");
|
|
81
|
+
return 2;
|
|
82
|
+
}
|
|
83
|
+
const temporary = await mkdtemp(join(tmpdir(), "velar-language-server-"));
|
|
84
|
+
const tool = join(temporary, "language-server.mjs");
|
|
85
|
+
try {
|
|
86
|
+
await buildLanguageServerTool(tool);
|
|
87
|
+
await import(__rewriteRelativeImportExtension(pathToFileURL(tool).href));
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
await rm(temporary, { recursive: true, force: true });
|
|
91
|
+
}
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
if (command === "skill") {
|
|
95
|
+
if (rest.length > 0) {
|
|
96
|
+
process.stderr.write("velar skill: this command does not accept arguments\n");
|
|
97
|
+
return 2;
|
|
98
|
+
}
|
|
99
|
+
process.stdout.write(await readFile(new URL("../skill/ai-skill.md", import.meta.url), "utf8"));
|
|
100
|
+
return 0;
|
|
101
|
+
}
|
|
102
|
+
if (command === "create") {
|
|
103
|
+
const parsed = parseCreateArguments(rest);
|
|
104
|
+
if (typeof parsed === "string") {
|
|
105
|
+
process.stderr.write(`velar create: ${parsed}\n`);
|
|
106
|
+
return 2;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
const result = await createVelarProject(parsed.directory, { template: parsed.template });
|
|
110
|
+
process.stdout.write(`Created VelarScript ${result.template} project -> ${result.root}\n`);
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
process.stderr.write(`velar create: ${hostErrorMessage(error)}\n`);
|
|
115
|
+
return 1;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (command === "install" || command === "add" || command === "remove" || command === "update") {
|
|
119
|
+
const parsed = parseDependencyArguments(command, rest);
|
|
120
|
+
if (typeof parsed === "string") {
|
|
121
|
+
process.stderr.write(`velar ${command}: ${parsed}\n`);
|
|
122
|
+
return 2;
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const result = await runDependencyCommand(command, parsed);
|
|
126
|
+
process.stdout.write(dependencyResultMessage(command, result.root, result.packages, result.activatedExtensions, result.removedExtensions));
|
|
127
|
+
return 0;
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
process.stderr.write(`velar ${command}: ${hostErrorMessage(error)}\n`);
|
|
131
|
+
return 1;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (command === "verify") {
|
|
135
|
+
const input = parseSingleOptionalInput(rest);
|
|
136
|
+
if (input !== null && typeof input === "object") {
|
|
137
|
+
process.stderr.write(`velar verify: ${input.error}\n`);
|
|
138
|
+
return 2;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
const verified = await verifyProductionBuild(input);
|
|
142
|
+
process.stdout.write(`Verified production ${verified.manifest.framework.capability} build ${verified.manifest.buildId} -> ${verified.directory}\n`);
|
|
143
|
+
return 0;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
process.stderr.write(`velar verify: ${hostErrorMessage(error)}\n`);
|
|
147
|
+
return 1;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (command === "preview") {
|
|
151
|
+
const parsed = parsePreviewArguments(rest);
|
|
152
|
+
if (typeof parsed === "string") {
|
|
153
|
+
process.stderr.write(`velar preview: ${parsed}\n`);
|
|
154
|
+
return 2;
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
const verified = await verifyProductionBuild(parsed.input);
|
|
158
|
+
await runProductionPreview(verified, parsed.port);
|
|
159
|
+
return 0;
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
process.stderr.write(`velar preview: ${hostErrorMessage(error)}\n`);
|
|
163
|
+
return 1;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (command === "verify-deployment") {
|
|
167
|
+
const parsed = parseDeploymentVerificationArguments(rest);
|
|
168
|
+
if (typeof parsed === "string") {
|
|
169
|
+
process.stderr.write(`velar verify-deployment: ${parsed}\n`);
|
|
170
|
+
return 2;
|
|
171
|
+
}
|
|
172
|
+
const url = parsed.url ?? process.env.VELAR_DEPLOYMENT_URL?.trim() ?? "";
|
|
173
|
+
if (!url) {
|
|
174
|
+
process.stderr.write("velar verify-deployment: provide --url <deployment-origin> or VELAR_DEPLOYMENT_URL\n");
|
|
175
|
+
return 2;
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const verified = await verifyProductionBuild(parsed.input);
|
|
179
|
+
const deployment = await verifyRemoteDeployment(verified, url);
|
|
180
|
+
if (parsed.json) {
|
|
181
|
+
process.stdout.write(`${JSON.stringify(createDeploymentVerificationReport(verified, deployment), null, 2)}\n`);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
process.stdout.write(`Verified deployed ${verified.manifest.framework.capability} build ${deployment.buildId} at ${deployment.url} `
|
|
185
|
+
+ `(${deployment.checkedFiles} files, ${deployment.checkedRoutes} routes, ${deployment.checkedHeaders} headers)\n`);
|
|
186
|
+
}
|
|
187
|
+
return 0;
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
process.stderr.write(`velar verify-deployment: ${hostErrorMessage(error)}\n`);
|
|
191
|
+
return 1;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (command === "run") {
|
|
195
|
+
const parsed = parseRunArguments(rest);
|
|
196
|
+
if (typeof parsed === "string") {
|
|
197
|
+
process.stderr.write(`velar run: ${parsed}\n`);
|
|
198
|
+
return 2;
|
|
199
|
+
}
|
|
200
|
+
let projectConfig;
|
|
201
|
+
try {
|
|
202
|
+
projectConfig = await resolveVelarProject(parsed.input);
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
process.stderr.write(`velar run: ${hostErrorMessage(error)}\n`);
|
|
206
|
+
return 1;
|
|
207
|
+
}
|
|
208
|
+
if (projectConfig.framework) {
|
|
209
|
+
process.stderr.write(`velar run: this project enables the '${projectConfig.framework.host.id}' application framework; use 'velar dev' or 'velar build' instead\n`);
|
|
210
|
+
return 1;
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
return await runProgram(projectConfig, parsed.programArguments, { fullStack: parsed.fullStack });
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
process.stderr.write(`velar run: ${hostErrorMessage(error)}\n`);
|
|
217
|
+
return 1;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (command === "fix") {
|
|
221
|
+
const input = parseSingleOptionalInput(rest);
|
|
222
|
+
if (input !== null && typeof input === "object") {
|
|
223
|
+
process.stderr.write(`velar fix: ${input.error}\n`);
|
|
224
|
+
return 2;
|
|
225
|
+
}
|
|
226
|
+
let fixConfig;
|
|
227
|
+
try {
|
|
228
|
+
fixConfig = await resolveVelarProject(input);
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
process.stderr.write(`velar fix: ${hostErrorMessage(error)}\n`);
|
|
232
|
+
return 1;
|
|
233
|
+
}
|
|
234
|
+
let report;
|
|
235
|
+
try {
|
|
236
|
+
report = await applyProjectMechanicalFixes(fixConfig, displayPath, 8, await projectTestModules(fixConfig));
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
process.stderr.write(`velar fix: ${hostErrorMessage(error)}\n`);
|
|
240
|
+
return 1;
|
|
241
|
+
}
|
|
242
|
+
for (const change of report.changes)
|
|
243
|
+
process.stdout.write(`${change}\n`);
|
|
244
|
+
if (report.remainingDiagnostics.length > 0)
|
|
245
|
+
process.stderr.write(`${report.remainingDiagnostics.join("\n\n")}\n`);
|
|
246
|
+
// D51 item NEW-D8: a write that failed is named, and the summary that says
|
|
247
|
+
// what did change is printed either way — a rewritten tree is never left
|
|
248
|
+
// unreported.
|
|
249
|
+
for (const failure of report.writeFailures)
|
|
250
|
+
process.stderr.write(`velar fix: could not write ${failure}\n`);
|
|
251
|
+
const files = report.changedFiles.length;
|
|
252
|
+
process.stdout.write(`applied ${report.changes.length} mechanical fix${report.changes.length === 1 ? "" : "es"}`
|
|
253
|
+
+ `${files > 0 ? ` in ${files} file${files === 1 ? "" : "s"}` : ""}`
|
|
254
|
+
+ `${report.writeFailures.length > 0 ? `; ${report.writeFailures.length} file${report.writeFailures.length === 1 ? "" : "s"} could not be written` : ""}`
|
|
255
|
+
+ `; ${report.remainingDiagnostics.length} diagnostic${report.remainingDiagnostics.length === 1 ? " remains" : "s remain"}\n`);
|
|
256
|
+
return report.remainingDiagnostics.length > 0 || report.writeFailures.length > 0 ? 1 : 0;
|
|
257
|
+
}
|
|
258
|
+
if (command === "repro") {
|
|
259
|
+
const parsed = parseReproArguments(rest);
|
|
260
|
+
if (typeof parsed === "string") {
|
|
261
|
+
process.stderr.write(`velar repro: ${parsed}\n`);
|
|
262
|
+
return 2;
|
|
263
|
+
}
|
|
264
|
+
let reproConfig;
|
|
265
|
+
try {
|
|
266
|
+
reproConfig = await resolveVelarProject(parsed.input);
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
process.stderr.write(`velar repro: ${hostErrorMessage(error)}\n`);
|
|
270
|
+
return 1;
|
|
271
|
+
}
|
|
272
|
+
try {
|
|
273
|
+
const checked = await checkResolvedProject(reproConfig, parsed.input);
|
|
274
|
+
if (checked.errors.length === 0) {
|
|
275
|
+
process.stderr.write(`velar repro: ${displayInput(parsed.input, reproConfig)} checks without errors; there is no failure to reproduce\n`);
|
|
276
|
+
return 1;
|
|
277
|
+
}
|
|
278
|
+
const reproduction = await writeReproduction({
|
|
279
|
+
config: reproConfig,
|
|
280
|
+
input: parsed.input,
|
|
281
|
+
checked,
|
|
282
|
+
outputDirectory: parsed.outputDirectory,
|
|
283
|
+
toolchainEntry: fileURLToPath(import.meta.url),
|
|
284
|
+
});
|
|
285
|
+
process.stdout.write(`Wrote a minimal reproduction of ${checked.errors.length} diagnostic${checked.errors.length === 1 ? "" : "s"} -> ${reproduction.directory}\n`);
|
|
286
|
+
// Discipline 3: the bundle was re-checked in an extracted copy, and a
|
|
287
|
+
// bundle that stopped reproducing says so instead of being handed over
|
|
288
|
+
// as a clean report.
|
|
289
|
+
process.stdout.write(reproduction.reproduced
|
|
290
|
+
? "The extracted bundle produces the same diagnostics.\n"
|
|
291
|
+
: "Reproduces on this machine but not in the extracted bundle; the README says what the copy reported instead.\n");
|
|
292
|
+
return 0;
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
process.stderr.write(`velar repro: ${hostErrorMessage(error)}\n`);
|
|
296
|
+
return 1;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (command !== "check" && command !== "build" && command !== "package" && command !== "format" && command !== "dev" && command !== "test") {
|
|
300
|
+
process.stderr.write(`Unknown command '${command}'.\n\n`);
|
|
301
|
+
printHelp(process.stderr);
|
|
302
|
+
return 2;
|
|
303
|
+
}
|
|
304
|
+
if (command === "format") {
|
|
305
|
+
const parsed = parseFormatArguments(rest);
|
|
306
|
+
if (typeof parsed === "string") {
|
|
307
|
+
process.stderr.write(`velar format: ${parsed}\n`);
|
|
308
|
+
return 2;
|
|
309
|
+
}
|
|
310
|
+
const singleFile = parsed.input !== null && extname(resolve(parsed.input)) === ".vel";
|
|
311
|
+
let inputs;
|
|
312
|
+
let formattingExtensions = [];
|
|
313
|
+
try {
|
|
314
|
+
if (singleFile) {
|
|
315
|
+
inputs = [resolve(parsed.input)];
|
|
316
|
+
const config = await resolveVelarProject(parsed.input);
|
|
317
|
+
formattingExtensions = config.compilerExtensions;
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
const config = await resolveVelarProject(parsed.input);
|
|
321
|
+
inputs = await discoverVelarSources(config);
|
|
322
|
+
formattingExtensions = config.compilerExtensions;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
process.stderr.write(`velar format: ${hostErrorMessage(error)}\n`);
|
|
327
|
+
return 1;
|
|
328
|
+
}
|
|
329
|
+
if (inputs.length === 0) {
|
|
330
|
+
process.stderr.write("velar format: no .vel source files were found\n");
|
|
331
|
+
return 1;
|
|
332
|
+
}
|
|
333
|
+
const changed = [];
|
|
334
|
+
try {
|
|
335
|
+
for (const input of inputs) {
|
|
336
|
+
const source = await readVelarSourceFile(input);
|
|
337
|
+
const formatted = formatSource(source, { extensions: formattingExtensions });
|
|
338
|
+
if (formatted === source)
|
|
339
|
+
continue;
|
|
340
|
+
changed.push(input);
|
|
341
|
+
if (!parsed.check)
|
|
342
|
+
await writeFile(input, formatted, "utf8");
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
process.stderr.write(`velar format: ${hostErrorMessage(error)}\n`);
|
|
347
|
+
return 1;
|
|
348
|
+
}
|
|
349
|
+
if (parsed.check && changed.length > 0) {
|
|
350
|
+
for (const input of changed)
|
|
351
|
+
process.stderr.write(`${displayPath(input)} is not formatted\n`);
|
|
352
|
+
process.stderr.write(`${changed.length} of ${inputs.length} VelarScript source file${inputs.length === 1 ? "" : "s"} require formatting\n`);
|
|
353
|
+
return 1;
|
|
354
|
+
}
|
|
355
|
+
if (singleFile) {
|
|
356
|
+
process.stdout.write(parsed.check ? `${parsed.input} is formatted\n` : `Formatted ${parsed.input}\n`);
|
|
357
|
+
}
|
|
358
|
+
else if (parsed.check) {
|
|
359
|
+
process.stdout.write(`Checked formatting of ${inputs.length} VelarScript source file${inputs.length === 1 ? "" : "s"}\n`);
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
process.stdout.write(`Formatted ${changed.length} of ${inputs.length} VelarScript source file${inputs.length === 1 ? "" : "s"}\n`);
|
|
363
|
+
}
|
|
364
|
+
return 0;
|
|
365
|
+
}
|
|
366
|
+
if (command === "dev") {
|
|
367
|
+
const parsed = parseDevArguments(rest);
|
|
368
|
+
if (typeof parsed === "string") {
|
|
369
|
+
process.stderr.write(`velar dev: ${parsed}\n`);
|
|
370
|
+
return 2;
|
|
371
|
+
}
|
|
372
|
+
let projectConfig;
|
|
373
|
+
try {
|
|
374
|
+
projectConfig = await resolveVelarProject(parsed.input);
|
|
375
|
+
if (!projectConfig.framework)
|
|
376
|
+
throw new Error("the project does not declare an application framework host");
|
|
377
|
+
await runDevServer(projectConfig, parsed.port);
|
|
378
|
+
}
|
|
379
|
+
catch (error) {
|
|
380
|
+
process.stderr.write(`velar dev: ${hostErrorMessage(error)}\n`);
|
|
381
|
+
return 1;
|
|
382
|
+
}
|
|
383
|
+
return 0;
|
|
384
|
+
}
|
|
385
|
+
if (command === "test") {
|
|
386
|
+
const parsed = parseTestArguments(rest);
|
|
387
|
+
if (typeof parsed === "string") {
|
|
388
|
+
process.stderr.write(`velar test: ${parsed}\n`);
|
|
389
|
+
return 2;
|
|
390
|
+
}
|
|
391
|
+
if (!parsed.browser && parsed.input?.endsWith(".browser.test.vel")) {
|
|
392
|
+
process.stderr.write("velar test: .browser.test.vel files require --browser\n");
|
|
393
|
+
return 2;
|
|
394
|
+
}
|
|
395
|
+
if (parsed.browser && parsed.input?.endsWith(".test.vel") && !parsed.input.endsWith(".browser.test.vel")) {
|
|
396
|
+
process.stderr.write("velar test: --browser accepts a project or .browser.test.vel file\n");
|
|
397
|
+
return 2;
|
|
398
|
+
}
|
|
399
|
+
let projectConfig;
|
|
400
|
+
try {
|
|
401
|
+
projectConfig = await resolveVelarProject(parsed.input);
|
|
402
|
+
if (parsed.browser && parsed.input?.endsWith(".browser.test.vel") && projectConfig.manifestPath) {
|
|
403
|
+
projectConfig = await resolveVelarProject(projectConfig.root);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
catch (error) {
|
|
407
|
+
process.stderr.write(`velar test: ${hostErrorMessage(error)}\n`);
|
|
408
|
+
return 1;
|
|
409
|
+
}
|
|
410
|
+
if (parsed.browser) {
|
|
411
|
+
const { runBrowserTests } = await import("./browser-test-runner.js");
|
|
412
|
+
return runBrowserTests(projectConfig, parsed.input, parsed.browser);
|
|
413
|
+
}
|
|
414
|
+
return runTests(projectConfig, parsed.input);
|
|
415
|
+
}
|
|
416
|
+
const parsed = command === "package" ? parsePackageArguments(rest) : parseCommandArguments(rest);
|
|
417
|
+
if (typeof parsed === "string") {
|
|
418
|
+
process.stderr.write(`velar ${command}: ${parsed}\n`);
|
|
419
|
+
return 2;
|
|
420
|
+
}
|
|
421
|
+
let projectConfig;
|
|
422
|
+
try {
|
|
423
|
+
projectConfig = await resolveVelarProject(parsed.input);
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
process.stderr.write(`velar ${command}: ${hostErrorMessage(error)}\n`);
|
|
427
|
+
return 1;
|
|
428
|
+
}
|
|
429
|
+
const checked = await checkResolvedProject(projectConfig, parsed.input);
|
|
430
|
+
const project = checked.project;
|
|
431
|
+
process.stderr.write(formatCheckOutput(checked));
|
|
432
|
+
if (checked.errors.length > 0) {
|
|
433
|
+
// D66 ruling 7B: a failing check ends with the command that bundles the
|
|
434
|
+
// failure — one line, no persuasion, and nothing about data leaving the
|
|
435
|
+
// machine, because `velar repro` never sends any. `build` and `package`
|
|
436
|
+
// reach this same exit, and the ruling names `check`: it is the command the
|
|
437
|
+
// reproduction's own README tells a reader to run.
|
|
438
|
+
if (command === "check")
|
|
439
|
+
process.stderr.write(`${reproductionHint(parsed.input)}\n`);
|
|
440
|
+
return 1;
|
|
441
|
+
}
|
|
442
|
+
if (command === "check") {
|
|
443
|
+
const count = checked.compiled.size;
|
|
444
|
+
process.stdout.write(`Checked ${count} module${count === 1 ? "" : "s"} from ${displayInput(parsed.input, projectConfig)}\n`);
|
|
445
|
+
return 0;
|
|
446
|
+
}
|
|
447
|
+
if (command === "package") {
|
|
448
|
+
if (!project.framework) {
|
|
449
|
+
process.stderr.write("velar package: this project does not enable an application target\n");
|
|
450
|
+
return 1;
|
|
451
|
+
}
|
|
452
|
+
try {
|
|
453
|
+
const packageHost = await loadApplicationPackageHost(projectConfig);
|
|
454
|
+
let buildRequests = 0;
|
|
455
|
+
const toolRequests = new Set();
|
|
456
|
+
let frameworkBuild = null;
|
|
457
|
+
const packageResult = await packageHost.packageApplication({
|
|
458
|
+
projectRoot: projectConfig.root,
|
|
459
|
+
config: projectConfig.framework.config,
|
|
460
|
+
buildFramework: async (requestedOutput) => {
|
|
461
|
+
buildRequests += 1;
|
|
462
|
+
if (buildRequests > 1)
|
|
463
|
+
throw new Error("application package host requested more than one framework build");
|
|
464
|
+
const outputDirectory = packageFrameworkOutput(projectConfig.root, requestedOutput);
|
|
465
|
+
frameworkBuild = writeFrameworkProductionApplication(project, outputDirectory);
|
|
466
|
+
await frameworkBuild;
|
|
467
|
+
},
|
|
468
|
+
buildTool: async (tool) => {
|
|
469
|
+
if (!tool || typeof tool.outputFile !== "string"
|
|
470
|
+
|| ![VELAR_LANGUAGE_SERVER_TOOL_ID, VELAR_PROJECT_TASK_TOOL_ID, VELAR_BUILD_ENGINE_TOOL_ID].includes(tool.id)) {
|
|
471
|
+
throw new Error(`application package host requested unknown official tool '${String(tool?.id ?? "")}'`);
|
|
472
|
+
}
|
|
473
|
+
if (toolRequests.has(tool.id))
|
|
474
|
+
throw new Error(`application package host requested official tool '${tool.id}' more than once`);
|
|
475
|
+
toolRequests.add(tool.id);
|
|
476
|
+
const outputFile = packageFrameworkOutput(projectConfig.root, tool.outputFile);
|
|
477
|
+
if (tool.id === VELAR_LANGUAGE_SERVER_TOOL_ID)
|
|
478
|
+
await buildLanguageServerTool(outputFile);
|
|
479
|
+
else if (tool.id === VELAR_PROJECT_TASK_TOOL_ID)
|
|
480
|
+
await buildProjectTaskTool(outputFile);
|
|
481
|
+
else
|
|
482
|
+
await buildBuildEngineTool(outputFile);
|
|
483
|
+
},
|
|
484
|
+
});
|
|
485
|
+
if (buildRequests !== 1 || !frameworkBuild)
|
|
486
|
+
throw new Error("application package host did not request exactly one checked framework build");
|
|
487
|
+
await frameworkBuild;
|
|
488
|
+
const result = validateApplicationPackageResult(packageResult, projectConfig.root);
|
|
489
|
+
process.stdout.write(`Packaged ${project.framework.host.displayName} application -> ${result.artifactPath}\n`);
|
|
490
|
+
for (const detail of result.details)
|
|
491
|
+
process.stdout.write(`${detail}\n`);
|
|
492
|
+
return 0;
|
|
493
|
+
}
|
|
494
|
+
catch (error) {
|
|
495
|
+
process.stderr.write(`velar package: ${hostErrorMessage(error)}\n`);
|
|
496
|
+
return 1;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if (parsed.output && project.modules.length !== 1) {
|
|
500
|
+
process.stderr.write("velar build: --out is only valid for a single-file build; use --out-dir for module projects\n");
|
|
501
|
+
return 2;
|
|
502
|
+
}
|
|
503
|
+
if (parsed.output) {
|
|
504
|
+
const outputPath = resolve(parsed.output);
|
|
505
|
+
try {
|
|
506
|
+
await assertNodeStandardModuleOutputAvailable(dirname(outputPath), project);
|
|
507
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
508
|
+
const result = project.modules[0].result;
|
|
509
|
+
if (needsStandaloneJavaScriptBundle(result)) {
|
|
510
|
+
const bundled = await bundleStandaloneJavaScript(outputPath, result);
|
|
511
|
+
await writeCompiled(outputPath, result, true, bundled.code, bundled.sourceMap, false);
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
await writeCompiled(outputPath, result, true);
|
|
515
|
+
}
|
|
516
|
+
await writeNodeStandardModules(dirname(outputPath), project, true);
|
|
517
|
+
}
|
|
518
|
+
catch (error) {
|
|
519
|
+
process.stderr.write(`velar build: ${hostErrorMessage(error)}\n`);
|
|
520
|
+
return 1;
|
|
521
|
+
}
|
|
522
|
+
process.stdout.write(`Built ${displayInput(parsed.input, projectConfig)} -> ${outputPath}\n`);
|
|
523
|
+
return 0;
|
|
524
|
+
}
|
|
525
|
+
const outputDirectory = parsed.outputDirectory ? resolve(parsed.outputDirectory) : projectConfig.outDir;
|
|
526
|
+
if (project.framework) {
|
|
527
|
+
try {
|
|
528
|
+
await writeFrameworkProductionApplication(project, outputDirectory);
|
|
529
|
+
}
|
|
530
|
+
catch (error) {
|
|
531
|
+
process.stderr.write(`velar build: ${hostErrorMessage(error)}\n`);
|
|
532
|
+
return 1;
|
|
533
|
+
}
|
|
534
|
+
process.stdout.write(`Built production ${project.framework.host.displayName} app -> ${outputDirectory}\n`);
|
|
535
|
+
return 0;
|
|
536
|
+
}
|
|
537
|
+
const staging = await prepareBuildStaging(outputDirectory);
|
|
538
|
+
try {
|
|
539
|
+
assertUniqueEmbeddedModuleOutputs(project.modules.map((module) => ({
|
|
540
|
+
ownerPath: join(staging, module.relativePath.replace(/\.vel$/, ".js")),
|
|
541
|
+
embeddedModules: module.result.embeddedModules,
|
|
542
|
+
})));
|
|
543
|
+
for (const module of project.modules) {
|
|
544
|
+
const outputPath = join(staging, module.relativePath.replace(/\.vel$/, ".js"));
|
|
545
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
546
|
+
await writeCompiled(outputPath, module.result, false, rewriteVelarPackageImports(project, module));
|
|
547
|
+
}
|
|
548
|
+
await writeNodeStandardModules(staging, project);
|
|
549
|
+
await replaceOutputDirectory(staging, outputDirectory);
|
|
550
|
+
}
|
|
551
|
+
catch (error) {
|
|
552
|
+
await rm(staging, { recursive: true, force: true });
|
|
553
|
+
process.stderr.write(`velar build: ${hostErrorMessage(error)}\n`);
|
|
554
|
+
return 1;
|
|
555
|
+
}
|
|
556
|
+
process.stdout.write(`Built ${project.modules.length} module${project.modules.length === 1 ? "" : "s"} -> ${outputDirectory}\n`);
|
|
557
|
+
return 0;
|
|
558
|
+
}
|
|
559
|
+
async function writeFrameworkProductionApplication(project, outputDirectory) {
|
|
560
|
+
if (!project.framework)
|
|
561
|
+
throw new Error("the checked project has no framework host");
|
|
562
|
+
const framework = project.framework;
|
|
563
|
+
await assertRequiredPublicAssets(project.publicRoot, project.projectRoot, framework.host.requiredPublicAssets?.(framework.config) ?? []);
|
|
564
|
+
const staging = await prepareBuildStaging(outputDirectory);
|
|
565
|
+
try {
|
|
566
|
+
await copyPublicAssets(project.publicRoot, staging);
|
|
567
|
+
const production = await buildProductionFramework(project, staging);
|
|
568
|
+
const artifacts = createFrameworkArtifacts(project, false, {}, {
|
|
569
|
+
entryPath: production.entryPath,
|
|
570
|
+
stylesheetPath: production.stylesheetPath,
|
|
571
|
+
includeStandardImports: false,
|
|
572
|
+
});
|
|
573
|
+
if (!artifacts)
|
|
574
|
+
throw new Error("The framework host did not create an application entry");
|
|
575
|
+
await writeFile(join(staging, "index.html"), artifacts.html, "utf8");
|
|
576
|
+
const deployment = await writeStaticDeployment(staging, artifacts.html, project.framework.host.staticDeployment(project.framework.config), production.framework);
|
|
577
|
+
await writeProductionManifest(staging, production, deployment);
|
|
578
|
+
await replaceOutputDirectory(staging, outputDirectory);
|
|
579
|
+
}
|
|
580
|
+
catch (error) {
|
|
581
|
+
await rm(staging, { recursive: true, force: true });
|
|
582
|
+
throw error;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
function packageFrameworkOutput(root, input) {
|
|
586
|
+
if (!isAbsolute(input))
|
|
587
|
+
throw new Error("application package host requested a non-absolute framework output path");
|
|
588
|
+
const output = resolve(input);
|
|
589
|
+
const fromRoot = relative(root, output);
|
|
590
|
+
if (fromRoot === "" || fromRoot === ".." || fromRoot.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute(fromRoot)) {
|
|
591
|
+
throw new Error("application package host requested a framework output path outside the project root");
|
|
592
|
+
}
|
|
593
|
+
return output;
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Reclaims only staging directories carrying a marker that names this exact
|
|
597
|
+
* output. A process cut can happen before or after either rename, so recovery
|
|
598
|
+
* also finishes restoring the previous output when installation never began.
|
|
599
|
+
*/
|
|
600
|
+
async function prepareBuildStaging(outputDirectory) {
|
|
601
|
+
const normalizedOutput = resolve(outputDirectory);
|
|
602
|
+
const parent = dirname(normalizedOutput);
|
|
603
|
+
await mkdir(parent, { recursive: true });
|
|
604
|
+
await recoverInterruptedBuilds(normalizedOutput);
|
|
605
|
+
const staging = await mkdtemp(join(parent, `.velar-${basename(normalizedOutput)}-`));
|
|
606
|
+
const ownership = {
|
|
607
|
+
formatVersion: 1,
|
|
608
|
+
kind: "velar-build-staging",
|
|
609
|
+
outputDirectory: normalizedOutput,
|
|
610
|
+
stagingDirectory: resolve(staging),
|
|
611
|
+
ownerPid: process.pid,
|
|
612
|
+
};
|
|
613
|
+
await writeFile(join(staging, BUILD_STAGING_MARKER), `${JSON.stringify(ownership, null, 2)}\n`, "utf8");
|
|
614
|
+
return staging;
|
|
615
|
+
}
|
|
616
|
+
async function recoverInterruptedBuilds(outputDirectory) {
|
|
617
|
+
const parent = dirname(outputDirectory);
|
|
618
|
+
const prefix = `.velar-${basename(outputDirectory)}-`;
|
|
619
|
+
const installed = await buildStagingOwnership(outputDirectory, outputDirectory, null);
|
|
620
|
+
if (installed && !processIsAlive(installed.ownerPid)) {
|
|
621
|
+
await rm(`${installed.stagingDirectory}-previous`, { recursive: true, force: true });
|
|
622
|
+
await rm(join(outputDirectory, BUILD_STAGING_MARKER), { force: true });
|
|
623
|
+
}
|
|
624
|
+
for (const entry of await readdir(parent, { withFileTypes: true })) {
|
|
625
|
+
if (!entry.name.startsWith(prefix) || entry.name.endsWith("-previous") || !entry.isDirectory())
|
|
626
|
+
continue;
|
|
627
|
+
const staging = resolve(parent, entry.name);
|
|
628
|
+
const ownership = await buildStagingOwnership(staging, outputDirectory, staging);
|
|
629
|
+
if (!ownership || processIsAlive(ownership.ownerPid))
|
|
630
|
+
continue;
|
|
631
|
+
const previous = `${staging}-previous`;
|
|
632
|
+
try {
|
|
633
|
+
await lstat(outputDirectory);
|
|
634
|
+
await rm(previous, { recursive: true, force: true });
|
|
635
|
+
}
|
|
636
|
+
catch (error) {
|
|
637
|
+
if (!isHostErrorCode(error, "ENOENT"))
|
|
638
|
+
throw error;
|
|
639
|
+
try {
|
|
640
|
+
await rename(previous, outputDirectory);
|
|
641
|
+
}
|
|
642
|
+
catch (restoreError) {
|
|
643
|
+
if (!isHostErrorCode(restoreError, "ENOENT"))
|
|
644
|
+
throw restoreError;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
await rm(staging, { recursive: true, force: true });
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
async function buildStagingOwnership(directory, outputDirectory, expectedStaging) {
|
|
651
|
+
try {
|
|
652
|
+
const directoryMetadata = await lstat(directory);
|
|
653
|
+
if (!directoryMetadata.isDirectory() || directoryMetadata.isSymbolicLink())
|
|
654
|
+
return null;
|
|
655
|
+
const markerPath = join(directory, BUILD_STAGING_MARKER);
|
|
656
|
+
const markerMetadata = await lstat(markerPath);
|
|
657
|
+
if (!markerMetadata.isFile() || markerMetadata.isSymbolicLink())
|
|
658
|
+
return null;
|
|
659
|
+
const parsed = JSON.parse(await readFile(markerPath, "utf8"));
|
|
660
|
+
if (parsed.formatVersion !== 1
|
|
661
|
+
|| parsed.kind !== "velar-build-staging"
|
|
662
|
+
|| parsed.outputDirectory !== outputDirectory
|
|
663
|
+
|| typeof parsed.stagingDirectory !== "string"
|
|
664
|
+
|| dirname(parsed.stagingDirectory) !== dirname(outputDirectory)
|
|
665
|
+
|| !basename(parsed.stagingDirectory).startsWith(`.velar-${basename(outputDirectory)}-`)
|
|
666
|
+
|| (expectedStaging !== null && parsed.stagingDirectory !== expectedStaging)
|
|
667
|
+
|| !Number.isSafeInteger(parsed.ownerPid)
|
|
668
|
+
|| (parsed.ownerPid ?? 0) <= 0)
|
|
669
|
+
return null;
|
|
670
|
+
return parsed;
|
|
671
|
+
}
|
|
672
|
+
catch (error) {
|
|
673
|
+
if (isHostErrorCode(error, "ENOENT") || error instanceof SyntaxError)
|
|
674
|
+
return null;
|
|
675
|
+
throw error;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
function processIsAlive(pid) {
|
|
679
|
+
try {
|
|
680
|
+
process.kill(pid, 0);
|
|
681
|
+
return true;
|
|
682
|
+
}
|
|
683
|
+
catch (error) {
|
|
684
|
+
return isHostErrorCode(error, "EPERM");
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
async function replaceOutputDirectory(staging, outputDirectory) {
|
|
688
|
+
const previous = `${staging}-previous`;
|
|
689
|
+
let movedPrevious = false;
|
|
690
|
+
let installed = false;
|
|
691
|
+
try {
|
|
692
|
+
try {
|
|
693
|
+
await rename(outputDirectory, previous);
|
|
694
|
+
movedPrevious = true;
|
|
695
|
+
}
|
|
696
|
+
catch (error) {
|
|
697
|
+
if (!isHostErrorCode(error, "ENOENT"))
|
|
698
|
+
throw error;
|
|
699
|
+
}
|
|
700
|
+
await rename(staging, outputDirectory);
|
|
701
|
+
installed = true;
|
|
702
|
+
if (movedPrevious)
|
|
703
|
+
await rm(previous, { recursive: true, force: true });
|
|
704
|
+
await rm(join(outputDirectory, BUILD_STAGING_MARKER), { force: true });
|
|
705
|
+
}
|
|
706
|
+
catch (error) {
|
|
707
|
+
if (!installed && movedPrevious) {
|
|
708
|
+
try {
|
|
709
|
+
await rename(previous, outputDirectory);
|
|
710
|
+
}
|
|
711
|
+
catch (restoreError) {
|
|
712
|
+
throw new Error(`Build output replacement failed and the previous output could not be restored: ${hostErrorMessage(restoreError)}`, { cause: error });
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
throw error;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
const VELAR_GENERATED_RUNTIME_PACKAGE_VERSION = 1;
|
|
719
|
+
async function writeNodeStandardModules(outputRoot, project, replaceExisting = false) {
|
|
720
|
+
const used = requiredNodeStandardModules(project);
|
|
721
|
+
const packageRoot = join(outputRoot, "node_modules", "velar");
|
|
722
|
+
if (!replaceExisting) {
|
|
723
|
+
if (used.size === 0)
|
|
724
|
+
return;
|
|
725
|
+
await writeNodeStandardModulePackage(packageRoot, used, project);
|
|
726
|
+
if (used.has("velar/websocket"))
|
|
727
|
+
await writeWebSocketDependency(dirname(packageRoot));
|
|
728
|
+
await writeAdapterDependencies(dirname(packageRoot), used);
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
const ownership = await generatedRuntimePackageOwnership(packageRoot);
|
|
732
|
+
if (used.size === 0) {
|
|
733
|
+
if (ownership === "generated")
|
|
734
|
+
await rm(packageRoot, { recursive: true, force: true });
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
if (ownership === "foreign")
|
|
738
|
+
throw new Error(`Refusing to replace non-generated package '${packageRoot}'`);
|
|
739
|
+
await mkdir(dirname(packageRoot), { recursive: true });
|
|
740
|
+
const staging = await mkdtemp(join(dirname(packageRoot), ".velar-runtime-"));
|
|
741
|
+
try {
|
|
742
|
+
await writeNodeStandardModulePackage(staging, used, project);
|
|
743
|
+
if (ownership === "generated")
|
|
744
|
+
await replaceOutputDirectory(staging, packageRoot);
|
|
745
|
+
else
|
|
746
|
+
await rename(staging, packageRoot);
|
|
747
|
+
if (used.has("velar/websocket"))
|
|
748
|
+
await writeWebSocketDependency(dirname(packageRoot));
|
|
749
|
+
await writeAdapterDependencies(dirname(packageRoot), used);
|
|
750
|
+
}
|
|
751
|
+
catch (error) {
|
|
752
|
+
await rm(staging, { recursive: true, force: true });
|
|
753
|
+
throw error;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
async function writeWebSocketDependency(nodeModulesRoot) {
|
|
757
|
+
const target = join(nodeModulesRoot, "ws");
|
|
758
|
+
try {
|
|
759
|
+
const manifest = JSON.parse(await readFile(join(target, "package.json"), "utf8"));
|
|
760
|
+
if (manifest.name !== "ws" || manifest.version !== "8.21.1")
|
|
761
|
+
throw new Error(`Refusing to use incompatible WebSocket runtime package '${target}'`);
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
catch (error) {
|
|
765
|
+
if (!isHostErrorCode(error, "ENOENT"))
|
|
766
|
+
throw error;
|
|
767
|
+
}
|
|
768
|
+
const require = createRequire(import.meta.url);
|
|
769
|
+
const source = dirname(require.resolve("ws/package.json"));
|
|
770
|
+
await cp(source, target, { recursive: true, errorOnExist: true });
|
|
771
|
+
}
|
|
772
|
+
async function writeAdapterDependencies(nodeModulesRoot, used) {
|
|
773
|
+
const require = createRequire(import.meta.url);
|
|
774
|
+
for (const [moduleName, dependency] of STANDARD_MODULE_ADAPTER_DEPENDENCIES) {
|
|
775
|
+
if (!used.has(moduleName))
|
|
776
|
+
continue;
|
|
777
|
+
const target = join(nodeModulesRoot, dependency.packageName);
|
|
778
|
+
try {
|
|
779
|
+
const manifest = JSON.parse(await readFile(join(target, "package.json"), "utf8"));
|
|
780
|
+
if (manifest.name !== dependency.packageName || manifest.version !== dependency.version) {
|
|
781
|
+
throw new Error(`Refusing to use incompatible ${moduleName} runtime package '${target}'`);
|
|
782
|
+
}
|
|
783
|
+
continue;
|
|
784
|
+
}
|
|
785
|
+
catch (error) {
|
|
786
|
+
if (!isHostErrorCode(error, "ENOENT"))
|
|
787
|
+
throw error;
|
|
788
|
+
}
|
|
789
|
+
const source = await resolveInstalledPackageRoot(dependency.packageName, dependency.packageName, require);
|
|
790
|
+
await cp(source, target, { recursive: true, errorOnExist: true });
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
function requiredNodeStandardModules(project) {
|
|
794
|
+
const sources = standardModuleSources(project.compilerExtensions);
|
|
795
|
+
const roots = new Set(project.modules.flatMap((module) => module.result.dependencies
|
|
796
|
+
.map((dependency) => dependency.source)
|
|
797
|
+
.filter((source) => sources.has(source))));
|
|
798
|
+
for (const module of project.modules) {
|
|
799
|
+
for (const source of module.result.runtimeModules)
|
|
800
|
+
if (sources.has(source))
|
|
801
|
+
roots.add(source);
|
|
802
|
+
}
|
|
803
|
+
return standardModuleClosure(roots, project.extensionConfig, project.compilerExtensions);
|
|
804
|
+
}
|
|
805
|
+
async function assertNodeStandardModuleOutputAvailable(outputRoot, project) {
|
|
806
|
+
if (requiredNodeStandardModules(project).size === 0)
|
|
807
|
+
return;
|
|
808
|
+
const packageRoot = join(outputRoot, "node_modules", "velar");
|
|
809
|
+
if (await generatedRuntimePackageOwnership(packageRoot) === "foreign") {
|
|
810
|
+
throw new Error(`Refusing to replace non-generated package '${packageRoot}'`);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
async function writeNodeStandardModulePackage(packageRoot, used, project) {
|
|
814
|
+
await mkdir(packageRoot, { recursive: true });
|
|
815
|
+
const exports = {};
|
|
816
|
+
for (const source of [...used].sort()) {
|
|
817
|
+
const name = source.slice("velar/".length);
|
|
818
|
+
const moduleSource = standardModuleSource(source, project.extensionConfig, project.compilerExtensions);
|
|
819
|
+
if (moduleSource === null)
|
|
820
|
+
throw new Error(`Unknown VelarScript standard module '${source}'`);
|
|
821
|
+
exports[`./${name}`] = `./${name}.js`;
|
|
822
|
+
await writeFile(join(packageRoot, `${name}.js`), moduleSource, "utf8");
|
|
823
|
+
}
|
|
824
|
+
await writeFile(join(packageRoot, "package.json"), `${JSON.stringify({
|
|
825
|
+
name: "velar",
|
|
826
|
+
private: true,
|
|
827
|
+
type: "module",
|
|
828
|
+
velarGeneratedRuntime: VELAR_GENERATED_RUNTIME_PACKAGE_VERSION,
|
|
829
|
+
exports,
|
|
830
|
+
}, null, 2)}\n`, "utf8");
|
|
831
|
+
}
|
|
832
|
+
async function generatedRuntimePackageOwnership(packageRoot) {
|
|
833
|
+
try {
|
|
834
|
+
const stats = await lstat(packageRoot);
|
|
835
|
+
if (!stats.isDirectory() || stats.isSymbolicLink())
|
|
836
|
+
return "foreign";
|
|
837
|
+
}
|
|
838
|
+
catch (error) {
|
|
839
|
+
if (isHostErrorCode(error, "ENOENT"))
|
|
840
|
+
return "absent";
|
|
841
|
+
throw error;
|
|
842
|
+
}
|
|
843
|
+
try {
|
|
844
|
+
const manifest = JSON.parse(await readFile(join(packageRoot, "package.json"), "utf8"));
|
|
845
|
+
return manifest.name === "velar"
|
|
846
|
+
&& manifest.private === true
|
|
847
|
+
&& manifest.type === "module"
|
|
848
|
+
&& manifest.velarGeneratedRuntime === VELAR_GENERATED_RUNTIME_PACKAGE_VERSION
|
|
849
|
+
? "generated"
|
|
850
|
+
: "foreign";
|
|
851
|
+
}
|
|
852
|
+
catch (error) {
|
|
853
|
+
if (isHostErrorCode(error, "ENOENT") || error instanceof SyntaxError)
|
|
854
|
+
return "foreign";
|
|
855
|
+
throw error;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
async function writeCompiled(outputPath, result, writeCss, codeOverride = null, sourceMapOverride = null, writeEmbedded = true) {
|
|
859
|
+
const mapPath = `${outputPath}.map`;
|
|
860
|
+
const rawCode = codeOverride ?? result.code ?? "";
|
|
861
|
+
const code = rawCode.includes(`//# sourceMappingURL=${basename(mapPath)}`)
|
|
862
|
+
? rawCode
|
|
863
|
+
: `${rawCode}//# sourceMappingURL=${basename(mapPath)}\n`;
|
|
864
|
+
if (writeEmbedded) {
|
|
865
|
+
assertUniqueEmbeddedModuleOutputs([{ ownerPath: outputPath, embeddedModules: result.embeddedModules }]);
|
|
866
|
+
for (const module of result.embeddedModules) {
|
|
867
|
+
const embeddedPath = embeddedModuleOutputPath(outputPath, module.specifier);
|
|
868
|
+
await assertEmbeddedModuleOutputWritable(embeddedPath);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
const writes = [
|
|
872
|
+
writeFile(outputPath, code, "utf8"),
|
|
873
|
+
writeFile(mapPath, sourceMapOverride ?? result.sourceMap ?? "", "utf8"),
|
|
874
|
+
...(writeEmbedded ? result.embeddedModules : []).flatMap((module) => {
|
|
875
|
+
const embeddedPath = embeddedModuleOutputPath(outputPath, module.specifier);
|
|
876
|
+
return [
|
|
877
|
+
writeFile(embeddedPath, embeddedModuleFileContents(embeddedPath, module), "utf8"),
|
|
878
|
+
writeFile(`${embeddedPath}.map`, module.sourceMap, "utf8"),
|
|
879
|
+
];
|
|
880
|
+
}),
|
|
881
|
+
];
|
|
882
|
+
if (writeCss) {
|
|
883
|
+
const cssPath = outputPath.replace(/\.js$/u, ".css");
|
|
884
|
+
writes.push(result.css ? writeFile(cssPath, result.css, "utf8") : rm(cssPath, { force: true }));
|
|
885
|
+
}
|
|
886
|
+
await Promise.all(writes);
|
|
887
|
+
}
|
|
888
|
+
async function assertEmbeddedModuleOutputWritable(path) {
|
|
889
|
+
try {
|
|
890
|
+
const metadata = await lstat(path);
|
|
891
|
+
if (!metadata.isFile() || metadata.isSymbolicLink()) {
|
|
892
|
+
throw new Error(`Refusing to replace non-generated embedded JavaScript output '${path}'`);
|
|
893
|
+
}
|
|
894
|
+
const existing = await readFile(path, "utf8");
|
|
895
|
+
if (!existing.includes(VELAR_EMBEDDED_MODULE_MARKER)) {
|
|
896
|
+
throw new Error(`Refusing to replace non-generated embedded JavaScript output '${path}'`);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
catch (error) {
|
|
900
|
+
if (!isHostErrorCode(error, "ENOENT"))
|
|
901
|
+
throw error;
|
|
902
|
+
try {
|
|
903
|
+
await lstat(`${path}.map`);
|
|
904
|
+
throw new Error(`Refusing to replace source map '${path}.map' without its generated embedded JavaScript owner`);
|
|
905
|
+
}
|
|
906
|
+
catch (mapError) {
|
|
907
|
+
if (!isHostErrorCode(mapError, "ENOENT"))
|
|
908
|
+
throw mapError;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
function rewriteVelarPackageImports(project, module) {
|
|
913
|
+
if (!module.result.code)
|
|
914
|
+
return null;
|
|
915
|
+
return module.result.code.replace(/(\bfrom\s+["']|\bimport\s+["'])([^"']+)(["'])/gu, (match, prefix, source, suffix) => {
|
|
916
|
+
const targetPath = project.velarImports.get(projectImportKey(module.inputPath, source));
|
|
917
|
+
if (!targetPath)
|
|
918
|
+
return match;
|
|
919
|
+
const target = project.modules.find((item) => item.inputPath === targetPath);
|
|
920
|
+
if (!target)
|
|
921
|
+
return match;
|
|
922
|
+
let targetImport = relative(dirname(module.relativePath), target.relativePath).replace(/\.vel$/u, ".js").replaceAll("\\", "/");
|
|
923
|
+
if (!targetImport.startsWith("."))
|
|
924
|
+
targetImport = `./${targetImport}`;
|
|
925
|
+
return `${prefix}${targetImport}${suffix}`;
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
function parseFormatArguments(arguments_) {
|
|
929
|
+
let input = null;
|
|
930
|
+
let check = false;
|
|
931
|
+
for (const argument of arguments_) {
|
|
932
|
+
if (argument === "--check") {
|
|
933
|
+
check = true;
|
|
934
|
+
}
|
|
935
|
+
else if (argument.startsWith("--")) {
|
|
936
|
+
return `unknown option '${argument}'`;
|
|
937
|
+
}
|
|
938
|
+
else if (input) {
|
|
939
|
+
return `unexpected extra input '${argument}'`;
|
|
940
|
+
}
|
|
941
|
+
else {
|
|
942
|
+
input = argument;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
return { input, check };
|
|
946
|
+
}
|
|
947
|
+
function parseCommandArguments(arguments_) {
|
|
948
|
+
let input = null;
|
|
949
|
+
let output = null;
|
|
950
|
+
let outputDirectory = null;
|
|
951
|
+
for (let index = 0; index < arguments_.length; index += 1) {
|
|
952
|
+
const argument = arguments_[index];
|
|
953
|
+
if (argument === "--out" || argument === "--out-dir") {
|
|
954
|
+
const value = arguments_[index + 1];
|
|
955
|
+
if (!value || value.startsWith("--")) {
|
|
956
|
+
return `${argument} requires a path`;
|
|
957
|
+
}
|
|
958
|
+
if (argument === "--out") {
|
|
959
|
+
if (extname(value) !== ".js")
|
|
960
|
+
return "--out requires a .js file path";
|
|
961
|
+
output = value;
|
|
962
|
+
}
|
|
963
|
+
else {
|
|
964
|
+
outputDirectory = value;
|
|
965
|
+
}
|
|
966
|
+
index += 1;
|
|
967
|
+
}
|
|
968
|
+
else if (argument.startsWith("--")) {
|
|
969
|
+
return `unknown option '${argument}'`;
|
|
970
|
+
}
|
|
971
|
+
else if (input) {
|
|
972
|
+
return `unexpected extra input '${argument}'`;
|
|
973
|
+
}
|
|
974
|
+
else {
|
|
975
|
+
input = argument;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
return { input, output, outputDirectory };
|
|
979
|
+
}
|
|
980
|
+
function parseReproArguments(arguments_) {
|
|
981
|
+
let input = null;
|
|
982
|
+
let outputDirectory = null;
|
|
983
|
+
for (let index = 0; index < arguments_.length; index += 1) {
|
|
984
|
+
const argument = arguments_[index];
|
|
985
|
+
if (argument === "--out-dir") {
|
|
986
|
+
const value = arguments_[index + 1];
|
|
987
|
+
if (!value || value.startsWith("--"))
|
|
988
|
+
return "--out-dir requires a path";
|
|
989
|
+
if (outputDirectory)
|
|
990
|
+
return "--out-dir may be provided only once";
|
|
991
|
+
outputDirectory = value;
|
|
992
|
+
index += 1;
|
|
993
|
+
}
|
|
994
|
+
else if (argument.startsWith("--out-dir=")) {
|
|
995
|
+
if (outputDirectory)
|
|
996
|
+
return "--out-dir may be provided only once";
|
|
997
|
+
outputDirectory = argument.slice("--out-dir=".length);
|
|
998
|
+
if (!outputDirectory)
|
|
999
|
+
return "--out-dir requires a path";
|
|
1000
|
+
}
|
|
1001
|
+
else if (argument.startsWith("--")) {
|
|
1002
|
+
return `unknown option '${argument}'`;
|
|
1003
|
+
}
|
|
1004
|
+
else if (input) {
|
|
1005
|
+
return `unexpected extra input '${argument}'`;
|
|
1006
|
+
}
|
|
1007
|
+
else {
|
|
1008
|
+
input = argument;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
return { input, outputDirectory };
|
|
1012
|
+
}
|
|
1013
|
+
function parsePackageArguments(arguments_) {
|
|
1014
|
+
if (arguments_.length > 1)
|
|
1015
|
+
return `unexpected extra input '${arguments_[1]}'`;
|
|
1016
|
+
if (arguments_[0]?.startsWith("-"))
|
|
1017
|
+
return `unknown option '${arguments_[0]}'`;
|
|
1018
|
+
return { input: arguments_[0] ?? null, output: null, outputDirectory: null };
|
|
1019
|
+
}
|
|
1020
|
+
function parseDevArguments(arguments_) {
|
|
1021
|
+
let input = null;
|
|
1022
|
+
let port = 5173;
|
|
1023
|
+
for (let index = 0; index < arguments_.length; index += 1) {
|
|
1024
|
+
const argument = arguments_[index];
|
|
1025
|
+
if (argument === "--port") {
|
|
1026
|
+
const value = arguments_[index + 1];
|
|
1027
|
+
const parsed = value ? Number(value) : Number.NaN;
|
|
1028
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65_535)
|
|
1029
|
+
return "--port requires an integer from 1 to 65535";
|
|
1030
|
+
port = parsed;
|
|
1031
|
+
index += 1;
|
|
1032
|
+
}
|
|
1033
|
+
else if (argument.startsWith("--")) {
|
|
1034
|
+
return `unknown option '${argument}'`;
|
|
1035
|
+
}
|
|
1036
|
+
else if (input) {
|
|
1037
|
+
return `unexpected extra input '${argument}'`;
|
|
1038
|
+
}
|
|
1039
|
+
else {
|
|
1040
|
+
input = argument;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
return { input, port };
|
|
1044
|
+
}
|
|
1045
|
+
function parseTestArguments(arguments_) {
|
|
1046
|
+
let input = null;
|
|
1047
|
+
let browser = null;
|
|
1048
|
+
const engines = new Set(["chromium", "firefox", "webkit", "all"]);
|
|
1049
|
+
for (let index = 0; index < arguments_.length; index += 1) {
|
|
1050
|
+
const argument = arguments_[index];
|
|
1051
|
+
if (argument === "--browser") {
|
|
1052
|
+
const candidate = arguments_[index + 1];
|
|
1053
|
+
if (candidate && engines.has(candidate)) {
|
|
1054
|
+
browser = candidate;
|
|
1055
|
+
index += 1;
|
|
1056
|
+
}
|
|
1057
|
+
else {
|
|
1058
|
+
browser = "chromium";
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
else if (argument.startsWith("--browser=")) {
|
|
1062
|
+
const candidate = argument.slice("--browser=".length);
|
|
1063
|
+
if (!engines.has(candidate))
|
|
1064
|
+
return "--browser must be chromium, firefox, webkit, or all";
|
|
1065
|
+
browser = candidate;
|
|
1066
|
+
}
|
|
1067
|
+
else if (argument.startsWith("--")) {
|
|
1068
|
+
return `unknown option '${argument}'`;
|
|
1069
|
+
}
|
|
1070
|
+
else if (input) {
|
|
1071
|
+
return `unexpected extra input '${argument}'`;
|
|
1072
|
+
}
|
|
1073
|
+
else {
|
|
1074
|
+
input = argument;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
return { input, browser };
|
|
1078
|
+
}
|
|
1079
|
+
function parseRunArguments(arguments_) {
|
|
1080
|
+
let input = null;
|
|
1081
|
+
let fullStack = false;
|
|
1082
|
+
const programArguments = [];
|
|
1083
|
+
for (let index = 0; index < arguments_.length; index += 1) {
|
|
1084
|
+
const argument = arguments_[index];
|
|
1085
|
+
if (argument === "--") {
|
|
1086
|
+
programArguments.push(...arguments_.slice(index + 1));
|
|
1087
|
+
break;
|
|
1088
|
+
}
|
|
1089
|
+
if (argument === "--stack") {
|
|
1090
|
+
if (fullStack)
|
|
1091
|
+
return "--stack may be provided only once";
|
|
1092
|
+
fullStack = true;
|
|
1093
|
+
continue;
|
|
1094
|
+
}
|
|
1095
|
+
if (argument.startsWith("--"))
|
|
1096
|
+
return `unknown option '${argument}'; program arguments belong after '--'`;
|
|
1097
|
+
if (input)
|
|
1098
|
+
return `unexpected extra input '${argument}'`;
|
|
1099
|
+
input = argument;
|
|
1100
|
+
}
|
|
1101
|
+
return { input, programArguments, fullStack };
|
|
1102
|
+
}
|
|
1103
|
+
function helpRequested(command, arguments_) {
|
|
1104
|
+
const separator = command === "run" ? arguments_.indexOf("--") : -1;
|
|
1105
|
+
const visible = separator === -1 ? arguments_ : arguments_.slice(0, separator);
|
|
1106
|
+
return visible.some((argument) => argument === "--help" || argument === "-h");
|
|
1107
|
+
}
|
|
1108
|
+
function parseSingleOptionalInput(arguments_) {
|
|
1109
|
+
if (arguments_.some((argument) => argument.startsWith("--"))) {
|
|
1110
|
+
return { error: `unknown option '${arguments_.find((argument) => argument.startsWith("--"))}'` };
|
|
1111
|
+
}
|
|
1112
|
+
if (arguments_.length > 1)
|
|
1113
|
+
return { error: `unexpected extra input '${arguments_[1]}'` };
|
|
1114
|
+
return arguments_[0] ?? null;
|
|
1115
|
+
}
|
|
1116
|
+
function parsePreviewArguments(arguments_) {
|
|
1117
|
+
let input = null;
|
|
1118
|
+
let port = 4173;
|
|
1119
|
+
for (let index = 0; index < arguments_.length; index += 1) {
|
|
1120
|
+
const argument = arguments_[index];
|
|
1121
|
+
if (argument === "--port") {
|
|
1122
|
+
const value = arguments_[index + 1];
|
|
1123
|
+
const parsed = value ? Number(value) : Number.NaN;
|
|
1124
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65_535)
|
|
1125
|
+
return "--port requires an integer from 1 to 65535";
|
|
1126
|
+
port = parsed;
|
|
1127
|
+
index += 1;
|
|
1128
|
+
}
|
|
1129
|
+
else if (argument.startsWith("--")) {
|
|
1130
|
+
return `unknown option '${argument}'`;
|
|
1131
|
+
}
|
|
1132
|
+
else if (input) {
|
|
1133
|
+
return `unexpected extra input '${argument}'`;
|
|
1134
|
+
}
|
|
1135
|
+
else {
|
|
1136
|
+
input = argument;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
return { input, port };
|
|
1140
|
+
}
|
|
1141
|
+
function parseDeploymentVerificationArguments(arguments_) {
|
|
1142
|
+
let input = null;
|
|
1143
|
+
let url = null;
|
|
1144
|
+
let json = false;
|
|
1145
|
+
for (let index = 0; index < arguments_.length; index += 1) {
|
|
1146
|
+
const argument = arguments_[index];
|
|
1147
|
+
if (argument === "--json") {
|
|
1148
|
+
if (json)
|
|
1149
|
+
return "--json may be provided only once";
|
|
1150
|
+
json = true;
|
|
1151
|
+
}
|
|
1152
|
+
else if (argument === "--url") {
|
|
1153
|
+
const value = arguments_[index + 1];
|
|
1154
|
+
if (!value || value.startsWith("--"))
|
|
1155
|
+
return "--url requires an absolute deployment origin";
|
|
1156
|
+
if (url)
|
|
1157
|
+
return "--url may be provided only once";
|
|
1158
|
+
url = value;
|
|
1159
|
+
index += 1;
|
|
1160
|
+
}
|
|
1161
|
+
else if (argument.startsWith("--url=")) {
|
|
1162
|
+
if (url)
|
|
1163
|
+
return "--url may be provided only once";
|
|
1164
|
+
url = argument.slice("--url=".length);
|
|
1165
|
+
if (!url)
|
|
1166
|
+
return "--url requires an absolute deployment origin";
|
|
1167
|
+
}
|
|
1168
|
+
else if (argument.startsWith("--")) {
|
|
1169
|
+
return `unknown option '${argument}'`;
|
|
1170
|
+
}
|
|
1171
|
+
else if (input) {
|
|
1172
|
+
return `unexpected extra input '${argument}'`;
|
|
1173
|
+
}
|
|
1174
|
+
else {
|
|
1175
|
+
input = argument;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
return { input, url, json };
|
|
1179
|
+
}
|
|
1180
|
+
function displayInput(input, config) {
|
|
1181
|
+
return input ?? config.manifestPath ?? config.entryPath;
|
|
1182
|
+
}
|
|
1183
|
+
function displayPath(path) {
|
|
1184
|
+
const value = relative(process.cwd(), path);
|
|
1185
|
+
return (value && !value.startsWith("..") ? value : path).replaceAll("\\", "/");
|
|
1186
|
+
}
|
|
1187
|
+
function printHelp(output = process.stdout) {
|
|
1188
|
+
output.write([
|
|
1189
|
+
"VelarScript Compiler",
|
|
1190
|
+
"",
|
|
1191
|
+
"Usage:",
|
|
1192
|
+
" velar check [entry.vel | project-directory]",
|
|
1193
|
+
" velar create <project-directory> [--template <web|node|desktop|docs|library|component>]",
|
|
1194
|
+
" velar install",
|
|
1195
|
+
" velar add <package[@version]>... [--dev]",
|
|
1196
|
+
" velar remove <package>...",
|
|
1197
|
+
" velar update [package...]",
|
|
1198
|
+
" velar dev [entry.vel | project-directory] [--port <port>]",
|
|
1199
|
+
" velar build [entry.vel | project-directory] [--out-dir <directory>]",
|
|
1200
|
+
" velar run [entry.vel | project-directory] [--stack] [-- <program-arguments>...]",
|
|
1201
|
+
" velar verify [project-directory | build-directory]",
|
|
1202
|
+
" velar preview [project-directory | build-directory] [--port <port>]",
|
|
1203
|
+
" velar verify-deployment [project-directory | build-directory] --url <https-origin> [--json]",
|
|
1204
|
+
" velar test [project-directory | file.test.vel]",
|
|
1205
|
+
" velar test [project-directory] --browser [chromium|firefox|webkit|all]",
|
|
1206
|
+
" velar build <single.vel> --out <file.js>",
|
|
1207
|
+
" velar package [project-directory]",
|
|
1208
|
+
" velar format [file.vel | project-directory] [--check]",
|
|
1209
|
+
" velar fix [entry.vel | project-directory]",
|
|
1210
|
+
" velar repro [entry.vel | project-directory] [--out-dir <directory>]",
|
|
1211
|
+
" velar skill",
|
|
1212
|
+
" velar lsp",
|
|
1213
|
+
" velar --version",
|
|
1214
|
+
"",
|
|
1215
|
+
].join("\n"));
|
|
1216
|
+
}
|
|
1217
|
+
const commandNames = new Set([
|
|
1218
|
+
"check", "create", "install", "add", "remove", "update", "dev", "build", "package", "run", "verify", "preview",
|
|
1219
|
+
"verify-deployment", "test", "format", "fix", "repro", "skill", "lsp",
|
|
1220
|
+
]);
|
|
1221
|
+
function printCommandHelp(command, output = process.stdout) {
|
|
1222
|
+
const details = {
|
|
1223
|
+
check: ["Usage: velar check [entry.vel | project-directory]", "Type-checks the whole resolved project without writing build output."],
|
|
1224
|
+
create: ["Usage: velar create <project-directory> [--template <web|node|desktop|docs|library|component>]", "Creates a transactional Web, Node, or Desktop app, documentation site, Core source library, or Web component source package without installing dependencies."],
|
|
1225
|
+
install: ["Usage: velar install", "Installs the current VelarScript project's declared dependencies through npm, then validates the project."],
|
|
1226
|
+
add: ["Usage: velar add <package[@version]>... [--dev]", "Adds npm registry packages and activates packages that declare velar.extension metadata."],
|
|
1227
|
+
remove: ["Usage: velar remove <package>...", "Removes npm packages and their extension-owned VelarScript project configuration."],
|
|
1228
|
+
update: ["Usage: velar update [package...]", "Updates all or selected direct dependencies within package.json ranges through npm."],
|
|
1229
|
+
dev: ["Usage: velar dev [entry.vel | project-directory] [--port <1-65535>]", "Runs the development server; the default port is 5173."],
|
|
1230
|
+
build: ["Usage: velar build [entry.vel | project-directory] [--out-dir <directory>]", " velar build <single.vel> --out <file.js>", "Builds isolated framework application output or JavaScript modules."],
|
|
1231
|
+
package: ["Usage: velar package [project-directory]", "Packages an application through its target-owned native packaging host."],
|
|
1232
|
+
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."],
|
|
1233
|
+
verify: ["Usage: velar verify [project-directory | build-directory]", "Verifies the exact production manifest, inventory, sizes, hashes, and relationships."],
|
|
1234
|
+
preview: ["Usage: velar preview [project-directory | build-directory] [--port <1-65535>]", "Serves only a verified production build; the default port is 4173."],
|
|
1235
|
+
"verify-deployment": ["Usage: velar verify-deployment [project-directory | build-directory] --url <https-origin> [--json]", "Compares verified local bytes, routes, MIME types, and headers with an HTTPS deployment."],
|
|
1236
|
+
test: ["Usage: velar test [project-directory | file.test.vel]", " velar test [project-directory | file.browser.test.vel] --browser[=chromium|firefox|webkit|all]", "Runs Core tests or explicit browser tests; bare --browser defaults to Chromium."],
|
|
1237
|
+
format: ["Usage: velar format [file.vel | project-directory] [--check]", "Formats one file or every manifest-owned .vel source; --check never writes."],
|
|
1238
|
+
fix: [
|
|
1239
|
+
"Usage: velar fix [entry.vel | project-directory]",
|
|
1240
|
+
"Applies every mechanical rewrite the compiler's own diagnostics name — retired spellings with one named successor, line-ending semicolons, and the rest of that family — then reports the diagnostics that are left.",
|
|
1241
|
+
"Nothing that needs a decision is rewritten, and a second run changes nothing.",
|
|
1242
|
+
],
|
|
1243
|
+
repro: [
|
|
1244
|
+
"Usage: velar repro [entry.vel | project-directory] [--out-dir <directory>]",
|
|
1245
|
+
"Writes a self-contained minimal reproduction of a failing check — the entry's modules and the test modules that failed, velar.json, the verbatim diagnostics, and the toolchain, Node, and platform versions — then prints where it went.",
|
|
1246
|
+
"It writes to disk and nothing else: no upload, no network call, no environment or account data, and every absolute path rewritten to a project-relative one.",
|
|
1247
|
+
"The bundle is extracted to a temporary directory and re-checked first; if the copy stops reproducing, the command says so rather than reporting a clean reproduction.",
|
|
1248
|
+
"The default location is .velar/repro inside the project, replaced on each run; a directory named with --out-dir must be empty.",
|
|
1249
|
+
],
|
|
1250
|
+
skill: ["Usage: velar skill", "Prints the packaged VelarScript AI skill brief verbatim to stdout for any coding agent."],
|
|
1251
|
+
lsp: ["Usage: velar lsp", "Runs the stdio language server for an editor host."],
|
|
1252
|
+
};
|
|
1253
|
+
output.write(["VelarScript Compiler", "", ...(details[command] ?? []), ""].join("\n"));
|
|
1254
|
+
}
|
|
1255
|
+
function dependencyResultMessage(action, root, packages, activated, removed) {
|
|
1256
|
+
if (action === "install")
|
|
1257
|
+
return `Installed and validated VelarScript project dependencies -> ${root}\n`;
|
|
1258
|
+
const names = packages.length > 0 ? packages.join(", ") : "all direct dependencies";
|
|
1259
|
+
const detail = activated.length > 0
|
|
1260
|
+
? `; activated extensions: ${activated.join(", ")}`
|
|
1261
|
+
: removed.length > 0
|
|
1262
|
+
? `; removed extensions: ${removed.join(", ")}`
|
|
1263
|
+
: "";
|
|
1264
|
+
const verb = action === "add" ? "Added" : action === "remove" ? "Removed" : "Updated";
|
|
1265
|
+
return `${verb} ${names}${detail} -> ${root}\n`;
|
|
1266
|
+
}
|
|
1267
|
+
try {
|
|
1268
|
+
process.exitCode = await main(process.argv.slice(2));
|
|
1269
|
+
}
|
|
1270
|
+
catch (error) {
|
|
1271
|
+
process.stderr.write(`velar: ${hostErrorMessage(error)}\n`);
|
|
1272
|
+
process.exitCode = 1;
|
|
1273
|
+
}
|
|
1274
|
+
//# sourceMappingURL=cli.js.map
|