{"record":{"id":"ad1fc6fa8c0de323","repo":"can1357/oh-my-pi","slug":"unterminated-date-literal-in-src","errorCode":null,"errorMessage":"unterminated date literal in \"${src}\"","messagePattern":"unterminated date literal in \"(.+?)\"","errorType":"exception","errorClass":"OmpTypeError","httpStatus":null,"severity":"error","filePath":"packages/omptype/src/ir.ts","lineNumber":197,"sourceCode":"\t| { t: \"str\"; v: string }\n\t| { t: \"op\"; v: string };\n\nconst SIMPLE_OPS = \"|&()[]=?%,#\";\n\nfunction tokenize(src: string): Tok[] {\n\tconst toks: Tok[] = [];\n\tlet i = 0;\n\tconst n = src.length;\n\twhile (i < n) {\n\t\tconst c = src[i];\n\t\tif (c === \" \" || c === \"\\t\" || c === \"\\n\" || c === \"\\r\") {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (c === \"d\" && (src[i + 1] === \"'\" || src[i + 1] === '\"')) {\n\t\t\tconst quote = src[i + 1];\n\t\t\tconst end = src.indexOf(quote, i + 2);\n\t\t\tif (end < 0) throw new OmpTypeError(`unterminated date literal in \"${src}\"`);\n\t\t\tconst source = src.slice(i + 2, end).trim();\n\t\t\tconst value = /^\\d+$/.test(source) ? new Date(Number(source)) : new Date(source);\n\t\t\tif (Number.isNaN(value.valueOf())) throw new OmpTypeError(`invalid date literal in \"${src}\"`);\n\t\t\ttoks.push({ t: \"date\", v: value });\n\t\t\ti = end + 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (c === \"'\" || c === '\"') {\n\t\t\tlet j = i + 1;\n\t\t\tlet value = \"\";\n\t\t\tfor (; j < n && src[j] !== c; j++) {\n\t\t\t\tif (src[j] === \"\\\\\") {\n\t\t\t\t\tj++;\n\t\t\t\t\tif (j >= n) break;\n\t\t\t\t}\n\t\t\t\tvalue += src[j];\n\t\t\t}\n\t\t\tif (j >= n) throw new OmpTypeError(`unterminated string literal in \"${src}\"`);","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/omptype/src/ir.ts#L179-L215","documentation":"When tokenizing a type expression (e.g. for date-literal comparisons), a date literal opened with `d'` or `d\"` was never closed by a matching quote before the end of the expression. The tokenizer throws instead of silently truncating.","triggerScenarios":"Type expressions like `d'2024-01-01` (missing closing quote) or `d\"2024 > ` passed to a type parser constructed from `ir.ts` tokenization.","commonSituations":"Hand-written constraint strings with a dropped quote; string interpolation accidentally consuming the closing quote; copy-paste truncation.","solutions":["Close the date literal with the same quote character used to open it: `d'2024-01-01'`.","Check for quotes consumed by template-literal interpolation in generated expressions.","Validate the expression string before passing it to the parser."],"exampleFix":"// before\nconst t = type(`date > d'2024-01-01`);\n// after\nconst t = type(`date > d'2024-01-01'`);","handlingStrategy":"validation","validationCode":"if (!/^d['\"][^'\"]*['\"]/.test(exprPart)) throw new Error(\"date literal must be d'...' or d\\\"...\\\"\");","typeGuard":null,"tryCatchPattern":"try {\n  const t = new TypeExpression(src);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"unterminated date literal\")) {\n    throw new Error(`Check quoting: ${err.message}`);\n  }\n  throw err;\n}","preventionTips":["Always close date literals with the same quote that opened them.","Beware template-literal interpolation eating quotes; escape `\\${` where needed.","Unit-test constraint strings as fixtures."],"tags":["parser","date-literal","syntax-error"],"backgroundTag":"unterminated-literal","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}