Skip to content

Commit

Permalink
Wrangler and C3: Move the cli folder of C3 into @cloudflare/cli and m…
Browse files Browse the repository at this point in the history
…ake Wrangler and C3 depend on it

We want to start using @clack/core and C3-like components in Wrangler, so the logical next step is to make these components available to wrangler and C3.

./helpers/cli.ts in C3 is now index.ts in @cloudflare/cli, didn't include openInBrowser,C3_DEFAULTS and WRANGLER_DEFAULTS.
./helpers/colors in C3 is now colors.ts in @cloudflare/cli.
./helpers/interactive.ts in C3 is now interactive.ts in @cloudflare/cli.
  • Loading branch information
gabivlj committed Oct 17, 2023
1 parent 36d4978 commit 435beb4
Show file tree
Hide file tree
Showing 38 changed files with 533 additions and 268 deletions.
7 changes: 7 additions & 0 deletions .changeset/itchy-ducks-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@cloudflare/cli": major
"create-cloudflare": patch
"wrangler": patch
---

Move helper cli files of C3 into @cloudflare/cli and make Wrangler and C3 depend on it
3 changes: 3 additions & 0 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Cloudflare CLI

All things related to rendering the CLI for workers-sdk.
8 changes: 8 additions & 0 deletions packages/cli/__tests__/cli.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { describe, expect, test } from "vitest";
import { space } from "..";

describe("cli", () => {
test("test spaces", () => {
expect(space(300)).toHaveLength(300);
});
});
File renamed without changes.
110 changes: 110 additions & 0 deletions packages/cli/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { exit } from "process";
import { brandColor, dim, gray, white, red, hidden, bgRed } from "./colors";

export const shapes = {
diamond: "◇",
dash: "─",
radioInactive: "○",
radioActive: "●",

bar: "│",
leftT: "├",
rigthT: "┤",

arrows: {
left: "‹",
right: "›",
},

corners: {
tl: "╭",
bl: "╰",
tr: "╮",
br: "╯",
},
};

export const status = {
error: bgRed(` ERROR `),
warning: bgRed(` WARNING `),
info: bgRed(` INFO `),
success: bgRed(` SUCCESS `),
};

// Returns a string containing n non-trimmable spaces
// This is useful for places where clack trims lines of output
// but we need leading spaces
export const space = (n = 1) => {
return hidden("\u200A".repeat(n));
};

// Primitive for printing to stdout. Use this instead of
// console.log or printing to stdout directly
export const logRaw = (msg: string) => {
process.stdout.write(`${msg}\n`);
};

// A simple stylized log for use within a prompt
export const log = (msg: string) => {
const lines = msg.split("\n").map((ln) => `${gray(shapes.bar)} ${white(ln)}`);

logRaw(lines.join("\n"));
};

export const newline = () => {
log("");
};

// Log a simple status update with a style similar to the clack spinner
export const updateStatus = (msg: string) => {
logRaw(`${gray(shapes.leftT)} ${msg}`);
newline();
};

export const startSection = (heading: string, subheading?: string) => {
logRaw(
`${gray(shapes.corners.tl)} ${brandColor(heading)} ${
subheading ? dim(subheading) : ""
}`
);
newline();
};

export const endSection = (heading: string, subheading?: string) => {
logRaw(
`${gray(shapes.corners.bl)} ${brandColor(heading)} ${
subheading ? dim(subheading) : ""
}\n`
);
};

export const cancel = (msg: string) => {
newline();
logRaw(`${gray(shapes.corners.bl)} ${white.bgRed(` X `)} ${dim(msg)}`);
};

export const warn = (msg: string) => {
newline();
logRaw(`${gray(shapes.corners.bl)} ${status.warning} ${dim(msg)}`);
};

// Strip the ansi color characters out of the line when calculating
// line length, otherwise the padding will be thrown off
// Used from https://github.com/natemoo-re/clack/blob/main/packages/prompts/src/index.ts
export const stripAnsi = (str: string) => {
const pattern = [
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))",
].join("|");
const regex = RegExp(pattern, "g");

return str.replace(regex, "");
};

