extract_svg
Extract SVG components from React/TypeScript/JavaScript files into individual SVG files, preserving structure while removing React-specific code.
Instructions
Extract SVG components from React/TypeScript/JavaScript files into individual .svg files. This tool will preserve the SVG structure and attributes while removing React-specific code. By default, the source file will be replaced with "MIGRATED TO " and a warning message after successful extraction, making it easy to track where the SVGs were moved to. This behaviour can be disabled by setting the DISABLE_SOURCE_REPLACEMENT environment variable to 'true'. The warning message can be customized by setting the WARNING_MESSAGE environment variable.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| sourcePath | Yes | Path to the source file containing SVG components | |
| targetDir | Yes | Directory where the SVG files should be written |
Implementation Reference
- src/index.ts:145-177 (handler)Executes the extract_svg tool: extracts SVGs using extractSvgs, writes individual SVG files to targetDir, optionally replaces source file with migration notice.} else if (request.params.name === 'extract_svg') { const { targetDir } = request.params.arguments as { targetDir: string }; const svgs = await this.extractSvgs(sourceCode); // Create target directory if it doesn't exist await fs.mkdir(targetDir, { recursive: true }); // Write each SVG to a separate file for (const svg of svgs) { const filePath = path.join(targetDir, `${svg.name}.svg`); await fs.writeFile(filePath, svg.content, 'utf-8'); } // Replace source file content with migration message if not disabled if (!DISABLE_SOURCE_REPLACEMENT) { const absoluteTargetDir = path.resolve(targetDir); await fs.writeFile( sourcePath, `MIGRATED TO ${absoluteTargetDir}${WARNING_MESSAGE}`, 'utf-8' ); } return { content: [ { type: 'text', text: `Successfully extracted ${svgs.length} SVG components to ${path.resolve(targetDir)}${ !DISABLE_SOURCE_REPLACEMENT ? `. Source file replaced with "MIGRATED TO ${path.resolve(targetDir)}"` : '' }`, }, ], };
- src/index.ts:83-96 (schema)Input schema definition for extract_svg tool requiring sourcePath and targetDir.inputSchema: { type: 'object', properties: { sourcePath: { type: 'string', description: 'Path to the source file containing SVG components', }, targetDir: { type: 'string', description: 'Directory where the SVG files should be written', }, }, required: ['sourcePath', 'targetDir'], },
- src/index.ts:80-97 (registration)Registers the extract_svg tool in the tools list with name, description, and input schema.{ name: 'extract_svg', description: 'Extract SVG components from React/TypeScript/JavaScript files into individual .svg files. This tool will preserve the SVG structure and attributes while removing React-specific code. By default, the source file will be replaced with "MIGRATED TO <target absolute path>" and a warning message after successful extraction, making it easy to track where the SVGs were moved to. This behaviour can be disabled by setting the DISABLE_SOURCE_REPLACEMENT environment variable to \'true\'. The warning message can be customized by setting the WARNING_MESSAGE environment variable.', inputSchema: { type: 'object', properties: { sourcePath: { type: 'string', description: 'Path to the source file containing SVG components', }, targetDir: { type: 'string', description: 'Directory where the SVG files should be written', }, }, required: ['sourcePath', 'targetDir'], }, },
- src/index.ts:264-295 (helper)Core extraction logic: parses source with Babel, traverses AST for SVG JSX in arrow function declarations, extracts using extractSvgContent.private async extractSvgs(sourceCode: string): Promise<SvgExtraction[]> { const ast = parser.parse(sourceCode, { sourceType: 'module', plugins: ['typescript', 'jsx'], }); const svgs: SvgExtraction[] = []; traverse(ast, { VariableDeclaration(path: NodePath<t.VariableDeclaration>) { const declaration = path.node.declarations[0]; if (t.isVariableDeclarator(declaration) && t.isIdentifier(declaration.id) && t.isArrowFunctionExpression(declaration.init)) { // Look for JSX in the arrow function body const body = declaration.init.body; if (t.isJSXElement(body)) { const svgContent = this.extractSvgContent(body); if (svgContent) { svgs.push({ name: declaration.id.name, content: svgContent }); } } } } }); return svgs; }
- src/index.ts:211-262 (helper)Helper to convert JSX SVG element to plain SVG string, handling attributes, nested elements, and text content.private extractSvgContent(jsxElement: t.JSXElement): string | null { // Check if this is an SVG element if (t.isJSXIdentifier(jsxElement.openingElement.name) && jsxElement.openingElement.name.name.toLowerCase() === 'svg') { // Convert JSX attributes to string const attributes = jsxElement.openingElement.attributes .map(attr => { if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) { const name = attr.name.name; if (t.isStringLiteral(attr.value)) { return `${name}="${attr.value.value}"`; } else if (t.isJSXExpressionContainer(attr.value) && t.isStringLiteral(attr.value.expression)) { return `${name}="${attr.value.expression.value}"`; } } return ''; }) .filter(Boolean) .join(' '); // Convert children to string const children = jsxElement.children .map(child => { if (t.isJSXElement(child)) { const elementName = (child.openingElement.name as t.JSXIdentifier).name; const childAttributes = child.openingElement.attributes .map(attr => { if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) { const name = attr.name.name; if (t.isStringLiteral(attr.value)) { return `${name}="${attr.value.value}"`; } } return ''; }) .filter(Boolean) .join(' '); return `<${elementName} ${childAttributes}>${child.children .map(c => t.isJSXText(c) ? c.value : '') .join('')}</${elementName}>`; } return ''; }) .join('\n '); return `<svg ${attributes}>\n ${children}\n</svg>`; } return null; }