// // ⚡ recursive react ⚡ extractor module v0.5 [new setup] // import React from 'react'; import { jsx as _jsx } from "react/jsx-runtime"; // // get the inscription ID to EXTRACT COMPONENTS FROM via the url query param // const url = new URL(import.meta.url); const params = new URLSearchParams(url.search); const idParam = params.get('id'); // get inscription ID of THIS module let currentId = (import.meta.url).split('/c0de')[1] if (currentId?.includes('?')) { currentId = currentId.split('?')[0] } currentId = 'c0de' + currentId currentId = 'extractor2' // // both types of functions can be extracted - function Name(){} (regular) and const Name = () => {} (arrow) // but we need to always convert to regular functions later on using this function // function convertArrowFunctionToRegular(funcString) { const arrowFunctionRegex = /const\s+(\w+)\s*=\s*\(?([^)]*)\)?\s*=>\s*\{/; return funcString.replace(arrowFunctionRegex, (match, functionName, params) => { return `function ${functionName}(${params}) {`; }); } // // this goes through the code and pulls out every function/component // const getComponentsRaw = (code) => { const components = []; const patterns = [ /(?:export\s+)?(?:const|let|var)?\s*(\w+)\s*=\s*\(.*?\)\s*=>\s*\{/g, /(?:export\s+)?function\s+(\w+)\s*\(.*?\)\s*\{/g, ]; patterns.forEach(pattern => { let match; while ((match = pattern.exec(code)) !== null) { const start = match.index; const componentName = match[1]; let bracesCount = 1; let i = match.index + match[0].length; let insideString = false; let stringChar = ''; while (i < code.length) { const char = code[i]; if (!insideString && (char === '"' || char === "'" || char === "`")) { insideString = true; stringChar = char; } else if (insideString && char === stringChar) { insideString = false; stringChar = ''; } else if (!insideString) { if (char === '{') { bracesCount++; } else if (char === '}') { bracesCount--; if (bracesCount === 0) { i++; break; } } } i++; } const componentCode = code.slice(start, i); components.push({ [componentName]: componentCode }); } }); return components; }; // // the main function; // const extract = async (file) => { // console.log('[⚡] extracting components from from ID: ' + file); const code = await fetch('/content/' + file).then(r => r.text()); const components = getComponentsRaw(code); // console.log(components) // detect imports const importRegex = /import\s+(\{[^}]+\}|\w+|\*\s+as\s+\w+)\s+from\s+['"]([^'"]+)['"];?/g; let match; const importStatements = []; // separate into identifier (React, CameraControls etc) and path (filename) while ((match = importRegex.exec(code)) !== null) { importStatements.push({ identifier: match[1].trim(), path: match[2].trim(), }); } // transpile each component for (const component of components) { const name = Object.keys(component)[0]; const jsxCode = Object.values(component)[0]; const babelCode = Babel.transform(jsxCode, { filename: 'bop.tsx', presets: [ ["react"], ], }).code; component.name = name; component.jsxCode = jsxCode; component.babelCode = babelCode; let importArgs = "React,_jsx"; const argValues = [React, _jsx]; const needToImport = []; for (const importStatement of importStatements) { // console.log('importStatement') // console.log(importStatement) // modules that ca be imported with import() if (!importStatement.path.includes(currentId)) { console.log('mod') console.log(importStatement) if (importStatement.identifier.startsWith('{')) { // destructured imports const destructuredNames = importStatement.identifier .replace('{', '') .replace('}', '') .split(',') .map(name => name.trim()); destructuredNames.forEach(name => { if (jsxCode.includes(name)) { needToImport.push({ name, path: importStatement.path }); importArgs += `,${name}`; } }); } else if (importStatement.identifier.startsWith('* as ')) { // wildcard imports const wildcardName = importStatement.identifier.split(' ')[2]; importArgs += `,${wildcardName}`; const mod = await import(importStatement.path); argValues.push(mod); } else { // default imports importArgs += `,${importStatement.identifier}`; } // import the modules required for the component for (const need of needToImport) { const mod = await import(need.path); argValues.push(mod[need.name]); } } else { console.log('else') console.log(importStatement) // console.log(importStatement) if (jsxCode.includes(importStatement.identifier)) { const importedModule = await extract(importStatement.path.replace(('/content/' + currentId + '?id='), '')); const extractedComponents = {}; importedModule.forEach(mod => { extractedComponents[mod.name] = mod.component; }); importArgs += `,${importStatement.identifier}`; argValues.push(extractedComponents); } } } let codee = component.babelCode if (codee.slice(0, 10).includes('const')) { codee = convertArrowFunctionToRegular(codee) } console.log(importArgs) console.log(argValues) // new Function() is similar to eval() const func = new Function(importArgs, `return ${codee}`); try { component.component = func(...argValues); } catch (error) { console.error('Error executing component function:', error); } } return components; }; const extractedComponents = await extract(idParam); // prep export object with all extracted components const obj = extractedComponents.reduce((acc, current) => { acc[current.name] = current.component; return acc; }, {}); export default obj; console.log(obj)