diff --git a/lib/actions/loadFilesInfo.js b/lib/actions/loadFilesInfo.js index 9f9ad6a..96676e2 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"); @@ -11,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) @@ -66,7 +68,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. @@ -101,7 +103,7 @@ const processFileSchema = (filePath) => { } } - 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 @@ -170,15 +172,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,13 +212,16 @@ 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(), diff --git a/lib/actions/processChildrenWidget.js b/lib/actions/processChildrenWidget.js index 12ae266..60cb332 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,16 @@ const processChildrenWidget = (htmlContent, fileSchemas) => { childProps = { ...childProps, children: childChildren }; } - const importItemPropsStringSequence = + let importItemPropsStringSequence = convertObjectToArray(childProps).join(","); + // Adiciona os spreads junto com as propriedades do elemento JSX. Ex: + // 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..3c1fe01 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; @@ -391,11 +392,7 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { .replaceAll(MORE_THAN_ONE_SPACE, " "); let childProps = extractPropsFromJSX(htmlElementString); - - // console.log("======= TESTE DO MALACDO PROPS ======="); - // console.log(importItemFilePath); - // console.log(childProps); - // console.log("\n\n"); + const childSpreads = extractSpreadsFromJSX(htmlElementString); // get the children let childChildren = extractJSXChildren(htmlElementString); @@ -407,9 +404,16 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => { childProps = { ...childProps, children: childChildren }; } - const importItemPropsStringSequence = + let importItemPropsStringSequence = convertObjectToArray(childProps).join(","); + // Adiciona os spreads junto com as propriedades do elemento JSX. Ex: + // 0) { + importItemPropsStringSequence += `${importItemPropsStringSequence.length > 0 ? "," : ""} ${childSpreads.join(",")}`; + } + // Babel segue os padroes JS, por isso: // 1 - Adiciona uma uma função no topo // 2 - Fecha a função no final diff --git a/lib/compiler.js b/lib/compiler.js index bde5fcd..ac87f2c 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -15,21 +15,12 @@ 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); - +/** + * 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 +109,28 @@ 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(entryFile); + + // Executa processo final para gerar bundle e esquemas de arquivos + run_final_process(filesInfo); +} + module.exports = { compile_files, }; 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 fad6f70..f188838 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -11,6 +11,7 @@ const { read_alem_config } = require("./config"); 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,6 +49,10 @@ async function dev(opts) { watchFolders(["./src"], async (path) => { loading = log.loading(`Change detected in ${path}, rebuilding...`); + + // Atualiza o arquivo no cache para ser acessado posteriormente no re-build() + filesContentCache.updateFileContent(path); + await build().catch((err) => { loading.error(); log.error(err); @@ -219,32 +224,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..ad57853 100644 --- a/lib/parsers/extractJSX.js +++ b/lib/parsers/extractJSX.js @@ -1,166 +1,65 @@ 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 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], -// }); - -// // Percorre a AST para encontrar JSX -// traverse(ast, { -// ReturnStatement(path) { -// if ( -// path.getFunctionParent().isArrowFunctionExpression() || -// path.getFunctionParent().isFunctionExpression() || -// path.getFunctionParent().isFunctionDeclaration() -// ) { -// const jsxAST = path.node.argument; -// if (jsxAST) { -// const jsxCode = generate(jsxAST, { concise: true }).code; -// jsxList.push(jsxCode); -// } -// } -// }, -// ArrowFunctionExpression(path) { -// // Verifica se o corpo é um JSXElement ou JSXFragment -// 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; -// } - -// 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; -// } +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); + } +} 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-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 b59836e..994022e 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", @@ -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",