@venn-lang/cli 0.1.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/LICENSE +21 -0
- package/README.md +284 -0
- package/dist/bin/venn.mjs +16 -0
- package/dist/cli.mjs +56378 -0
- package/dist/index.d.mts +98 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +916 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +67 -0
- package/src/bin/venn.ts +14 -0
- package/src/cli.ts +299 -0
- package/src/commands/build.ts +97 -0
- package/src/commands/check.ts +143 -0
- package/src/commands/deps.ts +228 -0
- package/src/commands/fmt.ts +55 -0
- package/src/commands/index.ts +2 -0
- package/src/commands/inside-workspace.ts +20 -0
- package/src/commands/list.ts +53 -0
- package/src/commands/new.ts +66 -0
- package/src/commands/run.ts +149 -0
- package/src/commands/script.ts +127 -0
- package/src/commands/upgrade.ts +86 -0
- package/src/commands/verify-plugin.ts +35 -0
- package/src/index.ts +7 -0
- package/src/manifest/index.ts +2 -0
- package/src/manifest/load-env.ts +70 -0
- package/src/manifest/load-manifest.ts +42 -0
- package/src/project/command-targets.ts +53 -0
- package/src/project/index.ts +9 -0
- package/src/project/resolve-targets.ts +70 -0
- package/src/project/select-packages.ts +37 -0
- package/src/project/targets-or-exit.ts +28 -0
- package/src/reporters/colors.ts +17 -0
- package/src/reporters/dot-sink.ts +18 -0
- package/src/reporters/error-line.ts +14 -0
- package/src/reporters/index.ts +9 -0
- package/src/reporters/junit-sink.ts +39 -0
- package/src/reporters/ndjson-stdout.ts +13 -0
- package/src/reporters/pick-reporter.ts +28 -0
- package/src/reporters/pretty/diff-lines.ts +53 -0
- package/src/reporters/pretty/index.ts +1 -0
- package/src/reporters/pretty/pretty-reporter.ts +122 -0
- package/src/reporters/pretty/pretty.types.ts +29 -0
- package/src/reporters/pretty/render.ts +88 -0
- package/src/reporters/problem-reporter.ts +13 -0
- package/src/reporters/problem-sink.ts +20 -0
- package/src/reporters/reporter.types.ts +21 -0
- package/src/run/collect-files.ts +43 -0
- package/src/run/ending.types.ts +17 -0
- package/src/run/exit-code.ts +15 -0
- package/src/run/node-io.ts +27 -0
- package/src/run/npm-loader.ts +41 -0
- package/src/run/package-types.ts +66 -0
- package/src/run/run-file.ts +106 -0
- package/src/run/should-leave.ts +11 -0
- package/src/run/step-titles.ts +61 -0
- package/src/shutdown/create-leave.ts +42 -0
- package/src/shutdown/create-shutdown.ts +34 -0
- package/src/shutdown/index.ts +7 -0
- package/src/shutdown/install-exit-hook.ts +21 -0
- package/src/shutdown/install-fault-hooks.ts +30 -0
- package/src/shutdown/install-hooks.ts +36 -0
- package/src/shutdown/install-signal-hooks.ts +26 -0
- package/src/shutdown/shutdown.types.ts +20 -0
- package/src/title/index.ts +2 -0
- package/src/title/program-title.ts +15 -0
- package/src/title/set-program-title.ts +15 -0
- package/src/upgrade/index.ts +6 -0
- package/src/upgrade/install-site.ts +70 -0
- package/src/upgrade/latest-version.ts +50 -0
- package/src/upgrade/upgrade-command.ts +32 -0
- package/src/upgrade/upgrade-plan.ts +36 -0
- package/src/upgrade/upgrade.types.ts +17 -0
- package/src/upgrade/version.ts +21 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { PACKAGE_NAME } from "./upgrade-plan.js";
|
|
2
|
+
|
|
3
|
+
/** How long to wait on the registry before giving up and saying so. */
|
|
4
|
+
const TIMEOUT_MS = 5_000;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The newest published version, asked of the registry.
|
|
8
|
+
*
|
|
9
|
+
* Only the `dist-tags` document is fetched rather than the full package
|
|
10
|
+
* metadata, which for this package is megabytes of version history nobody
|
|
11
|
+
* asked for.
|
|
12
|
+
*
|
|
13
|
+
* @returns The version under the `latest` tag, or nothing when the registry
|
|
14
|
+
* cannot be reached. Being offline is not an error worth stopping for.
|
|
15
|
+
*/
|
|
16
|
+
export async function latestVersion(): Promise<string | undefined> {
|
|
17
|
+
const url = `https://registry.npmjs.org/-/package/${encodeURIComponent(PACKAGE_NAME)}/dist-tags`;
|
|
18
|
+
try {
|
|
19
|
+
const answer = await fetch(url, { signal: AbortSignal.timeout(TIMEOUT_MS) });
|
|
20
|
+
if (!answer.ok) return undefined;
|
|
21
|
+
const tags = (await answer.json()) as Record<string, string>;
|
|
22
|
+
return typeof tags.latest === "string" ? tags.latest : undefined;
|
|
23
|
+
} catch {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Whether `candidate` is a later release than `current`.
|
|
30
|
+
*
|
|
31
|
+
* Compares the numeric parts only. A prerelease is never offered as an upgrade
|
|
32
|
+
* to someone on a stable version, since opting into one is a decision rather
|
|
33
|
+
* than an update.
|
|
34
|
+
*/
|
|
35
|
+
export function isNewer(args: { current: string; candidate: string }): boolean {
|
|
36
|
+
if (args.candidate.includes("-")) return false;
|
|
37
|
+
const now = parts(args.current);
|
|
38
|
+
const next = parts(args.candidate);
|
|
39
|
+
for (let at = 0; at < 3; at += 1) {
|
|
40
|
+
const a = next[at] ?? 0;
|
|
41
|
+
const b = now[at] ?? 0;
|
|
42
|
+
if (a !== b) return a > b;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parts(version: string): number[] {
|
|
48
|
+
const stable = version.split("-")[0] ?? version;
|
|
49
|
+
return stable.split(".").map((piece) => Number.parseInt(piece, 10) || 0);
|
|
50
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import type { InstallSite, UpgradeOptions } from "./upgrade.types.js";
|
|
3
|
+
import { upgradeCommandFor } from "./upgrade-plan.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The shell command that moves this install to the latest version.
|
|
7
|
+
*
|
|
8
|
+
* Runs the manager rather than rewriting files: the CLI cannot replace itself
|
|
9
|
+
* while it is executing, and on Windows the running executable is locked.
|
|
10
|
+
*
|
|
11
|
+
* @returns The exit code of the manager, or 1 when it could not be started.
|
|
12
|
+
*/
|
|
13
|
+
export function runUpgrade(args: { site: InstallSite; options: UpgradeOptions }): Promise<number> {
|
|
14
|
+
const command = upgradeCommandFor(args.site.manager);
|
|
15
|
+
if (!command) return Promise.resolve(1);
|
|
16
|
+
if (args.options.dryRun) {
|
|
17
|
+
process.stdout.write(`${command.join(" ")}\n`);
|
|
18
|
+
return Promise.resolve(0);
|
|
19
|
+
}
|
|
20
|
+
return spawned(command);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function spawned(command: readonly string[]): Promise<number> {
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
const child = spawn(command[0] as string, command.slice(1), {
|
|
26
|
+
stdio: "inherit",
|
|
27
|
+
shell: process.platform === "win32",
|
|
28
|
+
});
|
|
29
|
+
child.on("error", () => resolve(1));
|
|
30
|
+
child.on("close", (code) => resolve(code ?? 1));
|
|
31
|
+
});
|
|
32
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { InstallSite, PackageManager } from "./upgrade.types.js";
|
|
2
|
+
|
|
3
|
+
/** The published name, which is what a manager is asked to install. */
|
|
4
|
+
export const PACKAGE_NAME = "@venn-lang/cli";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* How each manager is told to install the latest version globally.
|
|
8
|
+
*
|
|
9
|
+
* @returns The command as its argument list, or nothing when the manager is
|
|
10
|
+
* unknown and guessing would be worse than saying so.
|
|
11
|
+
*/
|
|
12
|
+
export function upgradeCommandFor(manager: PackageManager): readonly string[] | undefined {
|
|
13
|
+
if (manager === "npm") return ["npm", "install", "-g", `${PACKAGE_NAME}@latest`];
|
|
14
|
+
if (manager === "pnpm") return ["pnpm", "add", "-g", `${PACKAGE_NAME}@latest`];
|
|
15
|
+
if (manager === "bun") return ["bun", "add", "-g", `${PACKAGE_NAME}@latest`];
|
|
16
|
+
if (manager === "yarn") return ["yarn", "global", "add", `${PACKAGE_NAME}@latest`];
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Why an upgrade cannot proceed, phrased for the person who typed the command. */
|
|
21
|
+
export function refusalFor(site: InstallSite): string | undefined {
|
|
22
|
+
if (site.manager === "unknown") {
|
|
23
|
+
return [
|
|
24
|
+
"Cannot tell how this copy of venn was installed, so it will not guess.",
|
|
25
|
+
`Reinstall it with your package manager, for example: npm install -g ${PACKAGE_NAME}@latest`,
|
|
26
|
+
].join("\n");
|
|
27
|
+
}
|
|
28
|
+
if (!site.global) {
|
|
29
|
+
return [
|
|
30
|
+
"This copy belongs to the project, not to you.",
|
|
31
|
+
`Its version is pinned in package.json, so upgrading here would be undone by the next install.`,
|
|
32
|
+
`Update it there instead: ${site.manager} ${site.manager === "npm" ? "install" : "add"} -D ${PACKAGE_NAME}@latest`,
|
|
33
|
+
].join("\n");
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** The package managers that can install a global CLI. */
|
|
2
|
+
export type PackageManager = "npm" | "pnpm" | "bun" | "yarn" | "unknown";
|
|
3
|
+
|
|
4
|
+
/** Where a copy of the CLI came from. */
|
|
5
|
+
export interface InstallSite {
|
|
6
|
+
manager: PackageManager;
|
|
7
|
+
/** False when the copy belongs to a project rather than to the user. */
|
|
8
|
+
global: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** What `venn upgrade` was asked to do. */
|
|
12
|
+
export interface UpgradeOptions {
|
|
13
|
+
/** Skip the confirmation. For scripts, never for a person. */
|
|
14
|
+
yes?: boolean;
|
|
15
|
+
/** Report what would happen and change nothing. */
|
|
16
|
+
dryRun?: boolean;
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The version of the CLI that is running.
|
|
5
|
+
*
|
|
6
|
+
* Read from the package manifest rather than written into the source, so a
|
|
7
|
+
* release cannot ship a binary that reports the version before it. The manifest
|
|
8
|
+
* sits one level above the bundle, which is true both in `dist` and in `src`
|
|
9
|
+
* during development.
|
|
10
|
+
*/
|
|
11
|
+
export const VERSION: string = read();
|
|
12
|
+
|
|
13
|
+
function read(): string {
|
|
14
|
+
try {
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
const manifest = require("../../package.json") as { version?: string };
|
|
17
|
+
return manifest.version ?? "0.0.0";
|
|
18
|
+
} catch {
|
|
19
|
+
return "0.0.0";
|
|
20
|
+
}
|
|
21
|
+
}
|