{"record":{"id":"913710d6a41896c2","repo":"chenglou/pretext","slug":"unsupported-bidi-class-raw","errorCode":null,"errorMessage":"Unsupported bidi class ${raw}","messagePattern":"Unsupported bidi class (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/generate-bidi-data.ts","lineNumber":85,"sourceCode":"\nfunction parseCodePointRange(raw: string): { start: number, end: number } {\n  const [startRaw, endRaw] = raw.split('..')\n  const start = Number.parseInt(startRaw!, 16)\n  const end = endRaw === undefined ? start : Number.parseInt(endRaw, 16)\n  if (!Number.isInteger(start) || !Number.isInteger(end) || start < 0 || end < start) {\n    throw new Error(`Invalid code point range: ${raw}`)\n  }\n  return { start, end }\n}\n\nfunction simplifyBidiType(raw: string): GeneratedBidiType {\n  if (generatedTypeToCode.has(raw as GeneratedBidiType)) return raw as GeneratedBidiType\n  if (bnProjectedTypes.has(raw)) return 'BN'\n\n  const longName = longBidiNames.get(raw)\n  if (longName !== undefined) return longName\n\n  throw new Error(`Unsupported bidi class ${raw}`)\n}\n\nfunction buildPayload(sourceText: string): GeneratedBidiPayload {\n  const sourceLines = sourceText.split(/\\r?\\n/)\n  const versionLine = sourceLines.find(line => line.startsWith('# DerivedBidiClass-'))\n  const versionMatch = versionLine?.match(/^# DerivedBidiClass-(.+)\\.txt$/)\n  if (versionMatch === null || versionMatch === undefined) {\n    throw new Error('Could not determine Unicode version from DerivedBidiClass header')\n  }\n  const unicodeVersion = versionMatch[1]!\n\n  const bidiCodes = new Uint8Array(0x110000)\n  bidiCodes.fill(generatedTypeToCode.get('L')!)\n\n  for (let i = 0; i < sourceLines.length; i++) {\n    const rawLine = sourceLines[i]!\n    let rangeText: string | null = null\n    let typeText: string | null = null","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/chenglou/pretext/blob/ac49b09b7d83ede19581fa94a8b892b07d309baf/scripts/generate-bidi-data.ts#L67-L103","documentation":"The derived file contains a bidi class abbreviation the generator does not model. Recognized inputs: the 14 short codes (L,R,AL,AN,EN,ES,ET,CS,ON,BN,B,S,WS,NSM), their long forms (e.g. `Arabic_Letter`), and the formatting/isolate controls (LRE,LRO,RLE,RLO,PDF,LRI,RLI,FSI,PDI) which project onto BN. Anything else throws.","triggerScenarios":"A newer Unicode version introduces or surfaces a bidi class not in the projection set, or the source file carries an unexpected long name.","commonSituations":"Upgrading the bundled DerivedBidiClass to a new Unicode version without updating the generator's class tables.","solutions":["If the class is a new formatting/isolate control, add it to `bnProjectedTypes` so it projects onto BN.","If it is a genuine new resolved class, extend `GENERATED_TYPES`, `longBidiNames`, and the generated type union — but first confirm the rich bidi helper actually needs it.","Otherwise re-download a clean DerivedBidiClass file; a stray token can masquerade as a class."],"exampleFix":"// before: a new isolate control (hypothetical 'RIN') is unsupported\nconst bnProjectedTypes = new Set(['LRE','LRO','RLE','RLO','PDF','LRI','RLI','FSI','PDI'])\n// after: project the new control onto BN\nconst bnProjectedTypes = new Set(['LRE','LRO','RLE','RLO','PDF','LRI','RLI','FSI','PDI','RIN'])","handlingStrategy":"validation","validationCode":"const KNOWN = new Set([...GENERATED_TYPES, ...longBidiNames.keys(), ...bnProjectedTypes])\nconst unknown = new Set<string>()\nfor (const line of sourceLines) {\n  const m = line.match(/;\\s*([A-Za-z_]+)/)\n  if (m && !KNOWN.has(m[1])) unknown.add(m[1])\n}\nif (unknown.size > 0) {\n  console.error(`Unmodeled bidi classes: ${[...unknown].join(', ')}`)\n  process.exit(1)\n}","typeGuard":"const isRecognizedBidiClass = (raw: string): boolean =>\n  generatedTypeToCode.has(raw as GeneratedBidiType) ||\n  bnProjectedTypes.has(raw) ||\n  longBidiNames.has(raw)","tryCatchPattern":null,"preventionTips":["After a Unicode upgrade, scan the derived file for classes outside the recognized set before generating.","Prefer projecting new formatting/isolate controls onto BN via bnProjectedTypes rather than expanding the resolved type union.","Only extend GENERATED_TYPES/longBidiNames if the rich bidi helper genuinely needs a new resolved class."],"tags":["unicode","bidi","codegen","data-file","validation"],"backgroundTag":null,"analyzedSha":"ac49b09b7d83ede19581fa94a8b892b07d309baf","analyzedAt":"2026-08-12T17:03:16.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}