diff --git a/lib/actions/getFileExports.js b/lib/actions/getFileExports.js new file mode 100644 index 0000000..9c94876 --- /dev/null +++ b/lib/actions/getFileExports.js @@ -0,0 +1,138 @@ +/** + * Handle const/var/let names to avoid duplicates + */ +const { + BETWEEN_EXPORT_CONST_AND_EQUAL, + SPACES, + BETWEEN_EXPORT_DEFAULT_FUNCTION_AND_OPEN_PARENTHESE, + AFTER_EXPORT_DEFAULT, + SPECIAL_CHARACTERS_AND_SPACES, + BETWEEN_EXPORT_LET_AND_EQUAL, + BETWEEN_EXPORT_VAR_AND_EQUAL, + BETWEEN_EXPORT_FUNCTION_AND_OPEN_PARENTHESE, +} = require("../regexp"); + +/** + * Get "export const" items + * @param {string} content + */ +const getExportConsts = (content) => { + let foundItems = content.match(BETWEEN_EXPORT_CONST_AND_EQUAL); + + // Remove spaces + if (foundItems) { + foundItems = foundItems.map((item) => item.replaceAll(SPACES, "")); + } + + return foundItems || []; +}; + +/** + * Get "export let" items + * @param {string} content + */ +const getExportLets = (content) => { + let foundItems = content.match(BETWEEN_EXPORT_LET_AND_EQUAL); + + // Remove spaces + if (foundItems) { + foundItems = foundItems.map((item) => item.replaceAll(SPACES, "")); + } + + return foundItems || []; +}; + +/** + * Get "export var" items + * @param {string} content + */ +const getExportVars = (content) => { + let foundItems = content.match(BETWEEN_EXPORT_VAR_AND_EQUAL); + + // Remove spaces + if (foundItems) { + foundItems = foundItems.map((item) => item.replaceAll(SPACES, "")); + } + + return foundItems || []; +}; + +/** + * Get "export function" items + * @param {string} content + */ +const getExportFunction = (content) => { + let foundItems = content.match(BETWEEN_EXPORT_FUNCTION_AND_OPEN_PARENTHESE); + + // Remove spaces + if (foundItems) { + foundItems = foundItems.map((item) => item.replaceAll(SPACES, "")); + } + + return foundItems || []; +}; + +/** + * Get "export default function" items + * @param {string} content + */ +const getExportDefaultFunction = (content) => { + let foundItems = content.match( + BETWEEN_EXPORT_DEFAULT_FUNCTION_AND_OPEN_PARENTHESE, + ); + + // Remove spaces + if (foundItems) { + foundItems = foundItems.map((item) => item.replaceAll(SPACES, "")); + } + + return foundItems || []; +}; + +/** + * Get "export default" items + * @param {string} content + */ +const getExportDefault = (content) => { + // Remove all "export default function" + const _content = content.replaceAll("export default function", ""); + + let foundItems = _content.match(AFTER_EXPORT_DEFAULT); + + // Remove spaces + if (foundItems) { + foundItems = foundItems.map((item) => + item.replaceAll(SPACES, "").replaceAll(SPECIAL_CHARACTERS_AND_SPACES, ""), + ); + } + + return foundItems || []; +}; + +/** + * Generates the exports schema + * + * + * exports organizer - original state + * + * returns: [{MyVar: "MyVar"}, {MyVar2: "MyVar2"}] + * + * + * @param {{filePath: string, toImport: string[], content: string}[]} fileSchemas + * @returns {Record}[]>} + */ +const getFileExports = (fileContent) => { + // TODO: melhorar isso usando Babel ? (pode ser mais penoso para processar se usar Babel) + const exports = [ + ...getExportConsts(fileContent), + ...getExportLets(fileContent), + ...getExportVars(fileContent), + ...getExportFunction(fileContent), + ...getExportDefaultFunction(fileContent), + ...getExportDefault(fileContent), + ]; + + return exports; +}; + +module.exports = getFileExports; diff --git a/lib/actions/handleNames.js b/lib/actions/handleNames.js index f96c256..fca5fd2 100644 --- a/lib/actions/handleNames.js +++ b/lib/actions/handleNames.js @@ -3,114 +3,8 @@ */ const replaceIdentifierInCode = require("../parsers/replaceIdentifierInCode"); -const { - BETWEEN_EXPORT_CONST_AND_EQUAL, - SPACES, - BETWEEN_EXPORT_DEFAULT_FUNCTION_AND_OPEN_PARENTHESE, - AFTER_EXPORT_DEFAULT, - SPECIAL_CHARACTERS_AND_SPACES, - BETWEEN_EXPORT_LET_AND_EQUAL, - BETWEEN_EXPORT_VAR_AND_EQUAL, - BETWEEN_EXPORT_FUNCTION_AND_OPEN_PARENTHESE, -} = require("../regexp"); const { create_new_name } = require("../utils"); - -/** - * Get "export const" items - * @param {string} content - */ -const getExportConsts = (content) => { - let foundItems = content.match(BETWEEN_EXPORT_CONST_AND_EQUAL); - - // Remove spaces - if (foundItems) { - foundItems = foundItems.map((item) => item.replaceAll(SPACES, "")); - } - - return foundItems || []; -}; - -/** - * Get "export let" items - * @param {string} content - */ -const getExportLets = (content) => { - let foundItems = content.match(BETWEEN_EXPORT_LET_AND_EQUAL); - - // Remove spaces - if (foundItems) { - foundItems = foundItems.map((item) => item.replaceAll(SPACES, "")); - } - - return foundItems || []; -}; - -/** - * Get "export var" items - * @param {string} content - */ -const getExportVars = (content) => { - let foundItems = content.match(BETWEEN_EXPORT_VAR_AND_EQUAL); - - // Remove spaces - if (foundItems) { - foundItems = foundItems.map((item) => item.replaceAll(SPACES, "")); - } - - return foundItems || []; -}; - -/** - * Get "export function" items - * @param {string} content - */ -const getExportFunction = (content) => { - let foundItems = content.match(BETWEEN_EXPORT_FUNCTION_AND_OPEN_PARENTHESE); - - // Remove spaces - if (foundItems) { - foundItems = foundItems.map((item) => item.replaceAll(SPACES, "")); - } - - return foundItems || []; -}; - -/** - * Get "export default function" items - * @param {string} content - */ -const getExportDefaultFunction = (content) => { - let foundItems = content.match( - BETWEEN_EXPORT_DEFAULT_FUNCTION_AND_OPEN_PARENTHESE, - ); - - // Remove spaces - if (foundItems) { - foundItems = foundItems.map((item) => item.replaceAll(SPACES, "")); - } - - return foundItems || []; -}; - -/** - * Get "export default" items - * @param {string} content - */ -const getExportDefault = (content) => { - // Remove all "export default function" - const _content = content.replaceAll("export default function", ""); - - let foundItems = _content.match(AFTER_EXPORT_DEFAULT); - - // Remove spaces - if (foundItems) { - foundItems = foundItems.map((item) => - item.replaceAll(SPACES, "").replaceAll(SPECIAL_CHARACTERS_AND_SPACES, ""), - ); - } - - return foundItems || []; -}; +const getFileExports = require("./getFileExports"); /** * Generates the exports schema @@ -130,33 +24,16 @@ const getExportDefault = (content) => { * @param {{filePath: string, toImport: string[], content: string}[]} fileSchemas * @returns {Record}[]>} */ -const getExportsOrganizer = (fileSchemas) => { - const exportsOrganizer = []; - - fileSchemas.forEach((schema) => { - // Cria lista de exports - exportsOrganizer[schema.filePath] = []; - - let exports = []; - // Verifica se já tem os nomes de elementos no conteúdo anterior - // exports = [...exports, ...getExportConsts(schema.content)]; - - // TODO: melhorar isso usando Babel - exports = [ - ...getExportConsts(schema.content), - ...getExportLets(schema.content), - ...getExportVars(schema.content), - ...getExportFunction(schema.content), - ...getExportDefaultFunction(schema.content), - ...getExportDefault(schema.content), - ]; - - exports.forEach((exportItem) => - exportsOrganizer[schema.filePath].push({ [exportItem]: exportItem }), - ); +const getExportsOrganizer = (fileContent) => { + // Cria lista de exports + const exports = getFileExports(fileContent); + const fileExportsOrganizer = {}; + + exports.forEach((exportItem) => { + fileExportsOrganizer[exportItem] = exportItem; }); - return exportsOrganizer; + return { fileExportsOrganizer, exports }; }; /** @@ -188,22 +65,6 @@ const replaceItemNamesInOtherFilesContent = ( // do arquivo atual let fileSchemaContent = fileSchema.content; - // RegExp aqui - // Regex: Troca somente e tão somente o item, nem mais nem menos, evitando assim - // trocar items erronamente como na descricao acima. - // const replaceItemRegexp = new RegExp("\\b" + itemName + "\\b", "gm"); - - // fileSchemaContent = fileSchemaContent.replaceAll( - // replaceItemRegexp, - // newItemName, - // ); - - // fileSchemaContent = replaceContentInCurrentFile( - // fileSchemaContent, - // itemName, - // newItemName, - // ); - fileSchemaContent = replaceIdentifierInCode( fileSchemaContent, itemName, @@ -252,6 +113,7 @@ const replaceContentInCurrentFile = ( * @param {string} newItemName * @param {string} contentFilePath * @param {{filePath: string, toImport: string[], content: string}[]} fileSchemas schemas to change the files content when a item gets its name changed + * @param {string | undefined} previousExportKeyName Nome anterior do itemName caso seja um re-processo de um arquivo alterado */ const replaceNamesInContent = ( content, @@ -259,6 +121,7 @@ const replaceNamesInContent = ( newItemName, contentFilePath, fileSchemas, + previousExportKeyName, ) => { content = replaceIdentifierInCode(content, itemName, newItemName); @@ -272,50 +135,33 @@ const replaceNamesInContent = ( // 2 - Ir em todos arquivos que dependem deste arquivo e mudar o nome do item lá // Replace item names in other files content - fileSchemas = replaceItemNamesInOtherFilesContent( - contentFilePath, - itemName, - newItemName, - fileSchemas, - ); + if (!previousExportKeyName) { + fileSchemas = replaceItemNamesInOtherFilesContent( + contentFilePath, + itemName, + newItemName, + fileSchemas, + ); + } else { + fileSchemas = replaceItemNamesInOtherFilesContent( + contentFilePath, + previousExportKeyName, + newItemName, + fileSchemas, + ); + } return { content, fileSchemas }; }; -/** - * Verifica se o item (const, let, var, function) existe no content - * @param {string} content - * @param {string} itemName - */ -const checkIfItemExistInContent = (content, itemName) => { - // Replace const values - // ex: const App - // nao pega: const AppRoute - // O mesmo para os proximos - // (const App)[^a-zA-Z0-9=] - const constRegExp = new RegExp(`(const ${itemName})[^a-zA-Z0-9=]`, "gm"); - const letRegExp = new RegExp(`(let ${itemName})[^a-zA-Z0-9=]`, "gm"); - const varRegExp = new RegExp(`(var ${itemName})[^a-zA-Z0-9=]`, "gm"); - const functionRegExp = new RegExp( - `(function ${itemName})[^a-zA-Z0-9=]`, - "gm", - ); - - return Boolean( - content.match(constRegExp) || - content.match(letRegExp) || - content.match(varRegExp) || - content.match(functionRegExp), - ); -}; - /** * Handle const/var/let names to avoid duplicates * @param {{filePath: string, toImport: string[], content: string}[]} fileSchemas */ const handleNames = (fileSchemas) => { // reset_name_counter(); - let tempBundle = ""; + // Lista de nomes de exports já usados em toda a aplicação + const takenNames = []; /** * exports organizer - original state @@ -328,26 +174,26 @@ const handleNames = (fileSchemas) => { * "caminho/do/arquivo.jsx": [{MyVar: "MyVar_newName"}, {MyVar2: "MyVar2_nameName"}] * } */ - const exportsOrganizer = getExportsOrganizer(fileSchemas); - - // Observe and changes duplicated names - // reverse (need to load deepest content first) - const itemsToProcess = Object.keys(exportsOrganizer).reverse(); - // ex: itemKey = caminho/para/arquivo.tsx - itemsToProcess.forEach((itemKey) => { - const fileSchema = fileSchemas.find( - (fileSchema) => fileSchema.filePath === itemKey, - ); + // const exportsOrganizerData = getExportsOrganizer(fileSchemas); + // fileSchemas = exportsOrganizerData.fileSchemas; + // const exportsOrganizer = exportsOrganizerData.exportsOrganizer; + + fileSchemas.forEach((fileSchema, fileSchemaIndex) => { + // console.log("File:", fileSchema.filePath); let fileContent = fileSchema?.content || ""; + const exportsData = getExportsOrganizer(fileContent); + let fileExportsObj = exportsData.fileExportsOrganizer; + const fileExportsName = exportsData.exports; // Checa se o nome dos exports do arquivo já existem no bundle // Exports do arquivo atual - exportsOrganizer[itemKey].forEach((exportObj, objIndex) => { - const exportKeyName = Object.keys(exportObj)[0]; + fileExportsName.forEach((exportKeyName) => { + // const exportKeyName = Object.keys(exportObj)[0]; // Verifica se ja tem um recurso (const, var, let, function) usando esse nome - if (checkIfItemExistInContent(tempBundle, exportKeyName)) { + // if (checkIfItemExistInContent(tempBundle, exportKeyName)) { + if (takenNames.includes(exportKeyName)) { // Se tiver, troca o nome no arquivo/conteudo atual... // Troca nome do item no organizer @@ -355,7 +201,10 @@ const handleNames = (fileSchemas) => { * = {"caminho/arquivo.tsx": [index of export key][key name]} */ const newName = create_new_name(); - exportsOrganizer[itemKey][objIndex][exportKeyName] = newName; + // Registra novo nome + takenNames.push(newName); + + fileExportsObj[exportKeyName] = newName; // exportsOrganizer[itemKey][importKeyName] = 'NewName' // atualiza o fileContent com os novos items @@ -364,19 +213,115 @@ const handleNames = (fileSchemas) => { fileContent, exportKeyName, newName, - itemKey, + fileSchema.filePath, fileSchemas, ); fileContent = result.content; fileSchemas = result.fileSchemas; + } else { + // Registra o nome do elemento sendo exportado para evitar duplicatas + takenNames.push(exportKeyName); } }); - tempBundle += fileContent; + // Adiciona os exports para o esquema do arquivo + fileSchemas[fileSchemaIndex].exports = fileExportsObj; }); return fileSchemas; }; -module.exports = handleNames; +const handleNamesForChangedFile = ( + fileSchemas, + changedFileSchema, + changedFileSchemaIndex, + previousTakenName = [], +) => { + // reset_name_counter(); + // let tempBundle = ""; + // Lista de nomes de exports já usados em toda a aplicação + const takenNames = [...previousTakenName]; + + /** + * exports organizer - original state + * { + * "caminho/do/arquivo.jsx": [{MyVar: "MyVar"}, {MyVar2: "MyVar2"}] + * } + * + * exports organizer - when the item needs to be changed + * { + * "caminho/do/arquivo.jsx": [{MyVar: "MyVar_newName"}, {MyVar2: "MyVar2_nameName"}] + * } + */ + + let fileContent = changedFileSchema?.content || ""; + const exportsData = getExportsOrganizer(fileContent); + let fileExportsObj = exportsData.fileExportsOrganizer; + const fileExportsName = exportsData.exports; + + // Checa se o nome dos exports do arquivo já existem no bundle + // Exports do arquivo atual + fileExportsName.forEach((exportKeyName) => { + // const exportKeyName = Object.keys(exportObj)[0]; + + // Verifica se ja tem um recurso (const, var, let, function) usando esse nome + // if (checkIfItemExistInContent(tempBundle, exportKeyName)) { + if (takenNames.includes(exportKeyName)) { + // Se tiver, troca o nome no arquivo/conteudo atual... + + // Troca nome do item no organizer + /** + * = {"caminho/arquivo.tsx": [index of export key][key name]} + */ + const newName = create_new_name(); + + // Registra novo nome + takenNames.push(newName); + + fileExportsObj[exportKeyName] = newName; + // exportsOrganizer[itemKey][importKeyName] = 'NewName' + + // Pega o nome que era usado para o item antes do processo atual. Isso é importante pois + // os arquivos que dependem deste item estão até este momento, usando o nome anterior + // e eles precisam ser alterados para o novo nome deste item. Isso será feito dentro do + // "replaceNamesInContent" + // Exemplo, se "Button" foi mudado para "A_14", logo, agora ele deve ter o nome + // "A_14" para que os arquivos que o receberam com esse nome possam ser atualizados + // com o novo novo nome que esse item receberá após ser editado. Sim, o valor sempre + // será diferente porque a função que cria novos nomes sempre é incrementada + const previousExportKeyName = + changedFileSchema.previousExports[exportKeyName]; + + // atualiza o fileContent com os novos items + // ...e atualiza o nome do item nos arquivos que dependem dele + const result = replaceNamesInContent( + fileContent, + exportKeyName, + newName, + changedFileSchema.filePath, + fileSchemas, + previousExportKeyName, + ); + + fileContent = result.content; + fileSchemas = result.fileSchemas; + } else { + // Registra o nome do elemento sendo exportado para evitar duplicatas + takenNames.push(exportKeyName); + } + }); + + // Adiciona os exports para o esquema do arquivo + fileSchemas[changedFileSchemaIndex].exports = fileExportsObj; + + // tempBundle += fileContent; + // }); + + return fileSchemas; +}; + +module.exports = { + handleNames, + handleNamesForChangedFile, +}; diff --git a/lib/actions/loadCachedFilesInfo.js b/lib/actions/loadCachedFilesInfo.js new file mode 100644 index 0000000..619b22e --- /dev/null +++ b/lib/actions/loadCachedFilesInfo.js @@ -0,0 +1,163 @@ +const path = require("path"); +const fs = require("fs"); +const handleNames = require("./handleNames"); +const loadFilesInfo = require("./loadFilesInfo"); +const replaceIdentifierInCode = require("../parsers/replaceIdentifierInCode"); +const checkSyntaxError = require("../parsers/checkSyntaxError"); +const checkForWildcardImports = require("../parsers/checkForWildcardImports"); + +/** + * Gera um esquema com os arquivos sendo importados no projeto a partir de um ponto de entrada + * @param {*} changedFilePath + * @returns + */ +const loadCachedFilesInfo = (changedFilePath) => { + // TODO: testar o erro que acontece quando um arquivo é removido do import (resolvido?!) + let hasError = null; + const filesInfoRaw = fs.readFileSync(path.join(`./build/filesInfo.json`)); + const filesInfo = JSON.parse(filesInfoRaw); + const changedFileSchema = loadFilesInfo(changedFilePath, true).fileSchemas[0]; + + // Verifica cada arquivo jsx e ts para ver se estão quebrados ou não. + hasError = checkSyntaxError(changedFilePath); + if (hasError) { + return { + hasError, + fileSchemas: filesInfo, + }; + } + + hasError = checkForWildcardImports(changedFilePath); + if (hasError) { + return { + hasError, + fileSchemas: filesInfo, + }; + } + + // Verifica se o arquivo existe na lista de esquemas. Se for um arquivo novo, ele + // deve ser adicionado primeiro + const fileExists = filesInfo.find( + (fileInfo) => fileInfo.filePath === changedFilePath, + ); + // console.log("O arquivo solicitado existe?", fileExists); + if (!fileExists) { + // Se nao existir o arquivo no esquema, adiciona-o + filesInfo.push(changedFileSchema); + } + + // Pega os exports dos arquivos que esse arquivo alterado depende. Isso vai ser usado + // para mudar o nome deles dentro deste arquivo alterado. + let changedFileImportsName = {}; + + changedFileSchema.toImport.forEach((toImportFile) => { + // ex: toImportFile = caminho/arquivo/file.ts + let toImportSchemaRef = filesInfo.find( + (fileInfo) => fileInfo.filePath === toImportFile, + ); + + // Se o arquivo ainda não existe na lista de esquemas, adiciona-o. Isso pode acontecer + // quando um novo arquivo é adicionado no processo de desenvolvimento + // console.log("Existe arquivo de dependencia/import?", !!toImportSchemaRef); + if (!toImportSchemaRef) { + // Se nao existir o arquivo no esquema, processa ele para tratar tudo (como nomes) + // Depois adiciona-o à lista de filesInfo + // INFO: recursividade + const updatedFileSchemasCall = loadCachedFilesInfo(toImportFile); + hasError = updatedFileSchemasCall.hasError; + + // Se tiver erro desse processo recursivo, nao segue em frente + if (hasError) return; + + const updatedFileSchemasWithImportSchema = + updatedFileSchemasCall.fileSchemas; + toImportSchemaRef = updatedFileSchemasWithImportSchema.find( + (fileSchema) => fileSchema.filePath === toImportFile, + ); + filesInfo.push(toImportSchemaRef); + } + + // Se nenhum erro foi encontrado até aqui... + if (!hasError) { + // Atualiza a lista de imports com seu nome original ou alterado + changedFileImportsName = { + ...changedFileImportsName, + ...toImportSchemaRef.exports, + }; + } + }); + + if (hasError) { + return { + hasError, + fileSchemas: filesInfo, + }; + } + + // console.log("\n"); + // console.log("IMPORTS NAME:", changedFileImportsName); + // console.log("\n"); + + const changedFileImportsNameEntries = Object.entries(changedFileImportsName); + changedFileImportsNameEntries.forEach((entry) => { + changedFileSchema.content = replaceIdentifierInCode( + changedFileSchema.content, + entry[0], + entry[1], + ); + }); + + // Lista de nomes ja usados nos exports + const previousTakenNames = []; + + // Muda o esquema do arquivo alterado na estrutura geral de esquemas + let changedFileIndex = 0; + const updatedFilesInfo = filesInfo.map((fileInfo, index) => { + if (fileInfo.filePath === changedFilePath) { + changedFileIndex = index; + // console.log("Encontrado:", fileInfo); + + // Registra o nome anterior dos items sendo exportados para que eles + // possam ser usados na troca de nomes posteriormente + // Exemplo, se "Button" foi mudado para "A_14", logo, agora ele deve ter o nome + // "A_14" para que os arquivos que o receberam com esse nome possam ser atualizados + // com o novo novo nome que esse item receberá após ser editado. Sim, o valor sempre + // será diferente porque a função que cria novos nomes sempre é incrementada + // Isso será feito dentro do "handleNamesForChangedFile" -> "replaceNamesInContent" + changedFileSchema.previousExports = fileInfo.exports; + + return changedFileSchema; + } + + // Aproveita esse loop para registrar os nomes de exports ja usados + // INFO: pula se for o mesmo arquivo alterado + const fileExportsNamesEntries = Object.entries(fileInfo.exports).map( + (entry) => entry[1], + ); + previousTakenNames.push(...fileExportsNamesEntries); + + // Retorna o fileInfo ja existente que não é o arquivo alterado + return fileInfo; + }); + + // console.log("\n"); + // console.log("TAKEN NAMES:", previousTakenNames); + // console.log("\n"); + + // console.log("CHANGED FILE SCHEMA:", updatedFilesInfo[changedFileIndex]); + + // Handle names -> remove const duplicates + const contentOrderer = handleNames.handleNamesForChangedFile( + updatedFilesInfo, + changedFileSchema, + changedFileIndex, + previousTakenNames, + ); + + return { + hasError, + fileSchemas: contentOrderer, + }; +}; + +module.exports = loadCachedFilesInfo; diff --git a/lib/actions/loadFilesInfo.js b/lib/actions/loadFilesInfo.js index 23b59ff..ecfa12c 100644 --- a/lib/actions/loadFilesInfo.js +++ b/lib/actions/loadFilesInfo.js @@ -220,7 +220,7 @@ const processFileSchema = (filePath, processOnlyThisFile) => { * @param {*} entryFile * @returns */ -const loadFilesInfo = (entryFile) => { +const loadFilesInfo = (entryFile, processOnlyThisFile) => { // Reset state contentOrderer = []; processedFiles = []; @@ -230,7 +230,7 @@ const loadFilesInfo = (entryFile) => { orderedFilesToImport = []; // Start loading process - processFileSchema(entryFile); + processFileSchema(entryFile, processOnlyThisFile); // Finaliza o processo do contentOrderer deletando o campo "filesToImport" // de todos os filhos, já que agora náo são mais necessarios @@ -250,7 +250,7 @@ const loadFilesInfo = (entryFile) => { const initialFileSchemas = _.cloneDeep(contentOrderer); // Handle names -> remove const duplicates - contentOrderer = handleNames(contentOrderer); // INFO: parte que esta consumindo bastante recurso + contentOrderer = handleNames.handleNames(contentOrderer); // INFO: parte que esta consumindo bastante recurso return { hasError, diff --git a/lib/alem-vm/alem-vm.d.ts b/lib/alem-vm/alem-vm.d.ts index 80fa92d..5321448 100644 --- a/lib/alem-vm/alem-vm.d.ts +++ b/lib/alem-vm/alem-vm.d.ts @@ -745,23 +745,23 @@ export declare const OverlayTrigger: (params: { /** * A boolean value that determines whether the overlay is currently visible or not. */ - show: string; + show?: string; /** * An array of events that trigger the display of the overlay. In this example, the `trigger` prop is set to `["hover", "focus"]`, which means that the overlay will be displayed when the user hovers over or focuses on the element. */ - trigger: string[]; + trigger?: string[]; /** * An object that specifies the delay before the overlay is displayed or hidden. In this example, the `delay` prop is set to `{ show: 250, hide: 300 }`, which means that the overlay will be displayed after a 250-millisecond delay and hidden after a 300-millisecond delay. */ - delay: { show: number; hide: number }; + delay?: { show: number; hide: number }; /** * A string that specifies the position of the overlay relative to the trigger element. In this example, the `placement` prop is set to `"auto"`, which means that the position will be automatically determined based on available space. */ - placement: string; + placement?: string; /** * The content that will be displayed in the overlay. */ - overlay: any; + overlay?: any; children: JSX.Element | ReactElement | JSX.Element[] | string | number; }) => React.ReactNode; diff --git a/lib/build.js b/lib/build.js index da369de..af22813 100644 --- a/lib/build.js +++ b/lib/build.js @@ -1,13 +1,17 @@ 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"; // Main function to orchestrate the build script -async function build(opts) { +async function build(opts, changedFilePath) { create_dist(distFolder); - compile_files(opts); + if (!changedFilePath) { + compile_files(opts); + } else { + compile_changed_file(opts, changedFilePath); + } generate_data_json(); } diff --git a/lib/compiler.js b/lib/compiler.js index 7b1efb5..9a9b235 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -1,4 +1,4 @@ -const { create_dist, log, reset_name_counter } = require("./utils"); +const { log, reset_name_counter } = require("./utils"); const path = require("path"); const fs = require("fs"); const loadFilesInfo = require("./actions/loadFilesInfo"); @@ -15,8 +15,7 @@ const applyOptions = require("./actions/applyOptions"); const injectFoundRegExps = require("./actions/injectFoundRegExps"); const createSuspenseWidget = require("./actions/createSuspenseWidget"); const { millisToMinutesAndSeconds } = require("./helpers"); - -const distFolder = process.env.DIST_FOLDER || "build"; +const loadCachedFilesInfo = require("./actions/loadCachedFilesInfo"); /** * Executa os comandos finais antes de gerar o bundle e arquivos/estrutura de esquemas finais @@ -127,7 +126,7 @@ function run_final_process(filesInfo, opts) { */ function compile_files(opts) { reset_name_counter(); - create_dist(distFolder); + // create_dist(distFolder); Esta sendo feito pelo build.js linha 9 let entryFile = path.join(".", "src", "index.tsx"); entryFile = fs.existsSync(entryFile) @@ -150,11 +149,37 @@ function compile_files(opts) { ); } - // Salva o esquema inicial. Bom para log - // fs.writeFileSync( - // path.join(`./build/src/initial.json`), - // JSON.stringify(filesInfo.fileSchemas, null, 2), - // ); + // Salva o esquema inicial para ser reutilizado depois e melhorar a velocidade + // de leitura inicial dos arquivos. + fs.writeFileSync( + path.join(`./build/filesInfo.json`), + JSON.stringify(filesInfo.fileSchemas, null, 2), + ); + + // Executa processo final para gerar bundle e esquemas de arquivos + run_final_process(filesInfo, opts); +} + +function compile_changed_file(opts, changedFilePath) { + const showLogs = process.env.SHOW_EXECUTION_TIME === "true"; + if (showLogs) console.log("Processing files..."); + // Load project files + let start = Date.now(); + + const filesInfo = loadCachedFilesInfo(changedFilePath); + let end = Date.now(); + if (showLogs) { + console.log( + `loadCachedFilesInfo -> Execution time: ${millisToMinutesAndSeconds(end - start)} sec`, + ); + } + + // Salva o esquema inicial atualizado. + // INFO: esse é o arquivo de entrada principal para o restante dos processos + fs.writeFileSync( + path.join(`./build/filesInfo.json`), + JSON.stringify(filesInfo.fileSchemas, null, 2), + ); // Executa processo final para gerar bundle e esquemas de arquivos run_final_process(filesInfo, opts); @@ -162,4 +187,5 @@ function compile_files(opts) { module.exports = { compile_files, + compile_changed_file, }; diff --git a/lib/dev.js b/lib/dev.js index f359a70..58c8842 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -21,7 +21,8 @@ const GATEWAY_PATH = path.join(__dirname, "..", "gateway", "dist"); // Main function to orchestrate the dev script async function dev(opts) { - let loading = log.loading(`Building the project for the first time`); + log.info(`Building project...`); + // let loading = log.loading(`Building the project for the first time`); let NETWORK = opts.network || "mainnet"; await build(opts); @@ -31,7 +32,7 @@ async function dev(opts) { // log.error(err); // process.exit(1); // }); - loading.finish(); + // loading.finish(); // Start serving the development JSON const { io } = await serveDevJson({ @@ -48,17 +49,21 @@ async function dev(opts) { }); watchFolders(["./src"], async (path) => { - loading = log.loading(`Change detected in ${path}, rebuilding...`); + log.info(`Change detected in ${path}, rebuilding...`); // Atualiza o arquivo no cache para ser acessado posteriormente no re-build() filesContentCache.updateFileContent(path); - await build(opts).catch((err) => { - loading.error(); - log.error(err); - process.exit(1); - }); - loading.finish(); + // await build(opts, path).catch((err) => { + // loading.error(); + // log.error(err); + // process.exit(1); + // }); + // INFO: Using like this to have better error messages + await build(opts, path); + + // loading.finish(); + log.sucess(`Done.`); if (io) { const devJson = generateAllDevJson(NETWORK); io.emit("fileChange", devJson); @@ -138,7 +143,7 @@ function generateAllDevJson(network) { // serves the development json async function serveDevJson({ useSocket, useGateway, useOpen, port, network }) { - log.info(`Starting workspace`); + log.info(`Starting workspace...`); const app = express(); let server = http.createServer(app); let io = null; diff --git a/lib/parsers/checkForWildcardImports.js b/lib/parsers/checkForWildcardImports.js index b1073b5..c9832ec 100644 --- a/lib/parsers/checkForWildcardImports.js +++ b/lib/parsers/checkForWildcardImports.js @@ -1,4 +1,4 @@ -const fs = require("fs"); +const filesContentCache = require("../config/filesContentCache"); /** * Procura por import que usem "import * as" e dispara erro @@ -6,7 +6,7 @@ const fs = require("fs"); */ function checkForWildcardImports(filePath) { // Ler o conteúdo do arquivo - const code = fs.readFileSync(filePath, "utf8"); + const code = filesContentCache.getFileContent(filePath); if (code.includes("import * as")) { return `Not supported 'import * as' statement found in file ${filePath}`; diff --git a/lib/parsers/checkSyntaxError.js b/lib/parsers/checkSyntaxError.js index 036e5db..eb28488 100644 --- a/lib/parsers/checkSyntaxError.js +++ b/lib/parsers/checkSyntaxError.js @@ -1,7 +1,7 @@ -const fs = require("fs"); const babel = require("@babel/core"); const presetReactPath = require("./presetReactPath"); const presetTypescriptPath = require("./presetTypescriptPath"); +const filesContentCache = require("../config/filesContentCache"); /** * Checa a estrutura de arquivos .tsx e .jsx para ver se a estrutura está correta. @@ -11,7 +11,7 @@ const presetTypescriptPath = require("./presetTypescriptPath"); function checkSyntaxError(filePath) { let error = null; - const code = fs.readFileSync(filePath, { encoding: "utf8" }); + const code = filesContentCache.getFileContent(filePath); if (!code) { console.error(`Erro ao ler o arquivo ${filePath}`); diff --git a/package.json b/package.json index bdc4ffb..1e7afe6 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.1", + "version": "1.1.0", "main": "main.js", "types": "index.d.ts", "author": "Wenderson Pires - wendersonpires.near",