From 56584481f0ab02225434a3aa5f3ae73597002453 Mon Sep 17 00:00:00 2001 From: James Opstad <13586373+jamesopstad@users.noreply.github.com> Date: Fri, 23 Jan 2026 14:57:36 +0000 Subject: [PATCH 1/3] Skip modifying the root `tsconfig.json` in projects that use TypeScript project references (#12062) * Add tests for project references handling * Skip tsconfig modification when tsconfig.json has project references * Add changeset * Skip E2E validation of compilerTypes in tsconfig.json for projects using project references --- .changeset/long-spiders-shop.md | 5 ++++ .../e2e/helpers/framework-helpers.ts | 11 ++++++-- .../src/__tests__/workers.test.ts | 26 +++++++++++++++++++ packages/create-cloudflare/src/workers.ts | 17 ++++++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 .changeset/long-spiders-shop.md diff --git a/.changeset/long-spiders-shop.md b/.changeset/long-spiders-shop.md new file mode 100644 index 000000000000..7a2b958af145 --- /dev/null +++ b/.changeset/long-spiders-shop.md @@ -0,0 +1,5 @@ +--- +"create-cloudflare": patch +--- + +Skip modifying the root `tsconfig.json` in projects that use TypeScript project references. diff --git a/packages/create-cloudflare/e2e/helpers/framework-helpers.ts b/packages/create-cloudflare/e2e/helpers/framework-helpers.ts index 15479826d03d..05a3976da74c 100644 --- a/packages/create-cloudflare/e2e/helpers/framework-helpers.ts +++ b/packages/create-cloudflare/e2e/helpers/framework-helpers.ts @@ -338,8 +338,15 @@ export async function verifyTypes( } const tsconfigPath = join(projectPath, "tsconfig.json"); - const tsconfigTypes = jsonc.parse(readFile(tsconfigPath)).compilerOptions - ?.types; + const tsconfig = jsonc.parse(readFile(tsconfigPath)); + + // Skip tsconfig verification if project uses TypeScript project references + // C3 doesn't modify the root tsconfig in this case - types are defined in child tsconfigs + if (Array.isArray(tsconfig.references) && tsconfig.references.length > 0) { + return; + } + + const tsconfigTypes = tsconfig.compilerOptions?.types; if (workersTypes === "generated") { expect(tsconfigTypes).toContain(typesPath); } diff --git a/packages/create-cloudflare/src/__tests__/workers.test.ts b/packages/create-cloudflare/src/__tests__/workers.test.ts index 1b23445009e7..18ae15cf507d 100644 --- a/packages/create-cloudflare/src/__tests__/workers.test.ts +++ b/packages/create-cloudflare/src/__tests__/workers.test.ts @@ -110,4 +110,30 @@ describe("updateTsConfig", () => { `./worker-configuration.d.ts`, ); }); + + test("skips modification when tsconfig uses project references", async () => { + vi.mocked(readFile).mockImplementation( + () => `{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] + }`, + ); + await updateTsConfig(ctx, { usesNodeCompat: false }); + expect(writeFile).not.toHaveBeenCalled(); + }); + + test("modifies tsconfig when references array is empty", async () => { + ctx.template.workersTypes = "installed"; + vi.mocked(readFile).mockImplementation( + () => `{ + "compilerOptions": { "types": [] }, + "references": [] + }`, + ); + await updateTsConfig(ctx, { usesNodeCompat: false }); + expect(writeFile).toHaveBeenCalled(); + }); }); diff --git a/packages/create-cloudflare/src/workers.ts b/packages/create-cloudflare/src/workers.ts index a09cc5ae593d..767962677fc1 100644 --- a/packages/create-cloudflare/src/workers.ts +++ b/packages/create-cloudflare/src/workers.ts @@ -105,6 +105,13 @@ export async function updateTsConfig( const tsconfig = readFile(tsconfigPath); try { const config = jsonc.parse(tsconfig); + + // Skip if tsconfig uses project references + // Types should be defined in child tsconfigs (e.g., tsconfig.worker.json) + if (hasProjectReferences(config)) { + return; + } + const currentTypes: string[] = config.compilerOptions?.types ?? []; let newTypes = new Set(currentTypes); if (ctx.template.workersTypes === "installed") { @@ -166,6 +173,16 @@ export async function updateTsConfig( } } +function hasProjectReferences(config: unknown): boolean { + if (typeof config !== "object" || config === null) { + return false; + } + + const tsconfig = config as Record; + + return Array.isArray(tsconfig.references) && tsconfig.references.length > 0; +} + /** * TODO: delete if/when qwik move to wrangler v4 * Installs the latest version of the `@cloudflare/workers-types` package From 3bd94e0db7f34163d5bf7930dee7404f1d92a670 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 23 Jan 2026 16:00:01 +0000 Subject: [PATCH 2/3] Slightly Improve process for experimental features in wrangler (#11938) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Augments Claude changesets review instructions to ensure that experimental features are appropriately handled * Add note in the Wrangler CONTRIBUTING.md file --------- Co-authored-by: Somhairle MacLeòid --- .github/workflows/changeset-review.yml | 1 + packages/wrangler/CONTRIBUTING.md | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/changeset-review.yml b/.github/workflows/changeset-review.yml index 445b37537517..9b64c9c434af 100644 --- a/.github/workflows/changeset-review.yml +++ b/.github/workflows/changeset-review.yml @@ -64,6 +64,7 @@ jobs: 3. **Markdown Headers**: No h1/h2/h3 headers (breaks changelog formatting) 4. **Analytics**: If the change collects more analytics, it should be a minor even though there is no user-visible change 5. **Dependabot**: Do not validate dependency update changesets for create-cloudflare + 6. **Experimental features**: Changesets for experimental features should include note on how users can opt in. If all changesets pass, just output "✅ All changesets look good" - no need for a detailed checklist. diff --git a/packages/wrangler/CONTRIBUTING.md b/packages/wrangler/CONTRIBUTING.md index 463d3a28bd8e..585f3d0229e9 100644 --- a/packages/wrangler/CONTRIBUTING.md +++ b/packages/wrangler/CONTRIBUTING.md @@ -135,6 +135,13 @@ Errors are caught at the top-level and formatted for the console. ## Best Practices +### Integration with Cloudflare REST API + +The [Cloudflare REST API](https://developers.cloudflare.com/api/) whenever possible should not be interacted directly with, the [Cloudflare TypeScript SDK](https://www.npmjs.com/package/cloudflare) package should be used instead. This helps the type safety of the code as well as preventing the usage of undocumented and unstable features that might be present in the raw REST API. + +The SDK is set up for every command's handler ([code](https://github.com/cloudflare/workers-sdk/blob/20467fda1/packages/wrangler/src/core/register-yargs-command.ts#L200)) and unless there are other needs, this should be the preferred way of consuming it. +You can see an example of using the SDK in the [KV create command](https://github.com/cloudflare/workers-sdk/blob/20467fda1/packages/wrangler/src/kv/index.ts#L110). + ### Status / Deprecation Status can be alpha, "private beta", "open beta", or stable. Breaking changes can freely be made in alpha or "private beta". Try avoid breaking changes in "open beta" but are acceptable and should be called out in [a changeset](../../CONTRIBUTING.md#Changesets). From 014e7aa2074d3464e012876b70e22af44fa26e5d Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Fri, 23 Jan 2026 18:36:50 +0000 Subject: [PATCH 3/3] chore: use native stripVTControlCharacters (#11853) * chore: use native stripVTControlCharacters Since Node 16.x, there is a built-in function, `stripVTControlCharacters`. This does the same job as the `strip-ansi` package and makes it redundant going forward. The minimum node version in these projects is at least 16, so we should be good to switch. * chore: remove unnecessary package-lock.json from import-npm fixture * chore: remove private package from changeset * chore: fix formatting --------- Co-authored-by: Edmund Hung --- .changeset/cuddly-shrimps-speak.md | 6 + fixtures/import-npm/.gitignore | 1 + fixtures/import-npm/package-lock.json | 185 ------------------ fixtures/interactive-dev-tests/package.json | 1 - .../interactive-dev-tests/tests/index.test.ts | 8 +- fixtures/worker-logs/package.json | 1 - fixtures/worker-logs/tests/index.test.ts | 4 +- packages/miniflare/src/shared/log.ts | 20 +- .../bindings/__tests__/shortcuts.spec.ts | 4 +- .../playground/package.json | 1 - packages/wrangler/e2e/helpers/normalize.ts | 4 +- packages/wrangler/e2e/helpers/read-until.ts | 4 +- packages/wrangler/package.json | 1 - packages/wrangler/src/cli-hotkeys.ts | 8 +- packages/wrangler/src/utils/log-file.ts | 4 +- packages/wrangler/src/utils/print-bindings.ts | 8 +- .../src/utils/render-labelled-values.ts | 8 +- packages/wrangler/src/wrangler-banner.ts | 6 +- pnpm-lock.yaml | 12 -- 19 files changed, 43 insertions(+), 243 deletions(-) create mode 100644 .changeset/cuddly-shrimps-speak.md create mode 100644 fixtures/import-npm/.gitignore delete mode 100644 fixtures/import-npm/package-lock.json diff --git a/.changeset/cuddly-shrimps-speak.md b/.changeset/cuddly-shrimps-speak.md new file mode 100644 index 000000000000..6a6a41274b11 --- /dev/null +++ b/.changeset/cuddly-shrimps-speak.md @@ -0,0 +1,6 @@ +--- +"miniflare": patch +"wrangler": patch +--- + +Use built-in stripVTControlCharacters utility rather than the `strip-ansi` package. diff --git a/fixtures/import-npm/.gitignore b/fixtures/import-npm/.gitignore new file mode 100644 index 000000000000..d8b83df9cdb6 --- /dev/null +++ b/fixtures/import-npm/.gitignore @@ -0,0 +1 @@ +package-lock.json diff --git a/fixtures/import-npm/package-lock.json b/fixtures/import-npm/package-lock.json deleted file mode 100644 index 2065f61f45bb..000000000000 --- a/fixtures/import-npm/package-lock.json +++ /dev/null @@ -1,185 +0,0 @@ -{ - "name": "@fixture/import-npm", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@fixture/import-npm", - "workspaces": [ - "packages/*" - ] - }, - "../../packages/workers-tsconfig": { - "name": "@cloudflare/workers-tsconfig", - "version": "0.0.0", - "dev": true - }, - "../../packages/wrangler": { - "version": "4.18.0", - "dev": true, - "license": "MIT OR Apache-2.0", - "dependencies": { - "@cloudflare/kv-asset-handler": "workspace:*", - "@cloudflare/unenv-preset": "2.3.2", - "blake3-wasm": "2.1.5", - "esbuild": "catalog:default", - "miniflare": "workspace:*", - "path-to-regexp": "6.3.0", - "unenv": "2.0.0-rc.17", - "workerd": "1.20250525.0" - }, - "bin": { - "wrangler": "bin/wrangler.js", - "wrangler2": "bin/wrangler.js" - }, - "devDependencies": { - "@aws-sdk/client-s3": "^3.721.0", - "@cloudflare/cli": "workspace:*", - "@cloudflare/eslint-config-shared": "workspace:*", - "@cloudflare/pages-shared": "workspace:^", - "@cloudflare/types": "6.18.4", - "@cloudflare/workers-shared": "workspace:*", - "@cloudflare/workers-tsconfig": "workspace:*", - "@cloudflare/workers-types": "^4.20250525.0", - "@cspotcode/source-map-support": "0.8.1", - "@iarna/toml": "^3.0.0", - "@sentry/node": "^7.86.0", - "@sentry/types": "^7.86.0", - "@sentry/utils": "^7.86.0", - "@types/command-exists": "^1.2.0", - "@types/glob-to-regexp": "^0.4.1", - "@types/is-ci": "^3.0.0", - "@types/javascript-time-ago": "^2.0.3", - "@types/mime": "^3.0.4", - "@types/minimatch": "^5.1.2", - "@types/node": "catalog:default", - "@types/node-forge": "^1.3.11", - "@types/prompts": "^2.0.14", - "@types/resolve": "^1.20.6", - "@types/shell-quote": "^1.7.2", - "@types/signal-exit": "^3.0.1", - "@types/supports-color": "^8.1.1", - "@types/ws": "^8.5.7", - "@types/yargs": "^17.0.22", - "@vitest/ui": "catalog:default", - "@webcontainer/env": "^1.1.0", - "chalk": "^5.2.0", - "chokidar": "^4.0.1", - "cli-table3": "^0.6.3", - "cmd-shim": "^4.1.0", - "command-exists": "^1.2.9", - "concurrently": "^8.2.2", - "date-fns": "^4.1.0", - "devtools-protocol": "^0.0.1182435", - "dotenv": "^16.3.1", - "execa": "^6.1.0", - "find-up": "^6.3.0", - "get-port": "^7.0.0", - "glob-to-regexp": "^0.4.1", - "https-proxy-agent": "7.0.2", - "is-ci": "^3.0.1", - "itty-time": "^1.0.6", - "javascript-time-ago": "^2.5.4", - "md5-file": "5.0.0", - "mime": "^3.0.0", - "minimatch": "^5.1.0", - "mock-socket": "^9.3.1", - "msw": "2.4.3", - "node-forge": "^1.3.1", - "open": "^8.4.0", - "p-queue": "^7.2.0", - "patch-console": "^1.0.0", - "pretty-bytes": "^6.0.0", - "prompts": "^2.4.2", - "resolve": "^1.22.8", - "rimraf": "catalog:default", - "selfsigned": "^2.0.1", - "semiver": "^1.1.0", - "shell-quote": "^1.8.1", - "signal-exit": "^3.0.7", - "source-map": "^0.6.1", - "strip-ansi": "^7.1.0", - "supports-color": "^9.2.2", - "timeago.js": "^4.0.2", - "ts-dedent": "^2.2.0", - "ts-json-schema-generator": "^1.5.0", - "tsup": "8.3.0", - "typescript": "catalog:default", - "undici": "catalog:default", - "update-check": "^1.5.4", - "vitest": "catalog:default", - "vitest-websocket-mock": "^0.4.0", - "ws": "catalog:default", - "xdg-app-paths": "^8.3.0", - "xxhash-wasm": "^1.0.1", - "yargs": "^17.7.2" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@cloudflare/workers-types": "^4.20250525.0" - }, - "peerDependenciesMeta": { - "@cloudflare/workers-types": { - "optional": true - } - } - }, - "../import-wasm-static": { - "name": "@fixture/import-wasm-static" - }, - "node_modules/@cloudflare/workers-tsconfig": { - "resolved": "../../packages/workers-tsconfig", - "link": true - }, - "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/@fixture/import-wasm-static": { - "resolved": "../import-wasm-static", - "link": true - }, - "node_modules/import-example": { - "resolved": "packages/import-example", - "link": true - }, - "node_modules/undici": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", - "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "node_modules/wrangler": { - "resolved": "../../packages/wrangler", - "link": true - }, - "packages/import-example": { - "dependencies": { - "@fixture/import-wasm-static": "../../../../fixtures/import-wasm-static" - }, - "devDependencies": { - "@cloudflare/workers-tsconfig": "../../../../packages/workers-tsconfig", - "undici": "^5.29.0", - "wrangler": "../../../../packages/wrangler" - } - } - } -} diff --git a/fixtures/interactive-dev-tests/package.json b/fixtures/interactive-dev-tests/package.json index d48fa99c9f10..0d825a0d88b8 100644 --- a/fixtures/interactive-dev-tests/package.json +++ b/fixtures/interactive-dev-tests/package.json @@ -7,7 +7,6 @@ }, "devDependencies": { "@fixture/shared": "workspace:*", - "strip-ansi": "^7.1.0", "undici": "catalog:default", "vitest": "catalog:default" }, diff --git a/fixtures/interactive-dev-tests/tests/index.test.ts b/fixtures/interactive-dev-tests/tests/index.test.ts index 145f27da9b95..8e4a3423aa79 100644 --- a/fixtures/interactive-dev-tests/tests/index.test.ts +++ b/fixtures/interactive-dev-tests/tests/index.test.ts @@ -6,7 +6,7 @@ import path from "node:path"; import rl from "node:readline"; import stream from "node:stream"; import { setTimeout } from "node:timers/promises"; -import stripAnsi from "strip-ansi"; +import { stripVTControlCharacters } from "node:util"; import { fetch } from "undici"; import { afterAll, @@ -151,7 +151,11 @@ if (process.platform === "win32") { if (!skipWaitingForReady) { let readyMatch: RegExpMatchArray | null = null; for await (const line of stdoutInterface) { - if ((readyMatch = readyRegexp.exec(stripAnsi(line))) !== null) break; + if ( + (readyMatch = readyRegexp.exec(stripVTControlCharacters(line))) !== + null + ) + break; } assert(readyMatch !== null, "Expected ready message"); result.url = readyMatch[1]; diff --git a/fixtures/worker-logs/package.json b/fixtures/worker-logs/package.json index b87bacee6f7c..9e5d46ce66fb 100644 --- a/fixtures/worker-logs/package.json +++ b/fixtures/worker-logs/package.json @@ -12,7 +12,6 @@ }, "devDependencies": { "@cloudflare/workers-tsconfig": "workspace:^", - "strip-ansi": "^7.1.0", "typescript": "catalog:default", "vitest": "catalog:default", "wrangler": "workspace:*" diff --git a/fixtures/worker-logs/tests/index.test.ts b/fixtures/worker-logs/tests/index.test.ts index defa312dbb9b..59f6fd20f47f 100644 --- a/fixtures/worker-logs/tests/index.test.ts +++ b/fixtures/worker-logs/tests/index.test.ts @@ -1,5 +1,5 @@ +import { stripVTControlCharacters } from "node:util"; import { resolve } from "path"; -import stripAnsi from "strip-ansi"; import { describe, expect, onTestFinished, test, vi } from "vitest"; import { runWranglerDev } from "../../shared/src/run-wrangler-long-lived"; @@ -43,7 +43,7 @@ async function getWranglerDevOutput( await response.text(); return () => { - const output = stripAnsi(getOutput()) + const output = stripVTControlCharacters(getOutput()) // Windows gets a different marker for ✘, so let's normalize it here // so that these tests can be platform independent .replaceAll("✘", "X") diff --git a/packages/miniflare/src/shared/log.ts b/packages/miniflare/src/shared/log.ts index 542c53eaf49d..77889a706015 100644 --- a/packages/miniflare/src/shared/log.ts +++ b/packages/miniflare/src/shared/log.ts @@ -1,4 +1,5 @@ import path from "node:path"; +import { stripVTControlCharacters } from "node:util"; import { Colorize, dim, green, grey, red, reset, yellow } from "kleur/colors"; import { LogLevel } from "../workers"; @@ -186,23 +187,6 @@ export class NoOpLog extends Log { error(_message: Error): void {} } -// Adapted from https://github.com/chalk/ansi-regex/blob/02fa893d619d3da85411acc8fd4e2eea0e95a9d9/index.js -/*! - * MIT License - * - * Copyright (c) Sindre Sorhus (https://sindresorhus.com) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -const ansiRegexpPattern = [ - "[\\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 ansiRegexp = new RegExp(ansiRegexpPattern, "g"); export function stripAnsi(value: string) { - return value.replace(ansiRegexp, ""); + return stripVTControlCharacters(value); } diff --git a/packages/vite-plugin-cloudflare/playground/bindings/__tests__/shortcuts.spec.ts b/packages/vite-plugin-cloudflare/playground/bindings/__tests__/shortcuts.spec.ts index e7961fbcf395..98905476a4bb 100644 --- a/packages/vite-plugin-cloudflare/playground/bindings/__tests__/shortcuts.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/bindings/__tests__/shortcuts.spec.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import stripAnsi from "strip-ansi"; +import { stripVTControlCharacters } from "node:util"; import { afterAll, beforeAll, describe, expect, test, vi } from "vitest"; import { resetServerLogs, @@ -12,7 +12,7 @@ import { resolvePluginConfig } from "../../../src/plugin-config"; import { addBindingsShortcut } from "../../../src/plugins/shortcuts"; const normalize = (logs: string[]) => - stripAnsi(logs.join("\n")) + stripVTControlCharacters(logs.join("\n")) .split("\n") .map((line: string) => line.trim()) .join("\n"); diff --git a/packages/vite-plugin-cloudflare/playground/package.json b/packages/vite-plugin-cloudflare/playground/package.json index 028bf6d1af56..3c2304932094 100644 --- a/packages/vite-plugin-cloudflare/playground/package.json +++ b/packages/vite-plugin-cloudflare/playground/package.json @@ -18,7 +18,6 @@ "@cloudflare/workers-tsconfig": "workspace:*", "playwright-chromium": "catalog:default", "semver": "^7.7.1", - "strip-ansi": "^7.1.0", "ts-dedent": "^2.2.0", "typescript": "catalog:default" } diff --git a/packages/wrangler/e2e/helpers/normalize.ts b/packages/wrangler/e2e/helpers/normalize.ts index 25aea243310c..f4f106b86b7d 100644 --- a/packages/wrangler/e2e/helpers/normalize.ts +++ b/packages/wrangler/e2e/helpers/normalize.ts @@ -1,4 +1,4 @@ -import stripAnsi from "strip-ansi"; +import { stripVTControlCharacters } from "node:util"; import { expect } from "vitest"; import { CLOUDFLARE_ACCOUNT_ID } from "./account-id"; @@ -22,7 +22,7 @@ export function normalizeOutput( normalizeSlashes, normalizeTempDirs, stripTimings, - stripAnsi, + stripVTControlCharacters, removeTimestamp, stripDevTimings, stripEmptyNewlines, diff --git a/packages/wrangler/e2e/helpers/read-until.ts b/packages/wrangler/e2e/helpers/read-until.ts index 5f2323665b73..e3386005fb46 100644 --- a/packages/wrangler/e2e/helpers/read-until.ts +++ b/packages/wrangler/e2e/helpers/read-until.ts @@ -1,5 +1,5 @@ import { setTimeout } from "node:timers/promises"; -import stripAnsi from "strip-ansi"; +import { stripVTControlCharacters } from "node:util"; import type { ReadableStream } from "node:stream/web"; const TIMEOUT = Symbol.for("TIMEOUT"); @@ -12,7 +12,7 @@ export async function readUntil( const timeoutPromise = setTimeout(timeout, TIMEOUT); const reader = lines.getReader(); const readArray: string[] = []; - const read = () => stripAnsi(readArray.join("\n")); + const read = () => stripVTControlCharacters(readArray.join("\n")); try { while (true) { const result = await Promise.race([reader.read(), timeoutPromise]); diff --git a/packages/wrangler/package.json b/packages/wrangler/package.json index dd28202754a0..e5f057516818 100644 --- a/packages/wrangler/package.json +++ b/packages/wrangler/package.json @@ -158,7 +158,6 @@ "signal-exit": "^3.0.7", "smol-toml": "catalog:default", "source-map": "^0.6.1", - "strip-ansi": "^7.1.0", "supports-color": "^9.2.2", "timeago.js": "^4.0.2", "ts-dedent": "^2.2.0", diff --git a/packages/wrangler/src/cli-hotkeys.ts b/packages/wrangler/src/cli-hotkeys.ts index a18a424bcb82..43baeca5b1b2 100644 --- a/packages/wrangler/src/cli-hotkeys.ts +++ b/packages/wrangler/src/cli-hotkeys.ts @@ -1,5 +1,5 @@ +import { stripVTControlCharacters } from "node:util"; import { dim } from "@cloudflare/cli/colors"; -import stripAnsi from "strip-ansi"; import { unwrapHook } from "./api/startDevWorker/utils"; import { logger } from "./logger"; import { onKeyPress } from "./utils/onKeyPress"; @@ -39,7 +39,7 @@ export default function ( .map(({ keys, label }) => `[${keys[0]}] ${dim(unwrapHook(label))}`); let stringifiedInstructions = instructions.join(" "); - const length = stripAnsi(stringifiedInstructions).length; + const length = stripVTControlCharacters(stringifiedInstructions).length; const ADDITIONAL_CHARS = 6; // 3 chars on each side of the instructions for the box and spacing ("│ " and " │") const willWrap = length + ADDITIONAL_CHARS > process.stdout.columns; @@ -50,14 +50,14 @@ export default function ( const maxLineLength = Math.max( ...stringifiedInstructions .split("\n") - .map((line) => stripAnsi(line).length) + .map((line) => stripVTControlCharacters(line).length) ); stringifiedInstructions = stringifiedInstructions .split("\n") .map( (line) => - `│ ${line + " ".repeat(Math.max(0, maxLineLength - stripAnsi(line).length))} │` + `│ ${line + " ".repeat(Math.max(0, maxLineLength - stripVTControlCharacters(line).length))} │` ) .join("\n"); diff --git a/packages/wrangler/src/utils/log-file.ts b/packages/wrangler/src/utils/log-file.ts index 08e4106ee983..543699e02668 100644 --- a/packages/wrangler/src/utils/log-file.ts +++ b/packages/wrangler/src/utils/log-file.ts @@ -1,12 +1,12 @@ import { appendFile } from "node:fs/promises"; import path from "node:path"; +import { stripVTControlCharacters } from "node:util"; import { getEnvironmentVariableFactory, getGlobalWranglerConfigPath, } from "@cloudflare/workers-utils"; import { Mutex } from "miniflare"; import onExit from "signal-exit"; -import stripAnsi from "strip-ansi"; import { logger } from "../logger"; import { ensureDirectoryExists } from "./filesystem"; import type { LoggerLevel } from "../logger"; @@ -54,7 +54,7 @@ export async function appendToDebugLogFile( ) { const entry = ` --- ${new Date().toISOString()} ${messageLevel} -${stripAnsi(message)} +${stripVTControlCharacters(message)} --- `; diff --git a/packages/wrangler/src/utils/print-bindings.ts b/packages/wrangler/src/utils/print-bindings.ts index d020e61eea66..c1eb7455d20b 100644 --- a/packages/wrangler/src/utils/print-bindings.ts +++ b/packages/wrangler/src/utils/print-bindings.ts @@ -1,7 +1,7 @@ +import { stripVTControlCharacters } from "node:util"; import { brandColor, dim, white } from "@cloudflare/cli/colors"; import { friendlyBindingNames, UserError } from "@cloudflare/workers-utils"; import chalk from "chalk"; -import stripAnsi from "strip-ansi"; import { getFlag } from "../experimental-flags"; import { logger } from "../logger"; import type { @@ -659,7 +659,7 @@ export function printBindings( ); const maxModeLength = Math.max( ...output.map((b) => - b.mode ? stripAnsi(b.mode).length : headings.mode.length + b.mode ? stripVTControlCharacters(b.mode).length : headings.mode.length ) ); @@ -782,7 +782,9 @@ export function printBindings( // Exactly the same as String.padEnd, but doesn't miscount ANSI control characters function padEndAnsi(str: string, length: number) { - return str + " ".repeat(Math.max(0, length - stripAnsi(str).length)); + return ( + str + " ".repeat(Math.max(0, length - stripVTControlCharacters(str).length)) + ); } /** diff --git a/packages/wrangler/src/utils/render-labelled-values.ts b/packages/wrangler/src/utils/render-labelled-values.ts index 7658c6b89aa5..0f9eb04857b1 100644 --- a/packages/wrangler/src/utils/render-labelled-values.ts +++ b/packages/wrangler/src/utils/render-labelled-values.ts @@ -1,5 +1,5 @@ +import { stripVTControlCharacters } from "node:util"; import { gray, white } from "@cloudflare/cli/colors"; -import stripAnsi from "strip-ansi"; type Options = { /** Hook to format each label. This is a convenience option to avoid manually formatting each label. */ @@ -29,14 +29,16 @@ export default function formatLabelledValues( spacerCount = 2, indentationCount = 0, valuesAlignmentColumn: valuesAlignment = Math.max( - ...Object.keys(view).map((label) => stripAnsi(formatLabel(label)).length) + ...Object.keys(view).map( + (label) => stripVTControlCharacters(formatLabel(label)).length + ) ), lineSeparator = "\n", labelJustification = "left", }: Options = {} ): string { const labelLengthsWithoutANSI = Object.keys(view).map( - (label) => stripAnsi(formatLabel(label)).length + (label) => stripVTControlCharacters(formatLabel(label)).length ); const formattedLines = Object.entries(view).map(([label, value], i) => { diff --git a/packages/wrangler/src/wrangler-banner.ts b/packages/wrangler/src/wrangler-banner.ts index a25b5b2215ac..4edda8d2a212 100644 --- a/packages/wrangler/src/wrangler-banner.ts +++ b/packages/wrangler/src/wrangler-banner.ts @@ -1,7 +1,7 @@ +import { stripVTControlCharacters } from "node:util"; import { getWranglerHideBanner } from "@cloudflare/workers-utils"; import chalk from "chalk"; import semiver from "semiver"; -import stripAnsi from "strip-ansi"; import supportsColor from "supports-color"; import { version as wranglerVersion } from "../package.json"; import { logger } from "./logger"; @@ -35,7 +35,9 @@ export async function printWranglerBanner(performUpdateCheck = true) { text + "\n" + (supportsColor.stdout - ? chalk.hex("#FF8800")("─".repeat(stripAnsi(text).length)) + ? chalk.hex("#FF8800")( + "─".repeat(stripVTControlCharacters(text).length) + ) : "─".repeat(text.length)) ); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5e72f2a93216..380427116599 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -434,9 +434,6 @@ importers: '@fixture/shared': specifier: workspace:* version: link:../shared - strip-ansi: - specifier: ^7.1.0 - version: 7.1.0 undici: specifier: catalog:default version: 7.18.2 @@ -1276,9 +1273,6 @@ importers: '@cloudflare/workers-tsconfig': specifier: workspace:^ version: link:../../packages/workers-tsconfig - strip-ansi: - specifier: ^7.1.0 - version: 7.1.0 typescript: specifier: catalog:default version: 5.8.3 @@ -2401,9 +2395,6 @@ importers: semver: specifier: ^7.7.1 version: 7.7.3 - strip-ansi: - specifier: ^7.1.0 - version: 7.1.0 ts-dedent: specifier: ^2.2.0 version: 2.2.0 @@ -4120,9 +4111,6 @@ importers: source-map: specifier: ^0.6.1 version: 0.6.1 - strip-ansi: - specifier: ^7.1.0 - version: 7.1.0 supports-color: specifier: ^9.2.2 version: 9.2.2