diff --git a/test/programs/string-template-literal/main.ts b/test/programs/string-template-literal/main.ts index 4b0745b0..adfb457b 100644 --- a/test/programs/string-template-literal/main.ts +++ b/test/programs/string-template-literal/main.ts @@ -8,4 +8,7 @@ interface MyObject { g: `${string}@`, h: `${number}@`, i: `${string}@${number}`, + j: `{{${string}}}` + k: `${string}\n` + l: `${string}-${string}` } \ No newline at end of file diff --git a/test/programs/string-template-literal/schema.json b/test/programs/string-template-literal/schema.json index cc39dd2c..bb0149f8 100644 --- a/test/programs/string-template-literal/schema.json +++ b/test/programs/string-template-literal/schema.json @@ -39,6 +39,18 @@ "i": { "type": "string", "pattern": "^.*@[0-9]*$" + }, + "j": { + "pattern": "^\\{\\{.*\\}\\}$", + "type": "string" + }, + "k": { + "pattern": "^.*\\n$", + "type": "string" + }, + "l": { + "pattern": "^.*-.*$", + "type": "string" } }, "additionalProperties": false, @@ -51,7 +63,10 @@ "f", "g", "h", - "i" + "i", + "j", + "k", + "l" ], "$schema": "http://json-schema.org/draft-07/schema#" } \ No newline at end of file diff --git a/typescript-json-schema.ts b/typescript-json-schema.ts index 68c34bf2..5e54fe08 100644 --- a/typescript-json-schema.ts +++ b/typescript-json-schema.ts @@ -751,40 +751,48 @@ export class JsonSchemaGenerator { definition.type = "string"; // @ts-ignore const {texts, types} = propertyType; - const pattern = []; + let pattern = "^"; for (let i = 0; i < texts.length; i++) { - const text = texts[i]; - const type = types[i]; - - if (i === 0) { - pattern.push(`^`); + const text: string = texts[i]; + const type: ts.Type = types[i]; + + // https://json-schema.org/understanding-json-schema/reference/regular_expressions + // `-` should not be escaped; + // it is escaped only if it is used like `[a-z]`, which never happens here. + const control = ["[", "]", "(", ")", "{", "}", "^", "$", ".", "|", "?", "*", "+", "!"]; + const escaped: { [char: string]: string } = { "\n": "\\n", "\r": "\\r", "\t": "\\t" }; + for (const char of text) { + if (control.includes(char)) { + pattern += `\\${char}`; + } else if (escaped[char]) { + pattern += escaped[char]; + } else { + pattern += char; + } } if (type) { if (type.flags & ts.TypeFlags.String) { - pattern.push(`${text}.*`); + pattern += ".*"; } if (type.flags & ts.TypeFlags.Number || type.flags & ts.TypeFlags.BigInt) { - pattern.push(`${text}[0-9]*`); + pattern += "[0-9]*"; } if (type.flags & ts.TypeFlags.Undefined) { - pattern.push(`${text}undefined`); + pattern += "undefined"; } if (type.flags & ts.TypeFlags.Null) { - pattern.push(`${text}null`); + pattern += "null"; } } - - - if (i === texts.length - 1) { - pattern.push(`${text}$`); - } } - definition.pattern = pattern.join(""); + + pattern += "$"; + definition.pattern = pattern; } else { definition.type = "array"; if (!definition.items) {