From 193789dbb93a29b3a34e77b8bbf09bf696420127 Mon Sep 17 00:00:00 2001 From: Wenderson Pires Date: Tue, 23 Apr 2024 16:52:04 -0300 Subject: [PATCH] added cache plugins, fixed duplicate props for Widgets during compilation, fixed props conflict --- lib/actions/loadFilesInfo.js | 6 ++ lib/actions/processChildrenWidget.js | 7 +-- lib/actions/transformSchemaToWidget.js | 18 ++---- .../stateless_renamePropsTo__props__.js | 59 +++++++++++++++++++ lib/config/filesContentCache.js | 17 ++++++ lib/parsers/extractPropsFromJSX.js | 45 ++++++++++---- lib/parsers/extractSpreadsFromJSX.js | 41 ------------- package.json | 2 +- 8 files changed, 123 insertions(+), 72 deletions(-) create mode 100644 lib/config/cache-plugins/stateless_renamePropsTo__props__.js delete mode 100644 lib/parsers/extractSpreadsFromJSX.js diff --git a/lib/actions/loadFilesInfo.js b/lib/actions/loadFilesInfo.js index 61009ae..aae1dce 100644 --- a/lib/actions/loadFilesInfo.js +++ b/lib/actions/loadFilesInfo.js @@ -74,6 +74,12 @@ const processFileSchema = (filePath, processOnlyThisFile) => { // Verifica cada arquivo jsx e ts para ver se estão quebrados ou não. hasError = checkSyntaxError(filePath); + + if (hasError) { + log.error(hasError); + return; + } + hasError = checkForWildcardImports(filePath); if (hasError) { diff --git a/lib/actions/processChildrenWidget.js b/lib/actions/processChildrenWidget.js index c2f122e..3ba1d6b 100644 --- a/lib/actions/processChildrenWidget.js +++ b/lib/actions/processChildrenWidget.js @@ -5,7 +5,6 @@ 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,14 +48,14 @@ const processChildrenWidget = (htmlContent, fileSchemas) => { // Processa o arquivo como Widget apenas se for achado na lista de schemas e // for um componente stateful if (componentSchema && !componentSchema.isModule) { - let childProps = extractPropsFromJSX(htmlElement); - const childSpreads = extractSpreadsFromJSX(htmlElement); + const extractPropsResult = extractPropsFromJSX(htmlElement); + let childProps = extractPropsResult.keyValueProps; + const childSpreads = extractPropsResult.spreads; let childChildren = extractJSXChildren(htmlElement); // INFO: Se tiver child dentro deste child (childChildren), chama essa mesma função recursivamente? // ja esta sendo feito pelo "transformSchemaToWidgets" if (childChildren) { - // childChildren = processChildrenWidget(childChildren, fileSchemas); childProps = { ...childProps, children: childChildren }; } diff --git a/lib/actions/transformSchemaToWidget.js b/lib/actions/transformSchemaToWidget.js index 3c1fe01..47bc537 100644 --- a/lib/actions/transformSchemaToWidget.js +++ b/lib/actions/transformSchemaToWidget.js @@ -31,7 +31,6 @@ 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; @@ -391,8 +390,10 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { .replaceAll(LINE_BREAKS, "") .replaceAll(MORE_THAN_ONE_SPACE, " "); - let childProps = extractPropsFromJSX(htmlElementString); - const childSpreads = extractSpreadsFromJSX(htmlElementString); + const extractPropsResult = extractPropsFromJSX(htmlElementString); + let childProps = extractPropsResult.keyValueProps; + + const childSpreads = extractPropsResult.spreads; // get the children let childChildren = extractJSXChildren(htmlElementString); @@ -630,17 +631,6 @@ const transformSchemaToWidget = (fileSchemas, additionalFileSchemas) => { // Reset error state processError = null; - // Tag alem files (INFO: Isso não está servindo pra nada atualmente) - // TODO: Checar para ver se remove nas versoes posteriores caso não tenha utilidade isso aqui - fileSchemas.forEach((fileSchema, fileSchemaIndex) => { - const isAlemImportableFile = fileSchema.filePath.includes( - "lib/alem-vm/importable/", - ); - - fileSchema.isAlemFile = isAlemImportableFile; - fileSchemas[fileSchemaIndex] = fileSchema; - }); - // Caso tenha dependencias do Alem (inportable items), prepara eles para serem injetados // Remove os elementos da chave em que está e coloca em uma nova linha contendo seu caminho // até a lib alem-vm/importable/item... diff --git a/lib/config/cache-plugins/stateless_renamePropsTo__props__.js b/lib/config/cache-plugins/stateless_renamePropsTo__props__.js new file mode 100644 index 0000000..0732215 --- /dev/null +++ b/lib/config/cache-plugins/stateless_renamePropsTo__props__.js @@ -0,0 +1,59 @@ +const parser = require("@babel/parser"); +const traverse = require("@babel/traverse").default; +const t = require("@babel/types"); +const hasWidgetPropsCheck = require("../../actions/hasWidgetPropsCheck"); +const generate = require("@babel/generator").default; + +/** + * Troca o nome de objeto global "props" para "__props__" para que as props do Widget parent não seja sobrescrevido. + * @param {*} code + * @returns + */ +function stateless_renamePropsTo__props__(code) { + // Stateless components only + if (!hasWidgetPropsCheck(code)) { + const ast = parser.parse(code, { + sourceType: "module", + plugins: ["jsx", "typescript"], + }); + + traverse(ast, { + ArrowFunctionExpression(path) { + // Procura por parâmetros chamados 'props' + path.node.params.forEach((param) => { + if (t.isIdentifier(param) && param.name === "props") { + // Renomeia para '__props__' + param.name = "__props__"; + // Renomeia todas as referências dentro do escopo da função + const binding = path.scope.getBinding("props"); + if (binding) { + binding.referencePaths.forEach((refPath) => { + refPath.node.name = "__props__"; + }); + } + } + }); + }, + FunctionDeclaration(path) { + // Similar ao ArrowFunctionExpression + path.node.params.forEach((param) => { + if (t.isIdentifier(param) && param.name === "props") { + param.name = "__props__"; + const binding = path.scope.getBinding("props"); + if (binding) { + binding.referencePaths.forEach((refPath) => { + refPath.node.name = "__props__"; + }); + } + } + }); + }, + }); + + return generate(ast, { retainLines: true, concise: false }).code; + } + + return code; +} + +module.exports = stateless_renamePropsTo__props__; diff --git a/lib/config/filesContentCache.js b/lib/config/filesContentCache.js index f364048..aa8864a 100644 --- a/lib/config/filesContentCache.js +++ b/lib/config/filesContentCache.js @@ -4,9 +4,16 @@ */ const fs = require("fs"); +const stateless_renamePropsTo__props__ = require("./cache-plugins/stateless_renamePropsTo__props__"); const filesContentCache = {}; +// TODO: usar esse processo para processar os arquivos apenas uma vez +const runPlugins = (code) => { + code = stateless_renamePropsTo__props__(code); + return code; +}; + const getFileContent = (filePath) => { // First, try to return the cached content if (filesContentCache[filePath]) { @@ -15,6 +22,11 @@ const getFileContent = (filePath) => { // If there's no cache, read file, save cache and return the file content let fileContent = fs.readFileSync(filePath, "utf8"); + + // Run plugins + fileContent = runPlugins(fileContent); + + // Store filesContentCache[filePath] = fileContent; return fileContent; @@ -23,6 +35,11 @@ const getFileContent = (filePath) => { const updateFileContent = (filePath) => { // Read file and save in cache let fileContent = fs.readFileSync(filePath, "utf8"); + + // Run plugins + fileContent = runPlugins(fileContent); + + // Store filesContentCache[filePath] = fileContent; }; diff --git a/lib/parsers/extractPropsFromJSX.js b/lib/parsers/extractPropsFromJSX.js index f4c98c5..00209a4 100644 --- a/lib/parsers/extractPropsFromJSX.js +++ b/lib/parsers/extractPropsFromJSX.js @@ -7,6 +7,8 @@ function extractPropsFromJSX(jsxString) { // V2 let propsObject = {}; + let spreads = []; + const ast = babel.parse(jsxString, { presets: [presetReactPath], }); @@ -28,17 +30,27 @@ function extractPropsFromJSX(jsxString) { : true; } propsObject[key] = value; - } else if (babel.types.isJSXSpreadAttribute(attr)) { - // Trata a propagação de objetos - if (babel.types.isObjectExpression(attr.argument)) { - attr.argument.properties.forEach((prop) => { - if (babel.types.isObjectProperty(prop)) { - const key = prop.key.name || prop.key.value; // Suporta tanto propriedades identificadas por nome quanto por valor - const value = generate(prop.value, { concise: true }).code; - propsObject[key] = value; - } - }); - } + } + // } else if (babel.types.isJSXSpreadAttribute(attr)) { + // // Trata a propagação de objetos + // if (babel.types.isObjectExpression(attr.argument)) { + // attr.argument.properties.forEach((prop) => { + // if (babel.types.isObjectProperty(prop)) { + // const key = prop.key.name || prop.key.value; // Suporta tanto propriedades identificadas por nome quanto por valor + // const value = generate(prop.value, { concise: true }).code; + // propsObject[key] = value; + // } + // }); + // } + // } + + // Extrais os spreads da estrutura + if (babel.types.isJSXSpreadAttribute(attr)) { + // Handles spread attributes + const spreadCode = `...${ + generate(attr.argument, { concise: true }).code + }`; + spreads.push(spreadCode); } }); @@ -46,7 +58,16 @@ function extractPropsFromJSX(jsxString) { }, }); - return propsObject; + return { + /** + * Propriedades que contem chave: valor + */ + keyValueProps: propsObject, + /** + * Spreads achados + */ + spreads, + }; } module.exports = extractPropsFromJSX; diff --git a/lib/parsers/extractSpreadsFromJSX.js b/lib/parsers/extractSpreadsFromJSX.js deleted file mode 100644 index 59db093..0000000 --- a/lib/parsers/extractSpreadsFromJSX.js +++ /dev/null @@ -1,41 +0,0 @@ -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/package.json b/package.json index bd71891..c923777 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.26", + "version": "1.0.0-beta.27", "main": "main.js", "types": "index.d.ts", "author": "Wenderson Pires - wendersonpires.near",