{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "jsx-utils",
	"type": "registry:lib",
	"description": "A set of utilities for working with JSX.",
	"files": [
		{
			"path": "./src/registry/lib/jsx-utils.ts",
			"content": "/**\n * Finds the closing bracket (>) of a JSX tag while properly handling:\n * - String literals (both single and double quotes)\n * - JSX expressions with braces {}\n * - Parentheses in arrow functions and function calls\n * - Arrow functions (=>)\n *\n * @param tagCode - The tag code starting from the opening <\n * @returns The index of the closing bracket, or -1 if not found\n */\nfunction findTagClosingBracket(tagCode: string): number {\n\tlet inString = false;\n\tlet stringChar: string | null = null;\n\tlet braceDepth = 0;\n\tlet parenDepth = 0;\n\n\tfor (let i = 1; i < tagCode.length; i++) {\n\t\tconst char = tagCode[i];\n\t\tconst prevChar = tagCode[i - 1];\n\n\t\tif (inString && prevChar === \"\\\\\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === '\"' || char === \"'\") {\n\t\t\tif (!inString) {\n\t\t\t\tinString = true;\n\t\t\t\tstringChar = char;\n\t\t\t} else if (char === stringChar && prevChar !== \"\\\\\") {\n\t\t\t\tinString = false;\n\t\t\t\tstringChar = null;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!inString) {\n\t\t\tif (char === \"{\") {\n\t\t\t\tbraceDepth++;\n\t\t\t} else if (char === \"}\") {\n\t\t\t\tbraceDepth--;\n\t\t\t} else if (char === \"(\") {\n\t\t\t\tparenDepth++;\n\t\t\t} else if (char === \")\") {\n\t\t\t\tparenDepth--;\n\t\t\t} else if (char === \">\" && braceDepth === 0 && parenDepth === 0) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn -1;\n}\n\n/**\n * Matches and extracts information about JSX tags in a string of code.\n * Handles three tag formats:\n * 1. Opening tags: <tag attr=\"value\">\n * 2. Self-closing tags: <tag />\n * 3. Closing tags: </tag>\n *\n * @param code - The string containing JSX code to analyze\n * @returns Object containing tag details or null if no match is found\n * @example\n * matchJsxTag('<div className=\"container\">');\n * // Returns:\n * // {\n * //   tag: '<div className=\"container\">',\n * //   tagName: 'div',\n * //   type: 'opening',\n * //   attributes: 'className=\"container\"',\n * //   startIndex: 0,\n * //   endIndex: 27\n * // }\n */\nexport function matchJsxTag(code: string) {\n\tif (code.trim() === \"\") {\n\t\treturn null;\n\t}\n\n\tconst tagStartMatch = code.match(/<\\/?([a-zA-Z][a-zA-Z0-9]*)/);\n\tif (!tagStartMatch || typeof tagStartMatch.index === \"undefined\") {\n\t\treturn null;\n\t}\n\n\tconst tagName = tagStartMatch[1];\n\tconst isClosingTag = tagStartMatch[0].startsWith(\"</\");\n\tconst startIndex = tagStartMatch.index;\n\n\tif (isClosingTag) {\n\t\tconst closingBracketIndex = code.indexOf(\">\", startIndex);\n\t\tif (closingBracketIndex === -1) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn {\n\t\t\ttag: code.slice(startIndex, closingBracketIndex + 1),\n\t\t\ttagName,\n\t\t\ttype: \"closing\",\n\t\t\tattributes: \"\",\n\t\t\tstartIndex,\n\t\t\tendIndex: closingBracketIndex + 1,\n\t\t};\n\t}\n\n\tconst tagContent = code.slice(startIndex);\n\tconst closingBracketPos = findTagClosingBracket(tagContent);\n\n\tif (closingBracketPos === -1) {\n\t\treturn null;\n\t}\n\n\tconst fullMatch = tagContent.slice(0, closingBracketPos + 1);\n\tconst isSelfClosing = fullMatch.endsWith(\"/>\");\n\n\tconst afterTagName = fullMatch.slice(tagName.length + 1);\n\tconst attributes = isSelfClosing\n\t\t? afterTagName.slice(0, -2).trim()\n\t\t: afterTagName.slice(0, -1).trim();\n\n\tconst type = isSelfClosing ? \"self-closing\" : \"opening\";\n\n\treturn {\n\t\ttag: fullMatch,\n\t\ttagName,\n\t\ttype,\n\t\tattributes,\n\t\tstartIndex,\n\t\tendIndex: startIndex + closingBracketPos + 1,\n\t};\n}\n\n/**\n * Completes any unclosed JSX tags in the provided code by adding their closing tags.\n * Maintains proper nesting order when adding closing tags.\n *\n * @param code - The JSX code string that may contain unclosed tags\n * @returns The completed JSX code with all necessary closing tags added\n * @example\n * completeJsxTag('<div><p');\n * // Returns: '<div></div>'\n */\nexport function completeJsxTag(code: string) {\n\tconst stack: string[] = [];\n\tlet result = \"\";\n\tlet currentPosition = 0;\n\n\twhile (currentPosition < code.length) {\n\t\tconst match = matchJsxTag(code.slice(currentPosition));\n\t\tif (!match) {\n\t\t\tbreak;\n\t\t}\n\n\t\tconst { tagName, type, endIndex } = match;\n\n\t\tif (type === \"opening\") {\n\t\t\tstack.push(tagName);\n\t\t} else if (type === \"closing\") {\n\t\t\tstack.pop();\n\t\t}\n\n\t\tresult += code.slice(currentPosition, currentPosition + endIndex);\n\t\tcurrentPosition += endIndex;\n\t}\n\n\treturn (\n\t\tresult +\n\t\tstack\n\t\t\t.reverse()\n\t\t\t.map((tag) => `</${tag}>`)\n\t\t\t.join(\"\")\n\t);\n}\n\n/**\n * Extracts JSX content from inside a return statement in the provided code.\n *\n * @param code - The code string containing a return statement with JSX\n * @returns The extracted JSX content as a string, or null if no content is found\n * @example\n * extractJsxContent('function Component() { return (<div>Hello</div>); }');\n * // Returns: '<div>Hello</div>'\n */\nexport function extractJsxContent(code: string): string | null {\n\tconst returnContentRegex = /return\\s*\\(\\s*([\\s\\S]*?)(?=\\s*\\);|\\s*$)/;\n\tconst match = code.match(returnContentRegex);\n\n\tif (match?.[1]) {\n\t\treturn match[1].trim();\n\t}\n\n\treturn null;\n}\n",
			"type": "registry:lib"
		}
	]
}
