Skip to content

Commit

Permalink
fix(wrangler): Add more helpful error messages when validating compat…
Browse files Browse the repository at this point in the history
…ibility date (#7002)

* Add more helpful error messages when validating compatibility date

* PR feedback

---------

Co-authored-by: Carmen Popoviciu <cpopoviciu@cloudflare.com>
  • Loading branch information
GregBrimble and CarmenPopoviciu authored Dec 9, 2024
1 parent 0920d13 commit d2447c6
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/fifty-dots-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wrangler": patch
---

fix: More helpful error messages when validating compatibility date
100 changes: 100 additions & 0 deletions packages/wrangler/src/__tests__/configuration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,106 @@ describe("normalizeAndValidateConfig()", () => {
`);
});

describe("compatibility_date", () => {
it("should allow valid values", () => {
const expectedConfig: RawConfig = {
compatibility_date: "2024-10-01",
};

const { config, diagnostics } = normalizeAndValidateConfig(
expectedConfig,
undefined,
{ env: undefined }
);

expect(config).toEqual(expect.objectContaining(expectedConfig));
expect(diagnostics.hasWarnings()).toBe(false);
expect(diagnostics.hasErrors()).toBe(false);
});

it("should error for en-dashes", () => {
const expectedConfig: RawConfig = {
compatibility_date: "2024–10–01", // en-dash
};

const result = normalizeAndValidateConfig(expectedConfig, undefined, {
env: undefined,
});

expect(result.config).toEqual(expect.objectContaining(expectedConfig));
expect(result.diagnostics.hasWarnings()).toBe(false);
expect(result.diagnostics.hasErrors()).toBe(true);

expect(normalizeString(result.diagnostics.renderErrors()))
.toMatchInlineSnapshot(`
"Processing wrangler configuration:
- \\"compatibility_date\\" field should use ISO-8601 accepted hyphens (-) rather than en-dashes (–) or em-dashes (—)."
`);
});

it("should error for em-dashes", () => {
const expectedConfig = {
compatibility_date: "2024—10—01", // em-dash
};

const result = normalizeAndValidateConfig(expectedConfig, undefined, {
env: undefined,
});

expect(result.config).toEqual(expect.objectContaining(expectedConfig));
expect(result.diagnostics.hasWarnings()).toBe(false);
expect(result.diagnostics.hasErrors()).toBe(true);

expect(normalizeString(result.diagnostics.renderErrors()))
.toMatchInlineSnapshot(`
"Processing wrangler configuration:
- \\"compatibility_date\\" field should use ISO-8601 accepted hyphens (-) rather than en-dashes (–) or em-dashes (—)."
`);
});

it("should error for invalid date values", () => {
const expectedConfig: RawConfig = {
compatibility_date: "abc",
};

const { config, diagnostics } = normalizeAndValidateConfig(
expectedConfig,
undefined,
{ env: undefined }
);

expect(config).toEqual(expect.objectContaining(expectedConfig));
expect(diagnostics.hasErrors()).toBe(true);

expect(normalizeString(diagnostics.renderErrors()))
.toMatchInlineSnapshot(`
"Processing wrangler configuration:
- \\"compatibility_date\\" field should be a valid ISO-8601 date (YYYY-MM-DD), but got \\"abc\\"."
`);
});

it("should error for dates that are both invalid and include en/em dashes", () => {
const expectedConfig = {
compatibility_date: "2024—100—01", // invalid date + em-dash
};

const result = normalizeAndValidateConfig(expectedConfig, undefined, {
env: undefined,
});

expect(result.config).toEqual(expect.objectContaining(expectedConfig));
expect(result.diagnostics.hasWarnings()).toBe(false);
expect(result.diagnostics.hasErrors()).toBe(true);

expect(normalizeString(result.diagnostics.renderErrors()))
.toMatchInlineSnapshot(`
"Processing wrangler configuration:
- \\"compatibility_date\\" field should use ISO-8601 accepted hyphens (-) rather than en-dashes (–) or em-dashes (—).
- \\"compatibility_date\\" field should be a valid ISO-8601 date (YYYY-MM-DD), but got \\"2024—100—01\\"."
`);
});
});

describe("[site]", () => {
it("should override `site` config defaults with provided values", () => {
const expectedConfig: RawConfig = {
Expand Down
41 changes: 41 additions & 0 deletions packages/wrangler/src/config/validation-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,47 @@ export const isValidName: ValidatorFn = (diagnostics, field, value) => {
}
};

/**
* Validate that the field is a valid ISO-8601 date time string
* see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format
* or https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-date-time-string-format
*/
export const isValidDateTimeStringFormat = (
diagnostics: Diagnostics,
field: string,
value: string
): boolean => {
let isValid = true;

// en/em dashes are not valid characters in the JS date time string format.
// While they would be caught by the `isNaN(data.getTime())` check below,
// we want to single these use cases out, and throw a more specific error
if (
value.includes("–") || // en-dash
value.includes("—") // em-dash
) {
diagnostics.errors.push(
`"${field}" field should use ISO-8601 accepted hyphens (-) rather than en-dashes (–) or em-dashes (—).`
);
isValid = false;
}

// en/em dashes were already handled above. Let's replace them with hyphens,
// which is a valid date time string format character, and evaluate the
// resulting date time string further. This ensures we validate for hyphens
// only once!
const data = new Date(value.replaceAll(/|/g, "-"));

if (isNaN(data.getTime())) {
diagnostics.errors.push(
`"${field}" field should be a valid ISO-8601 date (YYYY-MM-DD), but got ${JSON.stringify(value)}.`
);
isValid = false;
}

return isValid;
};

/**
* Validate that the field is an array of strings.
*/
Expand Down
18 changes: 17 additions & 1 deletion packages/wrangler/src/config/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
isRequiredProperty,
isString,
isStringArray,
isValidDateTimeStringFormat,
isValidName,
notInheritable,
validateAdditionalProperties,
Expand Down Expand Up @@ -1173,7 +1174,7 @@ function normalizeAndValidateEnvironment(
topLevelEnv,
rawEnv,
"compatibility_date",
isString,
validateCompatibilityDate,
undefined
),
compatibility_flags: inheritable(
Expand Down Expand Up @@ -3216,6 +3217,21 @@ const validateConsumer: ValidatorFn = (diagnostics, field, value, _config) => {
return isValid;
};

const validateCompatibilityDate: ValidatorFn = (diagnostics, field, value) => {
if (value === undefined) {
return true;
}

if (typeof value !== "string") {
diagnostics.errors.push(
`Expected "${field}" to be of type string but got ${JSON.stringify(value)}.`
);
return false;
}

return isValidDateTimeStringFormat(diagnostics, field, value);
};

const validatePipelineBinding: ValidatorFn = (diagnostics, field, value) => {
if (typeof value !== "object" || value === null) {
diagnostics.errors.push(
Expand Down

0 comments on commit d2447c6

Please sign in to comment.