Skip to content

Commit

Permalink
fix(#49): escape control characters
Browse files Browse the repository at this point in the history
  • Loading branch information
macropygia authored and astahmer committed Dec 12, 2022
1 parent c49b335 commit 5b061cf
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 3 deletions.
8 changes: 5 additions & 3 deletions lib/src/openApiToZod.ts
Expand Up @@ -5,7 +5,7 @@ import type { CodeMetaData, ConversionTypeContext } from "./CodeMeta";
import { CodeMeta } from "./CodeMeta";
import { isReferenceObject } from "./isReferenceObject";
import type { TemplateContext } from "./template-context";
import { isPrimitiveType, wrapWithQuotesIfNeeded } from "./utils";
import { escapeControlCharacters, isPrimitiveType, wrapWithQuotesIfNeeded } from "./utils";

type ConversionArgs = {
schema: SchemaObject | ReferenceObject;
Expand Down Expand Up @@ -226,7 +226,9 @@ const getZodChainableDefault = (schema: SchemaObject) => {
return "";
};

const wrapPatternIfNeeded = (pattern: string) => {
const formatPatternIfNeeded = (pattern: string) => {
pattern = escapeControlCharacters(pattern);

if (pattern.startsWith("/") && pattern.endsWith("/")) {
return pattern;
}
Expand All @@ -246,7 +248,7 @@ const getZodChainableStringValidations = (schema: SchemaObject) => {
}

if (schema.pattern) {
validations.push(`regex(${wrapPatternIfNeeded(schema.pattern)})`);
validations.push(`regex(${formatPatternIfNeeded(schema.pattern)})`);
}

if (schema.format) {
Expand Down
18 changes: 18 additions & 0 deletions lib/src/utils.ts
Expand Up @@ -45,3 +45,21 @@ export const isPrimitiveType = (type: SingleType): type is PrimitiveType => prim

const primitiveTypeList = ["string", "number", "integer", "boolean", "null"] as const;
export type PrimitiveType = typeof primitiveTypeList[number];

export const escapeControlCharacters = (str: string): string => {
return str
.replace(/\t/g, "\\t") // U+0009
.replace(/\n/g, "\\n") // U+000A
.replace(/\r/g, "\\r") // U+000D
.replace(
/([\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F\uFFFE\uFFFF])/g,
(_m, p1) => {
const dec: number = p1.codePointAt();
const hex: string = dec.toString(16);
// eslint-disable-next-line sonarjs/no-nested-template-literals
if (dec <= 0xFF) return `\\x${`00${hex}`.slice(-2)}`;
// eslint-disable-next-line sonarjs/no-nested-template-literals
return `\\u${`0000${hex}`.slice(-4)}`;
}
);
};
5 changes: 5 additions & 0 deletions lib/tests/invalid-pattern-regex.test.ts
Expand Up @@ -12,10 +12,15 @@ test("invalid-pattern-regex", () => {
type: "string",
pattern: "/[0-9]+/",
};
const controlCharacters: SchemaObject = {
type: "string",
pattern: "/[\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\uFFFE\uFFFF]+/",
};
expect(getZodSchema({ schema: schema }) + getZodChain(schema)).toMatchInlineSnapshot(
'"z.string().regex(/[0-9]+/).optional()"'
);
expect(getZodSchema({ schema: invalidSchema }) + getZodChain(invalidSchema)).toMatchInlineSnapshot(
'"z.string().regex(/[0-9]+/).optional()"'
);
expect(getZodSchema({ schema: controlCharacters }) + getZodChain(controlCharacters)).toMatchInlineSnapshot('"z.string().regex(/[\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f\\x7f\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\\ufffe\\uffff]+/).optional()"');
});

1 comment on commit 5b061cf

@vercel
Copy link

@vercel vercel bot commented on 5b061cf Dec 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.