export const crash = (msg?: string): never => {
if (msg) {
process.stderr.write(red(msg));
process.stderr.write("\n");
}
exit(1);
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { TextPrompt, SelectPrompt, ConfirmPrompt } from "@clack/core";
import { ConfirmPrompt, SelectPrompt, TextPrompt } from "@clack/core";
import ansiEscapes from "ansi-escapes";
import logUpdate from "log-update";
import { shapes, cancel, space, status, newline } from "./cli";
import { blue, dim, gray, brandColor, bold } from "./colors";
import type { ChalkInstance } from "chalk";
import type { C3Arg } from "types";
import logUpdate from "log-update";
import { blue, bold, brandColor, dim, gray } from "./colors";
import { cancel, newline, shapes, space, status } from "./index";

export type Arg = string | boolean | string[] | undefined;
const grayBar = gray(shapes.bar);
const blCorner = gray(shapes.corners.bl);
const leftT = gray(shapes.leftT);
Expand All @@ -25,9 +25,9 @@ export type BasePromptConfig = {
// The status label to be shown after submitting
label: string;
// Pretty-prints the value in the interactive prompt
format?: (value: C3Arg) => string;
format?: (value: Arg) => string;
// Returns a user displayed error if the value is invalid
validate?: (value: C3Arg) => string | void;
validate?: (value: Arg) => string | void;
};

export type TextPromptConfig = BasePromptConfig & {
Expand Down Expand Up @@ -104,7 +104,7 @@ type Renderer = (props: {
state?: string;
error?: string;
cursor?: number;
value: C3Arg;
value: Arg;
}) => string[];

const renderSubmit = (config: PromptConfig, value: string) => {
Expand Down Expand Up @@ -144,28 +144,27 @@ const getTextRenderers = (config: TextPromptConfig) => {
format: _format,
} = config;
const helpText = _helpText ?? "";
const format = _format ?? ((val: C3Arg) => String(val));
const format = _format ?? ((val: Arg) => String(val));

return {
initial: () => [
`${blCorner} ${bold(question)} ${dim(helpText)}`,
`${space(2)}${gray(format(defaultValue))}`,
``, // extra line for readability
],
active: ({ value }: { value: C3Arg }) => [
active: ({ value }: { value: Arg }) => [
`${blCorner} ${bold(question)} ${dim(helpText)}`,
`${space(2)}${format(value || dim(defaultValue))}`,
``, // extra line for readability
],
error: ({ value, error }: { value: C3Arg; error: string }) => [
error: ({ value, error }: { value: Arg; error: string }) => [
`${leftT} ${status.error} ${dim(error)}`,
`${grayBar}`,
`${blCorner} ${question} ${dim(helpText)}`,
`${space(2)}${format(value)}`,
``, // extra line for readability
],
submit: ({ value }: { value: C3Arg }) =>
renderSubmit(config, format(value)),
submit: ({ value }: { value: Arg }) => renderSubmit(config, format(value)),
cancel: handleCancel,
};
};
Expand Down Expand Up @@ -198,7 +197,7 @@ const getSelectRenderers = (config: SelectPromptConfig) => {
active: defaultRenderer,
confirm: defaultRenderer,
error: defaultRenderer,
submit: ({ value }: { value: C3Arg }) =>
submit: ({ value }: { value: Arg }) =>
renderSubmit(
config,
options.find((o) => o.value === value)?.label as string
Expand Down Expand Up @@ -228,7 +227,7 @@ const getConfirmRenderers = (config: ConfirmPromptConfig) => {
active: defaultRenderer,
confirm: defaultRenderer,
error: defaultRenderer,
submit: ({ value }: { value: C3Arg }) =>
submit: ({ value }: { value: Arg }) =>
renderSubmit(config, value ? "yes" : "no"),
cancel: handleCancel,
};
Expand Down
37 changes: 37 additions & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@cloudflare/cli",
"version": "0.1.0",
"description": "An SDK to build workers-sdk CLIs",
"keywords": [
"cloudflare",
"workers",
"cloudflare workers",
"cli"
],
"scripts": {
"check:type": "tsc",
"test": "vitest run",
"test:ci": "vitest run"
},
"repository": {
"type": "git",
"url": "https://github.com/cloudflare/workers-sdk.git",
"directory": "packages/cli"
},
"license": "MIT OR Apache-2.0",
"author": "wrangler@cloudflare.com",
"devDependencies": {
"@clack/core": "^0.3.2",
"@clack/prompts": "^0.6.3",
"@cloudflare/eslint-config-worker": "*",
"@cloudflare/workers-tsconfig": "workspace:*",
"@typescript-eslint/eslint-plugin": "^5.55.0",
"@typescript-eslint/parser": "^5.55.0",
"ansi-escapes": "^6.2.0",
"chalk": "^5.2.0",
"esbuild": "^0.17.12",
"log-update": "^5.0.1",
"pnpm": "^8.6.11",
"undici": "5.20.0"
}
}
17 changes: 17 additions & 0 deletions packages/cli/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"root": true,
"extends": "@cloudflare/workers-tsconfig/tsconfig.json",
"include": ["**/*.ts"],
"exclude": ["node_modules"],
"compilerOptions": {
"target": "ESNext",
"module": "CommonJS",
"moduleResolution": "node",
"allowJs": false,
"strict": true,
"esModuleInterop": true,
"outDir": "dist",
"types": ["node"],
"resolveJsonModule": true
}
}
7 changes: 7 additions & 0 deletions packages/cli/turbo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"$schema": "http://turbo.build/schema.json",
"extends": ["//"],

"pipeline": {
}
}
9 changes: 9 additions & 0 deletions packages/cli/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { defineConfig } from "vitest/config";

export default defineConfig({
test: {
include: ["**/__tests__/**/*.{test,spec}.{ts,js,tsx,jsx}"],
testTimeout: 30000,
setupFiles: "./vite.setup.ts",
},
});
3 changes: 3 additions & 0 deletions packages/cli/vite.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { vi } from "vitest";

vi.mock("log-update");
4 changes: 2 additions & 2 deletions packages/create-cloudflare/e2e-tests/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { existsSync, mkdtempSync, realpathSync, rmSync } from "fs";
import crypto from "node:crypto";
import { tmpdir } from "os";
import { join } from "path";
import { spinnerFrames } from "@cloudflare/cli/interactive";
import { spawn } from "cross-spawn";
import { sleep } from "helpers/common";
import { spinnerFrames } from "helpers/interactive";
import { detectPackageManager } from "helpers/packages";
import { fetch } from "undici";
import { expect } from "vitest";
import { version } from "../package.json";
import type { SpinnerStyle } from "helpers/interactive";
import type { SpinnerStyle } from "@cloudflare/cli/interactive";

export const C3_E2E_PREFIX = "c3-e2e-";

Expand Down
4 changes: 1 addition & 3 deletions packages/create-cloudflare/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
"devDependencies": {
"@babel/parser": "^7.21.3",
"@babel/types": "^7.21.4",
"@clack/core": "^0.3.2",
"@clack/prompts": "^0.6.3",
"@cloudflare/cli": "workspace:*",
"@cloudflare/eslint-config-worker": "*",
"@cloudflare/workers-tsconfig": "workspace:*",
"@cloudflare/workers-types": "^4.20230419.0",
Expand All @@ -58,7 +58,6 @@
"@types/yargs": "^17.0.22",
"@typescript-eslint/eslint-plugin": "^5.55.0",
"@typescript-eslint/parser": "^5.55.0",
"ansi-escapes": "^6.2.0",
"chalk": "^5.2.0",
"command-exists": "^1.2.9",
"cross-spawn": "^7.0.3",
Expand All @@ -67,7 +66,6 @@
"execa": "^7.1.1",
"glob": "^10.3.3",
"haikunator": "^2.1.2",
"log-update": "^5.0.1",
"open": "^8.4.0",
"pnpm": "^8.6.11",
"recast": "^0.22.0",
Expand Down
11 changes: 8 additions & 3 deletions packages/create-cloudflare/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
#!/usr/bin/env node
import { crash, logRaw, startSection } from "@cloudflare/cli";
import { blue, dim } from "@cloudflare/cli/colors";
import {
isInteractive,
spinner,
spinnerFrames,
} from "@cloudflare/cli/interactive";
import { parseArgs, processArgument } from "helpers/args";
import { C3_DEFAULTS, crash, logRaw, startSection } from "helpers/cli";
import { blue, dim } from "helpers/colors";
import { C3_DEFAULTS } from "helpers/cli";
import { runCommand } from "helpers/command";
import { isInteractive, spinnerFrames, spinner } from "helpers/interactive";
import { detectPackageManager } from "helpers/packages";
import semver from "semver";
import { version } from "../package.json";
Expand Down
13 changes: 6 additions & 7 deletions packages/create-cloudflare/src/common.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
import { existsSync, mkdirSync, readdirSync } from "fs";
import { basename, dirname, resolve } from "path";
import { chdir } from "process";
import { getFrameworkCli } from "frameworks/index";
import { processArgument } from "helpers/args";
import {
C3_DEFAULTS,
crash,
endSection,
log,
logRaw,
newline,
openInBrowser,
shapes,
startSection,
updateStatus,
} from "helpers/cli";
import { dim, blue, gray, bgGreen, brandColor } from "helpers/colors";
} from "@cloudflare/cli";
import { brandColor, dim, gray, bgGreen, blue } from "@cloudflare/cli/colors";
import { inputPrompt, spinner } from "@cloudflare/cli/interactive";
import { getFrameworkCli } from "frameworks/index";
import { processArgument } from "helpers/args";
import { C3_DEFAULTS, openInBrowser } from "helpers/cli";
import {
listAccounts,
printAsyncStatus,
runCommand,
runCommands,
wranglerLogin,
} from "helpers/command";
import { inputPrompt, spinner } from "helpers/interactive";
import { detectPackageManager } from "helpers/packages";
import { poll } from "helpers/poll";
import { version as wranglerVersion } from "wrangler/package.json";
Expand Down
Loading

0 comments on commit 435beb4

Please sign in to comment.