From e25b35df772ef5cfe7659fe0c9cd24caa28f6568 Mon Sep 17 00:00:00 2001 From: Wenderson Pires Date: Sat, 20 Apr 2024 23:28:24 -0300 Subject: [PATCH 1/4] added feature to extract spreads from JSX elements, bug fixes, features updated to use the new feature added --- lib/actions/processChildrenWidget.js | 8 +- lib/actions/transformSchemaToWidget.js | 123 +++++++++++++++- lib/dev.js | 52 +++---- lib/parsers/extractJSX.js | 193 ++++++++++--------------- lib/parsers/extractPropsFromJSX.js | 42 ------ lib/parsers/extractSpreadsFromJSX.js | 41 ++++++ lib/parsers/replaceJSXElement.js | 20 +-- package.json | 2 +- 8 files changed, 278 insertions(+), 203 deletions(-) create mode 100644 lib/parsers/extractSpreadsFromJSX.js diff --git a/lib/actions/processChildrenWidget.js b/lib/actions/processChildrenWidget.js index 12ae266..e56d754 100644 --- a/lib/actions/processChildrenWidget.js +++ b/lib/actions/processChildrenWidget.js @@ -5,6 +5,7 @@ const { } = require("../helpers"); const extractJSXChildren = require("../parsers/extractJSXChildren"); const extractPropsFromJSX = require("../parsers/extractPropsFromJSX"); +const extractSpreadsFromJSX = require("../parsers/extractSpreadsFromJSX"); const extractTopLevelJSXElements = require("../parsers/extractTopLevelJSXElements"); const replaceJSXElement = require("../parsers/replaceJSXElement"); @@ -49,6 +50,7 @@ const processChildrenWidget = (htmlContent, fileSchemas) => { // for um componente stateful if (componentSchema && !componentSchema.isModule) { let childProps = extractPropsFromJSX(htmlElement); + const childSpreads = extractSpreadsFromJSX(htmlElement); let childChildren = extractJSXChildren(htmlElement); // INFO: Se tiver child dentro deste child (childChildren), chama essa mesma função recursivamente? @@ -59,9 +61,13 @@ const processChildrenWidget = (htmlContent, fileSchemas) => { childProps = { ...childProps, children: childChildren }; } - const importItemPropsStringSequence = + let importItemPropsStringSequence = convertObjectToArray(childProps).join(","); + if (childSpreads.length > 0) { + importItemPropsStringSequence += `${importItemPropsStringSequence.length > 0 ? "," : ""} ${childSpreads.join(",")}`; + } + htmlElement = `const TempMethod = () => { return ${htmlElement} \n}`; htmlElement = replaceJSXElement( diff --git a/lib/actions/transformSchemaToWidget.js b/lib/actions/transformSchemaToWidget.js index 18dec73..5d2fce4 100644 --- a/lib/actions/transformSchemaToWidget.js +++ b/lib/actions/transformSchemaToWidget.js @@ -31,6 +31,7 @@ const analyzeFunctionSignature = require("../parsers/analyzeFunctionSignature"); const removeFunctionParams = require("../parsers/removeFunctionParams"); const transformAsyncAwait = require("../parsers/transformAsyncAwait"); const compilerOptions = require("./compilerOptions"); +const extractSpreadsFromJSX = require("../parsers/extractSpreadsFromJSX"); let processError = null; @@ -365,7 +366,30 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { // INFO: Esses comentarios acima creio que podem ser apagados, verificar // se ainda estou usando o modulo html parse + if (fileSchema.filePath.includes("FundingRaised.tsx")) { + console.log( + "fileSchema.content", + fileSchema.content, + "importItemWidgetComponentName", + importItemWidgetComponentName, + ); + console.log("\n\n"); + } + const jsxOnly = extractJSX(fileSchema.content); + // console.log("====="); + // console.log("FILE:", fileSchema.filePath); + // console.log("JSX ONLY:", jsxOnly); + + if (fileSchema.filePath.includes("FundingRaised.tsx")) { + console.log( + "jsxOnly", + jsxOnly, + "importItemWidgetComponentName", + importItemWidgetComponentName, + ); + console.log("\n\n"); + } const fixedJsxOnly = jsxOnly.length > 1 @@ -377,25 +401,82 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { importItemWidgetComponentName, ); + if (fileSchema.filePath.includes("FundingRaised.tsx")) { + console.log( + "fixedJsxOnly", + fixedJsxOnly, + "componentElements", + componentElements, + "importItemWidgetComponentName", + importItemWidgetComponentName, + ); + console.log("\n\n"); + } + + if (fileSchema.filePath.includes("FundingRaised.tsx")) { + console.log( + "AAAA - importItemWidgetComponentName: ", + importItemWidgetComponentName, + ); + console.log("\n\n"); + } + // Seta qualquer erro se tiver if (!processError && componentElements.error) { processError = `${fileSchema.filePath}: ${componentElements.error}`; } if (processError) return; + if (fileSchema.filePath.includes("FundingRaised.tsx")) { + console.log( + "AAAA 2 - importItemWidgetComponentName: ", + importItemWidgetComponentName, + ); + console.log("\n\n"); + } + // Transfor cada componente em Widget com suas propriedades componentElements.elements.forEach((div, divIndex) => { + if (fileSchema.filePath.includes("FundingRaised.tsx")) { + console.log( + "AAAA INFO - importItemWidgetComponentName: ", + importItemWidgetComponentName, + "div", + div, + "divIndex", + divIndex, + "componentElements.elements", + componentElements.elements, + ); + console.log("\n\n"); + } const htmlElementString = componentElements.elements[divIndex] .toString() .replaceAll(LINE_BREAKS, "") .replaceAll(MORE_THAN_ONE_SPACE, " "); let childProps = extractPropsFromJSX(htmlElementString); + // TODO: fazer isso dentro do "processChildrenWidget" também + const childSpreads = extractSpreadsFromJSX(htmlElementString); - // console.log("======= TESTE DO MALACDO PROPS ======="); - // console.log(importItemFilePath); - // console.log(childProps); - // console.log("\n\n"); + if (fileSchema.filePath.includes("FundingRaised.tsx")) { + console.log( + "AAAA 3 - importItemWidgetComponentName: ", + importItemWidgetComponentName, + ); + console.log("\n\n"); + } + + if (fileSchema.filePath.includes("Body.tsx")) { + console.log("htmlElementString: ", htmlElementString); + console.log("\n\n"); + console.log("======= TESTE DO MALACDO PROPS ======="); + console.log(importItemFilePath); + console.log(childProps); + console.log(childSpreads); + // console.log(["{...foo}", "{...foaao}"].join(" ")); + console.log("\n\n"); + } // get the children let childChildren = extractJSXChildren(htmlElementString); @@ -407,9 +488,21 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { childProps = { ...childProps, children: childChildren }; } - const importItemPropsStringSequence = + let importItemPropsStringSequence = convertObjectToArray(childProps).join(","); + if (childSpreads.length > 0) { + // console.log( + // "AAAAA ======>>>>>>>>", + // importItemPropsStringSequence, + // ); + importItemPropsStringSequence += `${importItemPropsStringSequence.length > 0 ? "," : ""} ${childSpreads.join(",")}`; + // console.log( + // "BBBBBB ======>>>>>>>>", + // importItemPropsStringSequence, + // ); + } + // Babel segue os padroes JS, por isso: // 1 - Adiciona uma uma função no topo // 2 - Fecha a função no final @@ -417,6 +510,16 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { // NOTE: nao adicionando a ultima linha, mas estou removendo a ultima linha // Caso quebre, ver isso. [Provavelmente o escape acima esta adicionando o } no final] + if (fileSchema.filePath.includes("FundingRaised.tsx")) { + console.log( + "BBBB - importItemWidgetComponentName: ", + importItemWidgetComponentName, + "fileBundle:", + fileBundle, + ); + console.log("\n\n"); + } + // Transform components generated by .jsx / .tsx into fileBundle = replaceJSXElement( fileBundle, @@ -425,6 +528,16 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { ``, ); + if (fileSchema.filePath.includes("FundingRaised.tsx")) { + console.log( + "CCCC - importItemWidgetComponentName: ", + importItemWidgetComponentName, + "fileBundle:", + fileBundle, + ); + console.log("\n\n"); + } + // Remove funcao no topo e ultima linha fechando a funcao fileBundle = fileBundle.replace("const TempMethod = () => {", ""); fileBundle = removeLastLineFromText(fileBundle); diff --git a/lib/dev.js b/lib/dev.js index fad6f70..0709ffc 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -219,32 +219,32 @@ async function serveDevJson({ useSocket, useGateway, useOpen, port, network }) { start = process.env.WSL_DISTRO_NAME ? "explorer.exe" : start; exec(`${start} http://127.0.0.1:${port}`); } - log.log(` - ┌─────────────────────────────────────────────────────────────┐ - │ BosLoader Server is Up and Running │ - │ │${ - useGateway - ? ` - │ ➜ Local Gateway: \u001b[32mhttp://127.0.0.1:${port}\u001b[0m │` - : "" - } - │ │ - │ ➜ Bos Loader Http: \u001b[32mhttp://127.0.0.1:${port}/api/loader\u001b[0m │${ - useSocket - ? ` - │ ➜ Bos Loader WebSocket: \u001b[32mws://127.0.0.1:${port}\u001b[0m │` - : "" - } - │ │ - │ Optionaly, to open local widgets: │ - │ 1. Visit either of the following sites: │ - │ - https://near.org/flags │ - │ - https://everything.dev/flags │ - │ 2. Paste the Bos Loader Http URL │ - │ │ - └─────────────────────────────────────────────────────────────┘ - `); - log.sucess(`Alem runnig on port ${port}!`); + // log.log(` + // ┌─────────────────────────────────────────────────────────────┐ + // │ BosLoader Server is Up and Running │ + // │ │${ + // useGateway + // ? ` + // │ ➜ Local Gateway: \u001b[32mhttp://127.0.0.1:${port}\u001b[0m │` + // : "" + // } + // │ │ + // │ ➜ Bos Loader Http: \u001b[32mhttp://127.0.0.1:${port}/api/loader\u001b[0m │${ + // useSocket + // ? ` + // │ ➜ Bos Loader WebSocket: \u001b[32mws://127.0.0.1:${port}\u001b[0m │` + // : "" + // } + // │ │ + // │ Optionaly, to open local widgets: │ + // │ 1. Visit either of the following sites: │ + // │ - https://near.org/flags │ + // │ - https://everything.dev/flags │ + // │ 2. Paste the Bos Loader Http URL │ + // │ │ + // └─────────────────────────────────────────────────────────────┘ + // `); + log.sucess(`Além runnig on port ${port}!`); }) .on("error", (err) => { log.error(err); diff --git a/lib/parsers/extractJSX.js b/lib/parsers/extractJSX.js index 1184fe9..37aef64 100644 --- a/lib/parsers/extractJSX.js +++ b/lib/parsers/extractJSX.js @@ -1,95 +1,110 @@ +// const babel = require("@babel/core"); +// const presetReact = require("@babel/preset-react"); +// const presetTypeScript = require("@babel/preset-typescript"); // Suporte TypeScript +// const traverse = require("@babel/traverse").default; +// const generate = require("@babel/generator").default; const babel = require("@babel/core"); -const presetReactPath = require("./presetReactPath"); -const pluginSyntaxJsx = require("./pluginSyntaxJsx"); +const presetReact = require("@babel/preset-react"); +const presetTypeScript = require("@babel/preset-typescript"); const traverse = require("@babel/traverse").default; const generate = require("@babel/generator").default; /** - * Extracts the JSX contents only from file + * Extracts JSX contents only from file * - * Isso retorna uma lista dos prinpais elementos JSX pais. + * Retorna uma lista dos principais elementos JSX pais. * - * @param {string} code - * @returns + * @param {string} code Código fonte de onde extrair JSX + * @returns {Array} Lista de códigos JSX */ function extractJSX(code) { - // V4 - Corrige erro onde verificacao de arrow functions para retorno de JSX estava sendo feito - // dentro do useEffect em sua funcao de limpeza. let jsxList = []; - - const ast = babel.parseSync(code, { - presets: [presetReactPath], - plugins: [pluginSyntaxJsx], // Assegura o suporte adequado para JSX + const ast = babel.parse(code, { + presets: [presetReact, presetTypeScript], + filename: "input.tsx", }); traverse(ast, { - ReturnStatement(path) { - // Esta verificação garante que estamos capturando retornos de componentes ou funções - // e não de hooks como useEffect - if ( - (path.getFunctionParent().isArrowFunctionExpression() && - path.getFunctionParent().parentPath.isVariableDeclarator()) || - path.getFunctionParent().isFunctionExpression() || - path.getFunctionParent().isFunctionDeclaration() - ) { - const jsxAST = path.node.argument; - - // Verifica se o retorno é um elemento JSX - if ( - jsxAST && - (jsxAST.type === "JSXElement" || jsxAST.type === "JSXFragment") - ) { - const jsxCode = generate(jsxAST, { concise: true }).code; - jsxList.push(jsxCode); - } - } + JSXElement(path) { + const jsxCode = generate(path.node, { concise: true }).code; + jsxList.push(jsxCode); + path.skip(); // Evita processar subelementos deste JSXElement novamente }, - ArrowFunctionExpression(path) { + ReturnStatement(path) { + // Processa apenas o retorno se for uma expressão JSX ou condicional contendo JSX if ( - path.node.body.type === "JSXElement" || - path.node.body.type === "JSXFragment" + path.node.argument && + [ + "JSXElement", + "JSXFragment", + "ConditionalExpression", + "LogicalExpression", + ].includes(path.node.argument.type) ) { - const jsxCode = generate(path.node.body, { concise: true }).code; - jsxList.push(jsxCode); + extractJSXFromNode(path.node.argument, jsxList); + path.skip(); // Evita reprocessar a expressão interna já manipulada } }, }); - return jsxList; + return [...new Set(jsxList)]; // Retorna apenas elementos únicos, removendo duplicatas } +function extractJSXFromNode(node, jsxList) { + if (!node) return; + if (node.type === "JSXElement" || node.type === "JSXFragment") { + const jsxCode = generate(node, { concise: true }).code; + if (!jsxList.includes(jsxCode)) { + jsxList.push(jsxCode); + } + } else if ( + node.type === "ConditionalExpression" || + node.type === "LogicalExpression" + ) { + // Recursivamente extrai JSX dos componentes das expressões condicionais e lógicas + extractJSXFromNode(node.consequent, jsxList); + extractJSXFromNode(node.alternate, jsxList); + } +} // function extractJSX(code) { -// // V3 -// // Retorna uma lista de elementos JSX. Entao se caso dentro da funçao for -// // encontrado mais de uma ocorrencia, retorna ambos. -// // Isso acontece em casos como do arquivo RouteLink que dependendo de uma comparação -// // retorna um grupo de jsx ou outro grupo de jsx. -// // Nessa versao 3, também retorna JSX que estão envoltos em arrow functions sem {}; - // let jsxList = []; -// // Analisa o código para AST -// const ast = babel.parseSync(code, { -// presets: [presetReactPath], +// const ast = babel.parse(code, { +// presets: [presetReact, presetTypeScript], // Usando presets React e TypeScript +// filename: "input.tsx", // Nome de arquivo fictício necessário para presets // }); -// // Percorre a AST para encontrar JSX // traverse(ast, { // ReturnStatement(path) { -// if ( -// path.getFunctionParent().isArrowFunctionExpression() || -// path.getFunctionParent().isFunctionExpression() || -// path.getFunctionParent().isFunctionDeclaration() +// let returnArg = path.node.argument; + +// // Manipula retorno de JSX dentro de blocos de código (ex: { return }) +// if (returnArg && returnArg.type === "BlockStatement") { +// returnArg.body.forEach((statement) => { +// if (statement.type === "ReturnStatement") { +// if ( +// statement.argument.type === "JSXElement" || +// statement.argument.type === "JSXFragment" +// ) { +// const jsxCode = generate(statement.argument, { +// concise: true, +// }).code; +// jsxList.push(jsxCode); +// } +// } +// }); +// } +// // Manipula retorno direto de JSX (ex: () => ) +// else if ( +// returnArg && +// (returnArg.type === "JSXElement" || returnArg.type === "JSXFragment") // ) { -// const jsxAST = path.node.argument; -// if (jsxAST) { -// const jsxCode = generate(jsxAST, { concise: true }).code; -// jsxList.push(jsxCode); -// } +// const jsxCode = generate(returnArg, { concise: true }).code; +// jsxList.push(jsxCode); // } // }, // ArrowFunctionExpression(path) { -// // Verifica se o corpo é um JSXElement ou JSXFragment +// // Diretamente retorna JSX ou fragmento JSX // if ( // path.node.body.type === "JSXElement" || // path.node.body.type === "JSXFragment" @@ -103,64 +118,4 @@ function extractJSX(code) { // return jsxList; // } -// function extractJSX(code) { -// // V2 = Retorna uma lista de elementos JSX. Entao se caso dentro da funçao for -// // encontrado mais de uma ocorrencia, retorna ambos. -// // Isso acontece em casos como do arquivo RouteLink que dependendo de uma comparação -// // retorna um grupo de jsx ou outro grupo de jsx -// let jsxList = []; - -// // Analisa o código para AST -// const ast = babel.parse(code, { -// presets: [presetReactPath], -// }); - -// // Percorre a AST para encontrar o JSX retornado pela função do componente -// traverse(ast, { -// ReturnStatement(path) { -// // Verifica se o retorno está dentro de uma função relevante (ArrowFunctionExpression ou outras) -// if ( -// path.getFunctionParent().isArrowFunctionExpression() || -// path.getFunctionParent().isFunctionExpression() || -// path.getFunctionParent().isFunctionDeclaration() -// ) { -// const jsxAST = path.node.argument; - -// // Gera código JSX a partir da subárvore AST e adiciona à lista -// const jsxCode = generate(jsxAST, { concise: true }).code; -// jsxList.push(jsxCode); -// // Não chama path.stop() para continuar a travessia e encontrar outros JSX -// } -// }, -// }); - -// // return jsx; -// return jsxList; -// } - -// function extractJSX(code) { -// let jsx = null; - -// // Analisa o código para AST -// const ast = babel.parse(code, { -// presets: [presetReactPath], -// }); - -// // Percorre a AST para encontrar o JSX retornado pela função do componente -// traverse(ast, { -// ReturnStatement(path) { -// // Verifica se o retorno está dentro de uma ArrowFunctionExpression -// if (path.getFunctionParent().isArrowFunctionExpression()) { -// const jsxAST = path.node.argument; - -// // Gera código JSX a partir da subárvore AST -// jsx = generate(jsxAST).code; -// path.stop(); // Interrompe a travessia após encontrar o primeiro JSX -// } -// }, -// }); - -// return jsx; -// } - module.exports = extractJSX; diff --git a/lib/parsers/extractPropsFromJSX.js b/lib/parsers/extractPropsFromJSX.js index 7f0aa5b..f4c98c5 100644 --- a/lib/parsers/extractPropsFromJSX.js +++ b/lib/parsers/extractPropsFromJSX.js @@ -49,46 +49,4 @@ function extractPropsFromJSX(jsxString) { return propsObject; } -// function extractPropsFromJSX(jsxString) { -// let propsObject = {}; - -// // Analisa o código JSX para AST -// const ast = babel.parse(jsxString, { -// presets: [presetReactPath], -// }); - -// // Percorre a AST para encontrar elementos JSX e suas propriedades -// traverse(ast, { -// JSXOpeningElement(path) { -// path.node.attributes.forEach((attr) => { -// if (babel.types.isJSXAttribute(attr)) { -// const key = attr.name.name; -// let value; - -// // Trata strings literais especialmente, envolvendo-as com {} -// if (babel.types.isStringLiteral(attr.value)) { -// value = `"${attr.value.value}"`; -// } else if (babel.types.isJSXExpressionContainer(attr.value)) { -// // Para expressões, gera o código diretamente -// value = generate(attr.value.expression, { concise: true }).code; -// } else { -// // Se o valor não for uma string literal ou expressão, trata de forma genérica -// // Isso pode incluir outros tipos como JSXElement, para os quais você pode querer expandir esta lógica -// value = attr.value -// ? generate(attr.value, { concise: true }).code -// : true; // Booleano true para props sem valor -// } - -// propsObject[key] = value; -// } -// }); - -// // Interrompe a travessia para evitar processamento desnecessário -// path.stop(); -// }, -// }); - -// return propsObject; -// } - module.exports = extractPropsFromJSX; diff --git a/lib/parsers/extractSpreadsFromJSX.js b/lib/parsers/extractSpreadsFromJSX.js new file mode 100644 index 0000000..59db093 --- /dev/null +++ b/lib/parsers/extractSpreadsFromJSX.js @@ -0,0 +1,41 @@ +const babel = require("@babel/core"); +const traverse = require("@babel/traverse").default; +const generate = require("@babel/generator").default; +const t = require("@babel/types"); +const presetReact = require("@babel/preset-react"); + +/** + * Extrai os spreads da estrutura de um JSX + * Exemplo, dado de entrada:

oi

+ * Saída: [ '{...foo}', '{...{ foobar: 1, ...foo }}' ] + * + * @param {*} jsxString + * @returns + */ +function extractSpreadsFromJSX(jsxString) { + let spreads = []; + + const ast = babel.parse(jsxString, { + presets: [presetReact], + }); + + traverse(ast, { + JSXOpeningElement(path) { + path.node.attributes.forEach((attr) => { + if (t.isJSXSpreadAttribute(attr)) { + // Handles spread attributes + const spreadCode = `...${ + generate(attr.argument, { concise: true }).code + }`; + spreads.push(spreadCode); + } + }); + + path.stop(); // Stops after the first JSX element + }, + }); + + return spreads; +} + +module.exports = extractSpreadsFromJSX; diff --git a/lib/parsers/replaceJSXElement.js b/lib/parsers/replaceJSXElement.js index ddb3d61..26933cb 100644 --- a/lib/parsers/replaceJSXElement.js +++ b/lib/parsers/replaceJSXElement.js @@ -1,5 +1,6 @@ const babel = require("@babel/core"); const presetReactPath = require("./presetReactPath"); +const presetTypescriptPath = require("./presetTypescriptPath"); const traverse = require("@babel/traverse").default; const generate = require("@babel/generator").default; @@ -20,33 +21,34 @@ const generate = require("@babel/generator").default; * @returns */ function replaceJSXElement(code, elementType, indexToReplace, newElementCode) { - const ast = babel.parse(code, { presets: [presetReactPath] }); + const ast = babel.parse(code, { + presets: [presetReactPath, presetTypescriptPath], + filename: "input.tsx", // Providing a filename for presets that require it + }); let currentIndex = 0; traverse(ast, { JSXElement(path) { if (path.node.openingElement.name.name === elementType) { if (currentIndex === indexToReplace) { - // Parse the new element to an AST const newAst = babel.parse(`
${newElementCode}
`, { - presets: [presetReactPath], + presets: [presetReactPath, presetTypescriptPath], + filename: "input.tsx", // Also for the new code's AST }); - // Extract the JSX element from the new AST const newElementAst = newAst.program.body[0].expression.children[0]; - // Replace the current JSXElement with the new one path.replaceWith(newElementAst); - path.stop(); // Stop the traversal once we've made our replacement + path.stop(); } currentIndex++; } }, }); - // Generate the new code from the modified AST const { code: newCode } = generate(ast, { - retainLines: true, - concise: true, + retainLines: true, // This option tries to use the same line numbers and indents for output as input + concise: false, // Set to false to avoid compacting the output too much + comments: true, // Preserve comments in the output }); return newCode; } diff --git a/package.json b/package.json index b59836e..d1f77bf 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "alem", "description": "Create web3 applications for NEAR BOS with a focus on performance and friendly development.", - "version": "1.0.0-beta.22", + "version": "1.0.0-beta.23", "main": "main.js", "types": "index.d.ts", "author": "Wenderson Pires - wendersonpires.near", From 3bf0a37ee91ab665174098b90e72f86076e960fe Mon Sep 17 00:00:00 2001 From: Wenderson Pires Date: Sun, 21 Apr 2024 03:08:44 -0300 Subject: [PATCH 2/4] implemented rebuild_file feature. This ensures that only the changed file be read again. --- lib/actions/loadFilesInfo.js | 94 +++++++++++++++++-- lib/actions/processChildrenWidget.js | 3 + lib/actions/transformFileToFileSchema.js | 2 +- lib/actions/transformSchemaToWidget.js | 114 +---------------------- lib/build.js | 8 +- lib/compiler.js | 75 ++++++++++++--- lib/dev.js | 9 +- package-lock.json | 10 +- package.json | 1 + 9 files changed, 174 insertions(+), 142 deletions(-) diff --git a/lib/actions/loadFilesInfo.js b/lib/actions/loadFilesInfo.js index 9f9ad6a..352af59 100644 --- a/lib/actions/loadFilesInfo.js +++ b/lib/actions/loadFilesInfo.js @@ -1,5 +1,6 @@ const path = require("path"); const fs = require("fs"); +const _ = require("lodash"); const helpers = require("../helpers"); const handleNames = require("./handleNames"); const removeCommentsFromTSX = require("../parsers/removeCommentsFromTSX"); @@ -66,7 +67,7 @@ let processedFiles = []; let orderedFilesToImport = []; // Sinal de erro let hasError = null; -const processFileSchema = (filePath) => { +const processFileSchema = (filePath, processOnlyThisFile) => { if (hasError) return; // Verifica cada arquivo jsx e ts para ver se estão quebrados ou não. @@ -170,15 +171,22 @@ const processFileSchema = (filePath) => { // Push current schema result contentOrderer.push(currentFileSchema); - // Recursividade - currentFileSchema.nextFilesToLoad.forEach((fileToImport) => { - // Nao pode ser um recurso do alem-vm - // if (!fileToImport.includes(ALEM_VM_FOLDER)) { - processFileSchema(fileToImport); - // } - }); + if (!processOnlyThisFile) { + // Recursividade + currentFileSchema.nextFilesToLoad.forEach((fileToImport) => { + // Nao pode ser um recurso do alem-vm + // if (!fileToImport.includes(ALEM_VM_FOLDER)) { + processFileSchema(fileToImport); + // } + }); + } }; +/** + * Gera um esquema com os arquivos sendo importados no projeto a partir de um ponto de entrada + * @param {*} entryFile + * @returns + */ const loadFilesInfo = (entryFile) => { // Reset state contentOrderer = []; @@ -203,17 +211,83 @@ const loadFilesInfo = (entryFile) => { return newItem; }); + // Registra uma copia (não referencia na mesmo ponto da memória) do esquema inicial inalterada + const initialFileSchemas = _.cloneDeep(contentOrderer); + // Handle names -> remove const duplicates contentOrderer = handleNames(contentOrderer); return { hasError, + initialFileSchemas, fileSchemas: contentOrderer, - // orderedFilesToImport: orderedFilesToImport.reverse(), orderedFilesToImport: contentOrderer .map((schema) => schema.filePath) .reverse(), }; }; -module.exports = loadFilesInfo; +/** + * Atualiza o esquema de arquivos iniciais alterando somente o arquivo que foi mudado + * @param {*} changedFilePath + * @returns + */ +const updateFilesInfo = (changedFilePath, previousInitialFileSchemas) => { + // Reset state + contentOrderer = []; + processedFiles = []; + hasError = null; + // NOTE: Nao esta sendo usado no momento porque esta usando o contentOrderer.filePath + // NOTE: contentOrderer.filePath funcionou melhor do que a sequencia do orderedFilesToImport + orderedFilesToImport = []; + + // Start loading process + processFileSchema(changedFilePath, true); + + // Finaliza o processo do contentOrderer deletando o campo "filesToImport" + // de todos os filhos, já que agora náo são mais necessarios + contentOrderer = contentOrderer.map((item) => { + const newItem = { + filePath: item.filePath, + toImport: item.toImport, + content: item.content, + }; + delete newItem.filesToImport; + return newItem; + }); + + // Busca a referencia deste arquivo no esquema de arquivos iniciais na memória + // e altera para os novos valores + const changedFilePreviousSchema = previousInitialFileSchemas.find( + (fileSchema) => fileSchema.filePath === changedFilePath, + ); + const changedFileIndex = previousInitialFileSchemas.indexOf( + changedFilePreviousSchema, + ); + + // Atualiza os dados do arquivo na lista de esquemas inicial já existente + const previousInitialFileSchemasCopy = _.cloneDeep( + previousInitialFileSchemas, + ); + previousInitialFileSchemasCopy[changedFileIndex] = contentOrderer[0]; + + // Handle names -> remove const duplicates + // INFO: É necessário fazer copias para não referenciar ao mesmo ponto de memória e causar um + // erro generalizado + let updatedFileSchemas = _.cloneDeep(previousInitialFileSchemasCopy); + updatedFileSchemas = handleNames(updatedFileSchemas); + + return { + hasError, + initialFileSchemas: previousInitialFileSchemasCopy, + fileSchemas: updatedFileSchemas, + orderedFilesToImport: updatedFileSchemas + .map((schema) => schema.filePath) + .reverse(), + }; +}; + +module.exports = { + loadFilesInfo, + updateFilesInfo, +}; diff --git a/lib/actions/processChildrenWidget.js b/lib/actions/processChildrenWidget.js index e56d754..60cb332 100644 --- a/lib/actions/processChildrenWidget.js +++ b/lib/actions/processChildrenWidget.js @@ -64,6 +64,9 @@ const processChildrenWidget = (htmlContent, fileSchemas) => { let importItemPropsStringSequence = convertObjectToArray(childProps).join(","); + // Adiciona os spreads junto com as propriedades do elemento JSX. Ex: + // 0) { importItemPropsStringSequence += `${importItemPropsStringSequence.length > 0 ? "," : ""} ${childSpreads.join(",")}`; } diff --git a/lib/actions/transformFileToFileSchema.js b/lib/actions/transformFileToFileSchema.js index a70c546..2ec54ac 100644 --- a/lib/actions/transformFileToFileSchema.js +++ b/lib/actions/transformFileToFileSchema.js @@ -9,7 +9,7 @@ const loadFilesInfo = require("./loadFilesInfo"); * @returns {{filePath: string, toImport: string[], content: string, finalFileBundle: string, componentImportItems:[], componentParamsItems:[], componentComponentItems: [], widgetName?: string, htmlElementsProps: {}}[]} */ const transformFileToFileSchema = (fileDir) => { - return loadFilesInfo(fileDir).fileSchemas[0]; + return loadFilesInfo.loadFilesInfo(fileDir).fileSchemas[0]; }; module.exports = transformFileToFileSchema; diff --git a/lib/actions/transformSchemaToWidget.js b/lib/actions/transformSchemaToWidget.js index 5d2fce4..6825351 100644 --- a/lib/actions/transformSchemaToWidget.js +++ b/lib/actions/transformSchemaToWidget.js @@ -366,30 +366,7 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { // INFO: Esses comentarios acima creio que podem ser apagados, verificar // se ainda estou usando o modulo html parse - if (fileSchema.filePath.includes("FundingRaised.tsx")) { - console.log( - "fileSchema.content", - fileSchema.content, - "importItemWidgetComponentName", - importItemWidgetComponentName, - ); - console.log("\n\n"); - } - const jsxOnly = extractJSX(fileSchema.content); - // console.log("====="); - // console.log("FILE:", fileSchema.filePath); - // console.log("JSX ONLY:", jsxOnly); - - if (fileSchema.filePath.includes("FundingRaised.tsx")) { - console.log( - "jsxOnly", - jsxOnly, - "importItemWidgetComponentName", - importItemWidgetComponentName, - ); - console.log("\n\n"); - } const fixedJsxOnly = jsxOnly.length > 1 @@ -401,55 +378,14 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { importItemWidgetComponentName, ); - if (fileSchema.filePath.includes("FundingRaised.tsx")) { - console.log( - "fixedJsxOnly", - fixedJsxOnly, - "componentElements", - componentElements, - "importItemWidgetComponentName", - importItemWidgetComponentName, - ); - console.log("\n\n"); - } - - if (fileSchema.filePath.includes("FundingRaised.tsx")) { - console.log( - "AAAA - importItemWidgetComponentName: ", - importItemWidgetComponentName, - ); - console.log("\n\n"); - } - // Seta qualquer erro se tiver if (!processError && componentElements.error) { processError = `${fileSchema.filePath}: ${componentElements.error}`; } if (processError) return; - if (fileSchema.filePath.includes("FundingRaised.tsx")) { - console.log( - "AAAA 2 - importItemWidgetComponentName: ", - importItemWidgetComponentName, - ); - console.log("\n\n"); - } - // Transfor cada componente em Widget com suas propriedades componentElements.elements.forEach((div, divIndex) => { - if (fileSchema.filePath.includes("FundingRaised.tsx")) { - console.log( - "AAAA INFO - importItemWidgetComponentName: ", - importItemWidgetComponentName, - "div", - div, - "divIndex", - divIndex, - "componentElements.elements", - componentElements.elements, - ); - console.log("\n\n"); - } const htmlElementString = componentElements.elements[divIndex] .toString() .replaceAll(LINE_BREAKS, "") @@ -459,25 +395,6 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { // TODO: fazer isso dentro do "processChildrenWidget" também const childSpreads = extractSpreadsFromJSX(htmlElementString); - if (fileSchema.filePath.includes("FundingRaised.tsx")) { - console.log( - "AAAA 3 - importItemWidgetComponentName: ", - importItemWidgetComponentName, - ); - console.log("\n\n"); - } - - if (fileSchema.filePath.includes("Body.tsx")) { - console.log("htmlElementString: ", htmlElementString); - console.log("\n\n"); - console.log("======= TESTE DO MALACDO PROPS ======="); - console.log(importItemFilePath); - console.log(childProps); - console.log(childSpreads); - // console.log(["{...foo}", "{...foaao}"].join(" ")); - console.log("\n\n"); - } - // get the children let childChildren = extractJSXChildren(htmlElementString); if (childChildren) { @@ -491,16 +408,11 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { let importItemPropsStringSequence = convertObjectToArray(childProps).join(","); + // Adiciona os spreads junto com as propriedades do elemento JSX. Ex: + // 0) { - // console.log( - // "AAAAA ======>>>>>>>>", - // importItemPropsStringSequence, - // ); importItemPropsStringSequence += `${importItemPropsStringSequence.length > 0 ? "," : ""} ${childSpreads.join(",")}`; - // console.log( - // "BBBBBB ======>>>>>>>>", - // importItemPropsStringSequence, - // ); } // Babel segue os padroes JS, por isso: @@ -510,16 +422,6 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { // NOTE: nao adicionando a ultima linha, mas estou removendo a ultima linha // Caso quebre, ver isso. [Provavelmente o escape acima esta adicionando o } no final] - if (fileSchema.filePath.includes("FundingRaised.tsx")) { - console.log( - "BBBB - importItemWidgetComponentName: ", - importItemWidgetComponentName, - "fileBundle:", - fileBundle, - ); - console.log("\n\n"); - } - // Transform components generated by .jsx / .tsx into fileBundle = replaceJSXElement( fileBundle, @@ -528,16 +430,6 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { ``, ); - if (fileSchema.filePath.includes("FundingRaised.tsx")) { - console.log( - "CCCC - importItemWidgetComponentName: ", - importItemWidgetComponentName, - "fileBundle:", - fileBundle, - ); - console.log("\n\n"); - } - // Remove funcao no topo e ultima linha fechando a funcao fileBundle = fileBundle.replace("const TempMethod = () => {", ""); fileBundle = removeLastLineFromText(fileBundle); diff --git a/lib/build.js b/lib/build.js index e717d3a..85773ab 100644 --- a/lib/build.js +++ b/lib/build.js @@ -1,6 +1,6 @@ const { generate_data_json } = require("./data.js"); const { create_dist, log } = require("./utils.js"); -const { compile_files } = require("./compiler.js"); +const { compile_files, compile_changed_file } = require("./compiler.js"); const distFolder = process.env.DIST_FOLDER || "build"; @@ -11,6 +11,11 @@ async function build() { generate_data_json(); } +async function rebuild_file(filePath) { + compile_changed_file(filePath); + generate_data_json(); +} + async function build_with_log() { await build(); let loading = log.loading("Building the project"); @@ -27,4 +32,5 @@ async function build_with_log() { module.exports = { build, build_with_log, + rebuild_file, }; diff --git a/lib/compiler.js b/lib/compiler.js index bde5fcd..9927b6f 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -15,21 +15,15 @@ const applyOptions = require("./actions/applyOptions"); const distFolder = process.env.DIST_FOLDER || "build"; -function compile_files() { - create_dist(distFolder); - - let entryFile = path.join(".", "src", "index.tsx"); - entryFile = fs.existsSync(entryFile) - ? entryFile - : path.join(".", "src", "index.jsx"); - if (!fs.existsSync(entryFile)) { - log.error("src/index.tsx or src/index.jsx not found."); - process.exit(1); - } - - // Load project files - const filesInfo = loadFilesInfo(entryFile); - +/** @type {{filePath: any;toImport: any;content: any;}[]} */ +let _initialFileSchemas = null; + +/** + * Executa os comandos finais antes de gerar o bundle e arquivos/estrutura de esquemas finais + * @param {{hasError: null;initialFileSchemas: {filePath: any;toImport: any;content: any;}[];fileSchemas: {filePath: string;toImport: string[];content: string;}[];orderedFilesToImport: string[];}} filesInfo + * @returns + */ +function run_final_process(filesInfo) { // Se não tiver erro if (filesInfo.hasError) { // Save bundle file with error info @@ -118,6 +112,57 @@ function compile_files() { } } +/** + * Le todos os arquivos independentes e compila pela primeira vez + */ +function compile_files() { + create_dist(distFolder); + + let entryFile = path.join(".", "src", "index.tsx"); + entryFile = fs.existsSync(entryFile) + ? entryFile + : path.join(".", "src", "index.jsx"); + if (!fs.existsSync(entryFile)) { + log.error("src/index.tsx or src/index.jsx not found."); + process.exit(1); + } + + // Load project files + const filesInfo = loadFilesInfo.loadFilesInfo(entryFile); + // Guarda a referencia do esquema inicial inalterada dos arquivos + _initialFileSchemas = filesInfo.initialFileSchemas; + + // Executa processo final para gerar bundle e esquemas de arquivos + run_final_process(filesInfo); +} + +/** + * Le apenas o arquivo alterado, mescla no esquema anterior e compila. Esse método poupa o re-processo + * de ler todos os arquivos novamente garantindo assim mais eficiencia durante o desenvolvimento. + * @param {*} filePath + * @returns + */ +function compile_changed_file(filePath) { + create_dist(distFolder); + + if (!fs.existsSync(filePath)) { + log.error(`${filePath} not found.`); + return; + } + + // Load changed file content + const updatedFileSchemaInfo = loadFilesInfo.updateFilesInfo( + filePath, + _initialFileSchemas, + ); + // Guarda a referencia atualizada do esquema inicial + _initialFileSchemas = updatedFileSchemaInfo.initialFileSchemas; + + // Re-executa processo final para gerar bundle e esquemas de arquivos + run_final_process(updatedFileSchemaInfo); +} + module.exports = { compile_files, + compile_changed_file, }; diff --git a/lib/dev.js b/lib/dev.js index 0709ffc..688eb08 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -8,7 +8,7 @@ const socketIo = require("socket.io"); const { exec } = require("child_process"); const { read_alem_config } = require("./config"); -const { build } = require("./build"); +const { build, rebuild_file } = require("./build"); const { log } = require("./utils"); const { injectHTML } = require("./parse"); @@ -48,7 +48,12 @@ async function dev(opts) { watchFolders(["./src"], async (path) => { loading = log.loading(`Change detected in ${path}, rebuilding...`); - await build().catch((err) => { + // await build().catch((err) => { + // loading.error(); + // log.error(err); + // process.exit(1); + // }); + await rebuild_file(path).catch((err) => { loading.error(); log.error(err); process.exit(1); diff --git a/package-lock.json b/package-lock.json index 4cae814..649acf9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "alem", - "version": "1.0.0-beta.20", + "version": "1.0.0-beta.23", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "alem", - "version": "1.0.0-beta.20", + "version": "1.0.0-beta.23", "license": "MIT", "dependencies": { "@babel/core": "^7.24.3", @@ -22,6 +22,7 @@ "crypto-js": "^4.2.0", "dotenv": "^16.4.5", "express": "^4.18.2", + "lodash": "^4.17.21", "mock-fs": "^5.2.0", "near-cli-rs": "^0.4.3", "node-html-parser": "^6.1.12", @@ -5769,6 +5770,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", diff --git a/package.json b/package.json index d1f77bf..994022e 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "crypto-js": "^4.2.0", "dotenv": "^16.4.5", "express": "^4.18.2", + "lodash": "^4.17.21", "mock-fs": "^5.2.0", "near-cli-rs": "^0.4.3", "node-html-parser": "^6.1.12", From 387212ef7484969bde7cd3f8cd339a0d38ae53af Mon Sep 17 00:00:00 2001 From: Wenderson Pires Date: Sun, 21 Apr 2024 03:50:26 -0300 Subject: [PATCH 3/4] implemented filesContentCache to improve development performance --- lib/actions/loadFilesInfo.js | 69 ++---------------------- lib/actions/transformFileToFileSchema.js | 2 +- lib/build.js | 8 +-- lib/compiler.js | 34 +----------- lib/config/filesContentCache.js | 32 +++++++++++ lib/dev.js | 14 ++--- 6 files changed, 46 insertions(+), 113 deletions(-) create mode 100644 lib/config/filesContentCache.js diff --git a/lib/actions/loadFilesInfo.js b/lib/actions/loadFilesInfo.js index 352af59..fe0f890 100644 --- a/lib/actions/loadFilesInfo.js +++ b/lib/actions/loadFilesInfo.js @@ -12,6 +12,7 @@ const { isWindows } = require("../constants"); const transformComponentReferenceToJSX = require("../parsers/transformComponentReferenceToJSX"); const hasWidgetPropsCheck = require("./hasWidgetPropsCheck"); const { removeImports } = require("../parse"); +const filesContentCache = require("../config/filesContentCache"); /** * Transform statefull components references to JSX (this applies for stateful and stateless components) @@ -102,7 +103,8 @@ const processFileSchema = (filePath, processOnlyThisFile) => { } } - let fileContent = fs.readFileSync(filePath, "utf8"); + // let fileContent = fs.readFileSync(filePath, "utf8"); + let fileContent = filesContentCache.getFileContent(filePath); // Remove comments from file // INFO: Esta sendo usado para remover comentários de arquivos jsx também @@ -227,67 +229,4 @@ const loadFilesInfo = (entryFile) => { }; }; -/** - * Atualiza o esquema de arquivos iniciais alterando somente o arquivo que foi mudado - * @param {*} changedFilePath - * @returns - */ -const updateFilesInfo = (changedFilePath, previousInitialFileSchemas) => { - // Reset state - contentOrderer = []; - processedFiles = []; - hasError = null; - // NOTE: Nao esta sendo usado no momento porque esta usando o contentOrderer.filePath - // NOTE: contentOrderer.filePath funcionou melhor do que a sequencia do orderedFilesToImport - orderedFilesToImport = []; - - // Start loading process - processFileSchema(changedFilePath, true); - - // Finaliza o processo do contentOrderer deletando o campo "filesToImport" - // de todos os filhos, já que agora náo são mais necessarios - contentOrderer = contentOrderer.map((item) => { - const newItem = { - filePath: item.filePath, - toImport: item.toImport, - content: item.content, - }; - delete newItem.filesToImport; - return newItem; - }); - - // Busca a referencia deste arquivo no esquema de arquivos iniciais na memória - // e altera para os novos valores - const changedFilePreviousSchema = previousInitialFileSchemas.find( - (fileSchema) => fileSchema.filePath === changedFilePath, - ); - const changedFileIndex = previousInitialFileSchemas.indexOf( - changedFilePreviousSchema, - ); - - // Atualiza os dados do arquivo na lista de esquemas inicial já existente - const previousInitialFileSchemasCopy = _.cloneDeep( - previousInitialFileSchemas, - ); - previousInitialFileSchemasCopy[changedFileIndex] = contentOrderer[0]; - - // Handle names -> remove const duplicates - // INFO: É necessário fazer copias para não referenciar ao mesmo ponto de memória e causar um - // erro generalizado - let updatedFileSchemas = _.cloneDeep(previousInitialFileSchemasCopy); - updatedFileSchemas = handleNames(updatedFileSchemas); - - return { - hasError, - initialFileSchemas: previousInitialFileSchemasCopy, - fileSchemas: updatedFileSchemas, - orderedFilesToImport: updatedFileSchemas - .map((schema) => schema.filePath) - .reverse(), - }; -}; - -module.exports = { - loadFilesInfo, - updateFilesInfo, -}; +module.exports = loadFilesInfo; diff --git a/lib/actions/transformFileToFileSchema.js b/lib/actions/transformFileToFileSchema.js index 2ec54ac..a70c546 100644 --- a/lib/actions/transformFileToFileSchema.js +++ b/lib/actions/transformFileToFileSchema.js @@ -9,7 +9,7 @@ const loadFilesInfo = require("./loadFilesInfo"); * @returns {{filePath: string, toImport: string[], content: string, finalFileBundle: string, componentImportItems:[], componentParamsItems:[], componentComponentItems: [], widgetName?: string, htmlElementsProps: {}}[]} */ const transformFileToFileSchema = (fileDir) => { - return loadFilesInfo.loadFilesInfo(fileDir).fileSchemas[0]; + return loadFilesInfo(fileDir).fileSchemas[0]; }; module.exports = transformFileToFileSchema; diff --git a/lib/build.js b/lib/build.js index 85773ab..e717d3a 100644 --- a/lib/build.js +++ b/lib/build.js @@ -1,6 +1,6 @@ const { generate_data_json } = require("./data.js"); const { create_dist, log } = require("./utils.js"); -const { compile_files, compile_changed_file } = require("./compiler.js"); +const { compile_files } = require("./compiler.js"); const distFolder = process.env.DIST_FOLDER || "build"; @@ -11,11 +11,6 @@ async function build() { generate_data_json(); } -async function rebuild_file(filePath) { - compile_changed_file(filePath); - generate_data_json(); -} - async function build_with_log() { await build(); let loading = log.loading("Building the project"); @@ -32,5 +27,4 @@ async function build_with_log() { module.exports = { build, build_with_log, - rebuild_file, }; diff --git a/lib/compiler.js b/lib/compiler.js index 9927b6f..ac87f2c 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -15,9 +15,6 @@ const applyOptions = require("./actions/applyOptions"); const distFolder = process.env.DIST_FOLDER || "build"; -/** @type {{filePath: any;toImport: any;content: any;}[]} */ -let _initialFileSchemas = null; - /** * Executa os comandos finais antes de gerar o bundle e arquivos/estrutura de esquemas finais * @param {{hasError: null;initialFileSchemas: {filePath: any;toImport: any;content: any;}[];fileSchemas: {filePath: string;toImport: string[];content: string;}[];orderedFilesToImport: string[];}} filesInfo @@ -128,41 +125,12 @@ function compile_files() { } // Load project files - const filesInfo = loadFilesInfo.loadFilesInfo(entryFile); - // Guarda a referencia do esquema inicial inalterada dos arquivos - _initialFileSchemas = filesInfo.initialFileSchemas; + const filesInfo = loadFilesInfo(entryFile); // Executa processo final para gerar bundle e esquemas de arquivos run_final_process(filesInfo); } -/** - * Le apenas o arquivo alterado, mescla no esquema anterior e compila. Esse método poupa o re-processo - * de ler todos os arquivos novamente garantindo assim mais eficiencia durante o desenvolvimento. - * @param {*} filePath - * @returns - */ -function compile_changed_file(filePath) { - create_dist(distFolder); - - if (!fs.existsSync(filePath)) { - log.error(`${filePath} not found.`); - return; - } - - // Load changed file content - const updatedFileSchemaInfo = loadFilesInfo.updateFilesInfo( - filePath, - _initialFileSchemas, - ); - // Guarda a referencia atualizada do esquema inicial - _initialFileSchemas = updatedFileSchemaInfo.initialFileSchemas; - - // Re-executa processo final para gerar bundle e esquemas de arquivos - run_final_process(updatedFileSchemaInfo); -} - module.exports = { compile_files, - compile_changed_file, }; diff --git a/lib/config/filesContentCache.js b/lib/config/filesContentCache.js new file mode 100644 index 0000000..f364048 --- /dev/null +++ b/lib/config/filesContentCache.js @@ -0,0 +1,32 @@ +/** + * Recurso criado para melhorar o desempenho durante o desenvolvimento e ler novamente somente + * os arquivos que foram alterados. + */ + +const fs = require("fs"); + +const filesContentCache = {}; + +const getFileContent = (filePath) => { + // First, try to return the cached content + if (filesContentCache[filePath]) { + return filesContentCache[filePath]; + } + + // If there's no cache, read file, save cache and return the file content + let fileContent = fs.readFileSync(filePath, "utf8"); + filesContentCache[filePath] = fileContent; + + return fileContent; +}; + +const updateFileContent = (filePath) => { + // Read file and save in cache + let fileContent = fs.readFileSync(filePath, "utf8"); + filesContentCache[filePath] = fileContent; +}; + +module.exports = { + getFileContent, + updateFileContent, +}; diff --git a/lib/dev.js b/lib/dev.js index 688eb08..f188838 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -8,9 +8,10 @@ const socketIo = require("socket.io"); const { exec } = require("child_process"); const { read_alem_config } = require("./config"); -const { build, rebuild_file } = require("./build"); +const { build } = require("./build"); const { log } = require("./utils"); const { injectHTML } = require("./parse"); +const filesContentCache = require("./config/filesContentCache"); // dist folder name when building an app const distFolder = process.env.DIST_FOLDER || "build"; @@ -48,12 +49,11 @@ async function dev(opts) { watchFolders(["./src"], async (path) => { loading = log.loading(`Change detected in ${path}, rebuilding...`); - // await build().catch((err) => { - // loading.error(); - // log.error(err); - // process.exit(1); - // }); - await rebuild_file(path).catch((err) => { + + // Atualiza o arquivo no cache para ser acessado posteriormente no re-build() + filesContentCache.updateFileContent(path); + + await build().catch((err) => { loading.error(); log.error(err); process.exit(1); From 46510fcdfd3956cab72ff37c5ba27ac10209575a Mon Sep 17 00:00:00 2001 From: Wenderson Pires Date: Mon, 22 Apr 2024 01:34:23 -0300 Subject: [PATCH 4/4] clean up --- lib/actions/loadFilesInfo.js | 1 - lib/actions/transformSchemaToWidget.js | 1 - lib/parsers/extractJSX.js | 56 -------------------------- 3 files changed, 58 deletions(-) diff --git a/lib/actions/loadFilesInfo.js b/lib/actions/loadFilesInfo.js index fe0f890..96676e2 100644 --- a/lib/actions/loadFilesInfo.js +++ b/lib/actions/loadFilesInfo.js @@ -103,7 +103,6 @@ const processFileSchema = (filePath, processOnlyThisFile) => { } } - // let fileContent = fs.readFileSync(filePath, "utf8"); let fileContent = filesContentCache.getFileContent(filePath); // Remove comments from file diff --git a/lib/actions/transformSchemaToWidget.js b/lib/actions/transformSchemaToWidget.js index 6825351..3c1fe01 100644 --- a/lib/actions/transformSchemaToWidget.js +++ b/lib/actions/transformSchemaToWidget.js @@ -392,7 +392,6 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { .replaceAll(MORE_THAN_ONE_SPACE, " "); let childProps = extractPropsFromJSX(htmlElementString); - // TODO: fazer isso dentro do "processChildrenWidget" também const childSpreads = extractSpreadsFromJSX(htmlElementString); // get the children diff --git a/lib/parsers/extractJSX.js b/lib/parsers/extractJSX.js index 37aef64..ad57853 100644 --- a/lib/parsers/extractJSX.js +++ b/lib/parsers/extractJSX.js @@ -1,8 +1,3 @@ -// const babel = require("@babel/core"); -// const presetReact = require("@babel/preset-react"); -// const presetTypeScript = require("@babel/preset-typescript"); // Suporte TypeScript -// const traverse = require("@babel/traverse").default; -// const generate = require("@babel/generator").default; const babel = require("@babel/core"); const presetReact = require("@babel/preset-react"); const presetTypeScript = require("@babel/preset-typescript"); @@ -66,56 +61,5 @@ function extractJSXFromNode(node, jsxList) { extractJSXFromNode(node.alternate, jsxList); } } -// function extractJSX(code) { -// let jsxList = []; - -// const ast = babel.parse(code, { -// presets: [presetReact, presetTypeScript], // Usando presets React e TypeScript -// filename: "input.tsx", // Nome de arquivo fictício necessário para presets -// }); - -// traverse(ast, { -// ReturnStatement(path) { -// let returnArg = path.node.argument; - -// // Manipula retorno de JSX dentro de blocos de código (ex: { return }) -// if (returnArg && returnArg.type === "BlockStatement") { -// returnArg.body.forEach((statement) => { -// if (statement.type === "ReturnStatement") { -// if ( -// statement.argument.type === "JSXElement" || -// statement.argument.type === "JSXFragment" -// ) { -// const jsxCode = generate(statement.argument, { -// concise: true, -// }).code; -// jsxList.push(jsxCode); -// } -// } -// }); -// } -// // Manipula retorno direto de JSX (ex: () => ) -// else if ( -// returnArg && -// (returnArg.type === "JSXElement" || returnArg.type === "JSXFragment") -// ) { -// const jsxCode = generate(returnArg, { concise: true }).code; -// jsxList.push(jsxCode); -// } -// }, -// ArrowFunctionExpression(path) { -// // Diretamente retorna JSX ou fragmento JSX -// if ( -// path.node.body.type === "JSXElement" || -// path.node.body.type === "JSXFragment" -// ) { -// const jsxCode = generate(path.node.body, { concise: true }).code; -// jsxList.push(jsxCode); -// } -// }, -// }); - -// return jsxList; -// } module.exports = extractJSX;