diff --git a/.changeset/smol-toml-1-9.md b/.changeset/smol-toml-1-9.md new file mode 100644 index 00000000000..d59737a3b1d --- /dev/null +++ b/.changeset/smol-toml-1-9.md @@ -0,0 +1,12 @@ +--- +"wrangler": patch +"create-cloudflare": patch +"@cloudflare/workers-utils": patch +"@cloudflare/workers-auth": patch +--- + +Update `smol-toml` to 1.9.0 to fix slow parsing of very large TOML files + +Parse time for TOML config files now grows linearly with their size, instead of with its square: a 40,000-line file that took 259 ms to parse now takes 17 ms, while typical `wrangler.toml` files parse in the same time as before. This addresses the `GHSA-r4xh-jqrq-34v2` advisory against earlier versions of the parser. + +Some TOML syntax errors now point at the character that caused them. For example, a `wrangler.toml` containing `INVALID "FILE` is now reported as `illegal character in key` at the `"`, rather than `incomplete key-value` at the start of the line. diff --git a/packages/create-cloudflare/src/deploy.ts b/packages/create-cloudflare/src/deploy.ts index b69cc3e9951..ce2327e03ed 100644 --- a/packages/create-cloudflare/src/deploy.ts +++ b/packages/create-cloudflare/src/deploy.ts @@ -12,7 +12,7 @@ import { C3_DEFAULTS, openInBrowser } from "helpers/cli"; import { readFile } from "helpers/files"; import { detectPackageManager } from "helpers/packageManagers"; import { poll } from "helpers/poll"; -import TOML from "smol-toml"; +import * as TOML from "smol-toml"; import { isInsideGitRepo } from "./git"; import { chooseAccount, wranglerLogin } from "./wrangler/accounts"; import { diff --git a/packages/create-cloudflare/src/helpers/files.ts b/packages/create-cloudflare/src/helpers/files.ts index 3a3c34d02c5..b7bc75f072e 100644 --- a/packages/create-cloudflare/src/helpers/files.ts +++ b/packages/create-cloudflare/src/helpers/files.ts @@ -1,7 +1,7 @@ import fs, { existsSync, statSync } from "node:fs"; import { join } from "node:path"; import { parse, stringify } from "comment-json"; -import TOML from "smol-toml"; +import * as TOML from "smol-toml"; import type { C3Context, PackageJson } from "types"; export const copyFile = (path: string, dest: string) => { diff --git a/packages/create-cloudflare/src/workers.ts b/packages/create-cloudflare/src/workers.ts index 26f04a482c2..a4006419ff0 100644 --- a/packages/create-cloudflare/src/workers.ts +++ b/packages/create-cloudflare/src/workers.ts @@ -9,7 +9,7 @@ import { readFile, readJSON, usesTypescript, writeFile } from "helpers/files"; import { detectPackageManager } from "helpers/packageManagers"; import { installPackages } from "helpers/packages"; import * as jsonc from "jsonc-parser"; -import TOML from "smol-toml"; +import * as TOML from "smol-toml"; import { readWranglerJsonOrJsonc, readWranglerToml, diff --git a/packages/create-cloudflare/src/wrangler/config.ts b/packages/create-cloudflare/src/wrangler/config.ts index 3c62e8a1d83..01dda8e8044 100644 --- a/packages/create-cloudflare/src/wrangler/config.ts +++ b/packages/create-cloudflare/src/wrangler/config.ts @@ -13,7 +13,7 @@ import { readJSONWithComments, writeJSONWithComments, } from "helpers/json"; -import TOML from "smol-toml"; +import * as TOML from "smol-toml"; import type { CommentObject, Reviver } from "comment-json"; import type { TomlTable } from "smol-toml"; import type { C3Context } from "types"; diff --git a/packages/workers-auth/src/core/file-format.ts b/packages/workers-auth/src/core/file-format.ts index 21faebcf9f5..4af453e2c47 100644 --- a/packages/workers-auth/src/core/file-format.ts +++ b/packages/workers-auth/src/core/file-format.ts @@ -1,5 +1,5 @@ import { parseTOML } from "@cloudflare/workers-utils"; -import TOML from "smol-toml"; +import * as TOML from "smol-toml"; /** * On-disk serialization format for a CLI's config/credential files. diff --git a/packages/workers-utils/src/config/index.ts b/packages/workers-utils/src/config/index.ts index f5dfcbab8b0..d664cd72818 100644 --- a/packages/workers-utils/src/config/index.ts +++ b/packages/workers-utils/src/config/index.ts @@ -1,4 +1,4 @@ -import TOML from "smol-toml"; +import * as TOML from "smol-toml"; import { parseJSONC, parseTOML, readFileSync } from "../parse"; import { resolveWranglerConfigPath } from "./config-helpers"; import type { Config, RawConfig } from "./config"; diff --git a/packages/workers-utils/src/config/patch-config.ts b/packages/workers-utils/src/config/patch-config.ts index 6c4ae76f87f..0cb5da8ee62 100644 --- a/packages/workers-utils/src/config/patch-config.ts +++ b/packages/workers-utils/src/config/patch-config.ts @@ -1,6 +1,6 @@ import { writeFileSync } from "node:fs"; import { applyEdits, format, modify } from "jsonc-parser"; -import TOML from "smol-toml"; +import * as TOML from "smol-toml"; import { parseJSONC, parseTOML, readFileSync } from "../parse"; import type { RawConfig } from "./config"; import type { JSONPath } from "jsonc-parser"; diff --git a/packages/workers-utils/src/parse.ts b/packages/workers-utils/src/parse.ts index d50c7b48a27..4ba8b276f88 100644 --- a/packages/workers-utils/src/parse.ts +++ b/packages/workers-utils/src/parse.ts @@ -1,7 +1,7 @@ import { readFileSync as fsReadFileSync } from "node:fs"; import { resolve } from "node:path"; import * as jsoncParser from "jsonc-parser"; -import TOML, { TomlError } from "smol-toml"; +import * as TOML from "smol-toml"; import { UserError } from "./errors"; import type { TelemetryMessage } from "./errors"; import type { ParseError as JsoncParseError } from "jsonc-parser"; @@ -117,7 +117,7 @@ export function parseTOML(tomlContent: string, filePath?: string): unknown { try { return TOML.parse(tomlContent); } catch (err) { - if (!(err instanceof TomlError)) { + if (!(err instanceof TOML.TomlError)) { throw err; } diff --git a/packages/workers-utils/tests/config/validation/normalize-and-validate-config.test.ts b/packages/workers-utils/tests/config/validation/normalize-and-validate-config.test.ts index 432fb7ee233..daae75b6127 100644 --- a/packages/workers-utils/tests/config/validation/normalize-and-validate-config.test.ts +++ b/packages/workers-utils/tests/config/validation/normalize-and-validate-config.test.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import TOML from "smol-toml"; +import * as TOML from "smol-toml"; import { assert, describe, it, test, vi } from "vitest"; import { normalizeAndValidateConfig } from "../../../src/config/validation"; import { normalizeString } from "../../../src/test-helpers"; diff --git a/packages/workers-utils/tests/parse.test.ts b/packages/workers-utils/tests/parse.test.ts index a8e57202c6b..928467b3de1 100644 --- a/packages/workers-utils/tests/parse.test.ts +++ b/packages/workers-utils/tests/parse.test.ts @@ -11,7 +11,7 @@ import { describe("parseTOML", () => { it("should parse toml that is empty", ({ expect }) => { - expect(parseTOML("")).toStrictEqual({}); + expect(parseTOML("")).toEqual({}); }); it("should parse toml with basic values", ({ expect }) => { @@ -20,7 +20,7 @@ describe("parseTOML", () => { name = "basic" version = 1 `) - ).toStrictEqual({ + ).toEqual({ name: "basic", version: 1, }); @@ -37,7 +37,7 @@ describe("parseTOML", () => { [owner.dog] exists = true `) - ).toStrictEqual({ + ).toEqual({ name: "complex", owner: { alive: true, diff --git a/packages/wrangler/src/__tests__/pages/deploy.test.ts b/packages/wrangler/src/__tests__/pages/deploy.test.ts index d330b0376c5..3bc293b20af 100644 --- a/packages/wrangler/src/__tests__/pages/deploy.test.ts +++ b/packages/wrangler/src/__tests__/pages/deploy.test.ts @@ -7,7 +7,7 @@ import { } from "@cloudflare/workers-utils/test-helpers"; import ci from "ci-info"; import { http, HttpResponse } from "msw"; -import TOML from "smol-toml"; +import * as TOML from "smol-toml"; import { x } from "tinyexec"; import dedent from "ts-dedent"; /* eslint-disable-next-line no-restricted-imports -- diff --git a/packages/wrangler/src/__tests__/pages/pages-build-env.test.ts b/packages/wrangler/src/__tests__/pages/pages-build-env.test.ts index 1be3dd069df..20175adb9c7 100644 --- a/packages/wrangler/src/__tests__/pages/pages-build-env.test.ts +++ b/packages/wrangler/src/__tests__/pages/pages-build-env.test.ts @@ -138,11 +138,11 @@ describe("pages build env", () => { expect(process.exitCode).toEqual(EXIT_CODE_INVALID_PAGES_CONFIG); expect(std.err).toMatchInlineSnapshot(` - "X [ERROR] Invalid TOML document: incomplete key-value: cannot find end of key + "X [ERROR] Invalid TOML document: illegal character in key - /wrangler.toml:1:0: -  1 │ INVALID "FILE - ╵ ^ + /wrangler.toml:1:8: +  1 │ INVALID "FILE + ╵ ^ " `); diff --git a/packages/wrangler/src/deployments.ts b/packages/wrangler/src/deployments.ts index 47ff9d52d6c..9a84b1bdd9a 100644 --- a/packages/wrangler/src/deployments.ts +++ b/packages/wrangler/src/deployments.ts @@ -5,7 +5,7 @@ import { UserError, } from "@cloudflare/workers-utils"; import chalk from "chalk"; -import TOML from "smol-toml"; +import * as TOML from "smol-toml"; import { FormData } from "undici"; import { fetchResult } from "./cfetch"; import { readConfig } from "./config"; diff --git a/packages/wrangler/src/pages/download-config.ts b/packages/wrangler/src/pages/download-config.ts index 171f9d2c06d..5863358adfc 100644 --- a/packages/wrangler/src/pages/download-config.ts +++ b/packages/wrangler/src/pages/download-config.ts @@ -8,7 +8,7 @@ import { UserError, } from "@cloudflare/workers-utils"; import chalk from "chalk"; -import TOML from "smol-toml"; +import * as TOML from "smol-toml"; import { fetchResult } from "../cfetch"; import { getConfigCache } from "../config-cache"; import { createCommand } from "../core/create-command"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f02c9565ab6..157c87df978 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -64,8 +64,8 @@ catalogs: specifier: 4.1.0 version: 4.1.0 smol-toml: - specifier: 1.8.0 - version: 1.8.0 + specifier: 1.9.0 + version: 1.9.0 tinyglobby: specifier: 0.2.16 version: 0.2.16 @@ -2011,7 +2011,7 @@ importers: version: 7.7.1 smol-toml: specifier: catalog:default - version: 1.8.0 + version: 1.9.0 tinyglobby: specifier: catalog:default version: 0.2.16 @@ -4251,7 +4251,7 @@ importers: version: 2.14.6(@types/node@22.15.17)(typescript@5.8.3) smol-toml: specifier: catalog:default - version: 1.8.0 + version: 1.9.0 ts-dedent: specifier: ^2.2.0 version: 2.2.0 @@ -4523,7 +4523,7 @@ importers: version: 4.1.0 smol-toml: specifier: catalog:default - version: 1.8.0 + version: 1.9.0 ts-dedent: specifier: ^2.2.0 version: 2.2.0 @@ -4861,7 +4861,7 @@ importers: version: 4.1.0 smol-toml: specifier: catalog:default - version: 1.8.0 + version: 1.9.0 supports-color: specifier: ^9.2.2 version: 9.2.2 @@ -15534,8 +15534,8 @@ packages: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - smol-toml@1.8.0: - resolution: {integrity: sha512-kCZr2V3ch9i00x8zXRhjUNVcjG9ijES5dDudkXvUVCT5QlJNQWElSJdZqyPemffHoLNUYwOcou0Fy+ojN0uHSQ==} + smol-toml@1.9.0: + resolution: {integrity: sha512-hpd+HLON7HdZXqYchMM/+LaTTbdK0AU3NngIJ4KVyWbY9bfQqdL9cD+4yf6dUoU2Ap4VsU0JkQi6FxAI1B2mXQ==} engines: {node: '>= 18'} snake-case@3.0.4: @@ -28308,7 +28308,7 @@ snapshots: smart-buffer@4.2.0: {} - smol-toml@1.8.0: {} + smol-toml@1.9.0: {} snake-case@3.0.4: dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4ac4994f78e..cfe12e54b79 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -132,7 +132,7 @@ catalog: "@cloudflare/workers-types": "^5.20260923.1" workerd: "1.20260923.1" jsonc-parser: "3.2.0" - smol-toml: "1.8.0" + smol-toml: "1.9.0" msw: "2.14.6" tinyglobby: "0.2.16" "tree-kill": "1.2.2"