1 line
12 KiB
Plaintext
1 line
12 KiB
Plaintext
{"version":3,"sources":["../src/cartographer.ts","../src/constants.ts","../package.json"],"sourcesContent":["import fs from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { parse } from '@babel/parser';\nimport type {\n File as BabelFile,\n Node as BabelNode,\n JSXIdentifier,\n JSXMemberExpression,\n JSXOpeningElement,\n} from '@babel/types';\nimport MagicString from 'magic-string';\nimport type { Plugin } from 'vite';\n\nimport {\n DATA_ATTRIBUTES,\n R3F_BAILOUT_ELEMENTS,\n R3F_BAILOUT_PATTERNS,\n R3F_IMPORT_SOURCES,\n} from './constants';\n\nconst validExtensions = new Set(['.jsx', '.tsx']);\n\nexport function cartographer(): Plugin {\n let clientScript: string;\n let configuredRoot: string;\n let configuredRootName: string;\n\n return {\n name: '@replit/vite-plugin-cartographer',\n enforce: 'pre' as const,\n\n async configResolved(config) {\n configuredRoot = config.root;\n // The name of the directory that contains the configured root\n configuredRootName = path.basename(configuredRoot);\n\n // Resolve the client script path in both CJS and ESM environments\n const currentFileUrl =\n typeof __dirname === 'string'\n ? path.join(__dirname, '../dist/beacon/index.global.js')\n : fileURLToPath(\n new URL('../dist/beacon/index.global.js', import.meta.url),\n );\n\n try {\n clientScript = await fs.readFile(currentFileUrl, 'utf-8');\n } catch (error) {\n // eslint-disable-next-line no-console -- This is an error in the plugin\n console.error(\n '[replit-cartographer] Failed to load client script:',\n error,\n );\n }\n },\n\n resolveId(_source, _importer) {\n // Let Vite handle the resolution\n return null;\n },\n\n transform: {\n order: 'pre',\n async handler(code: string, id: string) {\n if (\n !validExtensions.has(path.extname(id)) ||\n id.includes('node_modules')\n ) {\n return null;\n }\n\n try {\n const ast = parse(code, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n });\n\n let isR3FFile = usesReactThreeFiber(ast);\n\n if (isR3FFile) {\n return null;\n }\n\n const magicString = new MagicString(code);\n let currentElement: BabelNode | null = null;\n\n // One day the JS ecosystem will decide on one standard to use, until then\n // We need to dynamically import this so that we don't mess with vite resolving this module\n // Handle CommonJS/ESM interop: @babel/traverse may be wrapped differently depending on the module system\n const traverseModule = await import('@babel/traverse');\n const traverse =\n (\n traverseModule.default as {\n default?: typeof traverseModule.default;\n }\n )?.default ||\n traverseModule.default ||\n traverseModule;\n\n if (typeof traverse !== 'function') {\n // eslint-disable-next-line no-console -- I want my errors to be logged :D\n console.error(\n `[replit-cartographer] @babel/traverse did not resolve to a function.`,\n );\n\n return null; // Skip transformation instead of crashing\n }\n\n traverse(ast, {\n JSXElement: {\n enter(elementPath) {\n if (isR3FFile) {\n return; // Optimization: Stop processing if we already know it's R3F\n }\n\n currentElement = elementPath.node;\n },\n exit() {\n currentElement = null;\n },\n },\n JSXOpeningElement(elementPath) {\n if (isR3FFile) {\n return;\n }\n\n const jsxNode = elementPath.node;\n const elementName = getElementName(jsxNode);\n\n if (!elementName) {\n return;\n }\n\n // Check if this file contains R3F elements that should trigger a file-level bailout\n if (shouldBailout(elementName)) {\n isR3FFile = true;\n elementPath.stop(); // Stop traversing this file entirely\n\n return;\n }\n\n // Skip instrumentation for specific ambiguous elements (like 'line')\n // We don't instrument them, but they don't trigger a file-level bailout\n if (elementName === 'line') {\n return;\n }\n\n if (currentElement) {\n const { line = 0, column: col = 0 } = jsxNode.loc?.start ?? {};\n\n const relativeToConfigured = path.relative(configuredRoot, id);\n const componentPath = path.join(\n configuredRootName,\n relativeToConfigured,\n );\n\n const componentMetadata =\n col === 0\n ? `${componentPath}:${line}`\n : `${componentPath}:${line}:${col}`;\n\n magicString.appendLeft(\n jsxNode.name.end ?? 0,\n ` ${DATA_ATTRIBUTES.METADATA}=\"${componentMetadata}\" ${DATA_ATTRIBUTES.COMPONENT_NAME}=\"${elementName}\"`,\n );\n }\n },\n });\n\n if (isR3FFile) {\n return null;\n }\n\n return {\n code: magicString.toString(),\n map: magicString.generateMap({ hires: true }),\n };\n } catch (error) {\n // eslint-disable-next-line no-console -- I want my errors to be logged :D\n console.error(`[replit-cartographer] Error processing ${id}:`, error);\n\n return null;\n }\n },\n },\n\n transformIndexHtml() {\n if (!clientScript) {\n return [];\n }\n\n return [\n {\n tag: 'script',\n attrs: { type: 'module' },\n children: clientScript,\n injectTo: 'head',\n },\n ];\n },\n };\n}\n\n// Helper function to extract element name from JSX node\nfunction getElementName(jsxNode: JSXOpeningElement): string | null {\n if (jsxNode.name.type === 'JSXIdentifier') {\n return jsxNode.name.name;\n }\n\n if (jsxNode.name.type === 'JSXMemberExpression') {\n const memberExpr = jsxNode.name as JSXMemberExpression;\n const object = memberExpr.object as JSXIdentifier;\n const property = memberExpr.property as JSXIdentifier;\n\n return `${object.name}.${property.name}`;\n }\n\n return null;\n}\n\nfunction usesReactThreeFiber(ast: BabelFile): boolean {\n return ast.program.body.some(\n (node) =>\n node.type === 'ImportDeclaration' &&\n typeof node.source.value === 'string' &&\n R3F_IMPORT_SOURCES.has(node.source.value),\n );\n}\n\nfunction shouldBailout(name: string): boolean {\n if (R3F_BAILOUT_ELEMENTS.has(name)) {\n return true;\n }\n\n return R3F_BAILOUT_PATTERNS.some((pattern) => name.match(pattern));\n}\n","export const DATA_ATTRIBUTES = {\n METADATA: 'data-replit-metadata',\n COMPONENT_NAME: 'data-component-name',\n} as const;\n\nexport const R3F_IMPORT_SOURCES = new Set([\n '@react-three/fiber',\n '@react-three/drei',\n 'react-three-fiber',\n]);\n\n// Elements that, if present, indicate the file is likely an R3F scene\nexport const R3F_BAILOUT_ELEMENTS = new Set([\n 'Canvas', // Top-level R3F component\n 'mesh',\n 'group',\n 'scene',\n 'primitive',\n 'points',\n 'instancedMesh',\n 'fog',\n 'fogExp2',\n 'object3D',\n]);\n\n// Regex patterns for elements that indicate R3F (e.g. <boxGeometry>, <ambientLight>)\nexport const R3F_BAILOUT_PATTERNS = [\n /Geometry$/,\n /Material$/,\n /Light$/,\n /Camera$/,\n /Helper$/,\n /Control$/,\n];\n","{\n \"name\": \"@replit/vite-plugin-cartographer\",\n \"version\": \"0.4.4\",\n \"private\": false,\n \"devDependencies\": {\n \"@replit/tsconfig\": \"workspace:*\",\n \"@types/babel__core\": \"^7.20.5\",\n \"@types/babel__traverse\": \"^7.20.6\",\n \"@types/node\": \"^22.5.5\",\n \"@typescript-eslint/eslint-plugin\": \"^6.7.0\",\n \"@typescript-eslint/parser\": \"^6.7.0\",\n \"happy-dom\": \"^20.0.2\",\n \"tsup\": \"^8.3.5\",\n \"tsx\": \"^4.9.5\",\n \"vite\": \"^5.4.10\",\n \"vitest\": \"^3.2.4\"\n },\n \"main\": \"./src/index.ts\",\n \"files\": [\n \"src\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"lint\": \"eslint src\",\n \"format\": \"prettier --write \\\"src/**/*.ts\\\"\",\n \"test\": \"vitest\"\n },\n \"dependencies\": {\n \"@babel/parser\": \"^7.26.9\",\n \"@babel/traverse\": \"^7.26.9\",\n \"@babel/types\": \"^7.26.9\",\n \"magic-string\": \"^0.30.12\",\n \"modern-screenshot\": \"^4.6.0\"\n }\n}\n"],"mappings":"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","names":[]} |