{"record":{"id":"3ee8dc850b40b871","repo":"can1357/oh-my-pi","slug":"unexpected-end-of-definition-this-src","errorCode":null,"errorMessage":"unexpected end of definition \"${this.#src}\"","messagePattern":"unexpected end of definition \"(.+?)\"","errorType":"exception","errorClass":"OmpTypeError","httpStatus":null,"severity":"error","filePath":"packages/omptype/src/ir.ts","lineNumber":352,"sourceCode":"class StrParser {\n\t#toks: Tok[];\n\t#pos = 0;\n\t#src: string;\n\t#resolve: AliasResolver | undefined;\n\n\tconstructor(src: string, resolve?: AliasResolver) {\n\t\tthis.#src = src;\n\t\tthis.#resolve = resolve;\n\t\tthis.#toks = tokenize(src);\n\t}\n\n\t#peek(offset = 0): Tok | undefined {\n\t\treturn this.#toks[this.#pos + offset];\n\t}\n\n\t#next(): Tok {\n\t\tconst t = this.#toks[this.#pos++];\n\t\tif (!t) throw new OmpTypeError(`unexpected end of definition \"${this.#src}\"`);\n\t\treturn t;\n\t}\n\n\t#eatOp(v: string): boolean {\n\t\tconst t = this.#peek();\n\t\tif (t?.t === \"op\" && t.v === v) {\n\t\t\tthis.#pos++;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/** Full definition with optional trailing `= literal` default and/or `?` optional marker. */\n\tparseTop(): ParsedTop {\n\t\tconst ir = this.parseUnion();\n\t\tlet def: unknown;\n\t\tlet hasDefault = false;\n\t\tif (this.#eatOp(\"=\")) {","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/omptype/src/ir.ts#L334-L370","documentation":"The parser called #next() when the token stream was exhausted — the definition string ended where another token was required. Callers include t() (primary parsing), hi (right bound), limit (after == or %), and name (after #). This is the 'premature end of input' error for the string-definition mini-grammar.","triggerScenarios":"Definitions that stop mid-construct: 'string<' (generic without args), 'number>=' (bound without a limit), '5 %' (divisor missing), 'array#' (brand name missing), '(' (unclosed group reaching EOF), 'string|' (dangling union bar).","commonSituations":"Truncated strings from template concatenation (`number >= ${}` with undefined min printing as nothing is caught earlier, but a trailing operator is common); hand-edited schemas where a value was deleted; string slicing that chopped the tail off a definition.","solutions":["Append the missing token: a limit after a comparator ('number>=1'), an operand after '|' or '&', a ')' for '(', or an identifier after '#'.","If the definition is interpolated, verify every interpolated value is defined and non-empty before building the string.","Log/echo the full definition string (included in the message) and compare against expected syntax to spot truncation.","Prefer composing from validated parts or use the object/IR form of the schema instead of string concatenation."],"exampleFix":"// before\nschema.parse(\"number>=\");\n// after\nschema.parse(\"number>=1\");","handlingStrategy":"validation","validationCode":"function assertComplete(def) {\n  if (/[<>=|&%(#%]$/.test(def.trim())) throw new Error(`definition ends mid-construct: ${def}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const schema = parse(def);\n} catch (e) {\n  if (String(e.message).includes(\"unexpected end of definition\")) {\n    // log def and its length; check the interpolation that built it\n  }\n  throw e;\n}","preventionTips":["Never end a definition with a dangling operator; always pair comparators with limits and brackets with closers.","Assert every interpolated variable is defined and non-empty before composing the string.","Build complex definitions from small, individually-parsed fragments instead of one long concatenation."],"tags":["parser","unexpected-end","schema-definition"],"backgroundTag":"incomplete-type-definition","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}