{"record":{"id":"b28fe1853cf12f9b","repo":"can1357/oh-my-pi","slug":"composer-style-id-must-be-a-non-empty-trimmed-stri","errorCode":null,"errorMessage":"Composer style id must be a non-empty trimmed string","messagePattern":"Composer style id must be a non-empty trimmed string","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/tui/src/components/composer/registry.ts","lineNumber":46,"sourceCode":"/**\n * Whether a style paints its own row foreground.\n *\n * Extensions registered before `filledSurface` existed received undecorated\n * row text, so an omitted flag remains filled for extension-owned ids.\n */\nexport function isFilledComposerStyle(style: ComposerStyle): boolean {\n\treturn style.filledSurface ?? !isBuiltinComposerStyle(style.id);\n}\n\n/**\n * Register one extension-owned composer style for this process.\n *\n * Built-in ids and duplicate extension ids are rejected. The returned disposer\n * removes only this registration.\n */\nexport function registerComposerStyle(style: ComposerStyle): () => void {\n\tconst id = style.id.trim();\n\tif (id.length === 0 || id !== style.id) throw new TypeError(\"Composer style id must be a non-empty trimmed string\");\n\tif (isBuiltinComposerStyle(id)) throw new Error(`Cannot replace built-in composer style \"${id}\"`);\n\tif (extensionComposerStyles.has(id)) throw new Error(`Composer style \"${id}\" is already registered`);\n\textensionComposerStyles.set(id, style);\n\treturn () => {\n\t\tif (extensionComposerStyles.get(id) === style) extensionComposerStyles.delete(id);\n\t};\n}\n\n/** Style object for a composer shape; unknown ids fall back to `box`. */\nexport function getComposerStyle(id: EditorBorderStyle): ComposerStyle {\n\treturn extensionComposerStyles.get(id) ?? BUILTIN_COMPOSER_STYLES[id] ?? boxComposerStyle;\n}\n","sourceCodeStart":28,"sourceCodeEnd":59,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/tui/src/components/composer/registry.ts#L28-L59","documentation":"registerComposerStyle() validates extension composer style ids: the id must be non-empty after trimming and must already be trimmed. If `style.id.trim()` differs from `style.id` (leading/trailing whitespace) or trims to empty, a TypeError is thrown at registration time.","triggerScenarios":"Calling registerComposerStyle with a ComposerStyle whose `id` is \"\", \"   \", \"my-style \", or \" my-style\" — any id with surrounding whitespace or empty.","commonSituations":"Building id strings dynamically (e.g. from user input or config) that pick up whitespace; forgetting to set an id at all; template strings that end in a newline.","solutions":["Trim the id before registering: pass `id: rawId.trim()`","Ensure the id is non-empty after trimming","Fail fast on config parsing: validate ids at load time"],"exampleFix":"// before\nregisterComposerStyle({ id: name, ...style })\n// after\nregisterComposerStyle({ id: name.trim(), ...style })","handlingStrategy":"validation","validationCode":"function assertValidStyleId(id: string): void {\n  const t = id.trim();\n  if (t.length === 0 || t !== id) throw new TypeError(`invalid composer style id: ${JSON.stringify(id)}`);\n}","typeGuard":"function isTrimmedNonEmpty(id: string): boolean {\n  const t = id.trim();\n  return t.length > 0 && t === id;\n}","tryCatchPattern":"try {\n  registerComposerStyle(style);\n} catch (err) {\n  if (err instanceof TypeError && err.message.includes(\"non-empty trimmed\")) {\n    style = { ...style, id: style.id.trim() || fallbackId() };\n    registerComposerStyle(style);\n  } else throw err;\n}","preventionTips":["Always construct ids with `.trim()` from raw input","Validate style ids at config-load time, not at registration","Never build ids from multi-line template strings"],"tags":["validation","api-misuse","tui"],"backgroundTag":"invalid-identifier","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}