From 50770e7612daf65bff135681ae1a05bebb863db5 Mon Sep 17 00:00:00 2001 From: Wenderson Pires Date: Thu, 7 Mar 2024 03:28:10 -0300 Subject: [PATCH] implemented organizer feature for the build process. this was made to avoid the usage of something before its definition --- README.md | 4 ++ lib/build.js | 22 ++++++- lib/organize.js | 172 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 lib/organize.js diff --git a/README.md b/README.md index 5f2fe99..52b2946 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ Alem is a web3 JavaScript / TypeScript library for building user interfaces for - **Declarative:** Alem makes it painless to create interactive UIs. Design simple views for each state in your application, and Alem will efficiently update and render just the right components when your data changes. Declarative views make your code more predictable, simpler to understand, and easier to debug. - **Component-Based:** Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in JavaScript, you can easily pass rich data through your app. - **Learn Once, Write Anywhere:** We don't make assumptions about the rest of your technology stack, so you can develop new features in Alem without rewriting existing code. +- **CSS:** Alem supports .css files. Just create them and they will all be included in the application. +- **Easy State Management:** Use state management to make it easier to process data through the application. +- **Routes System:** An integrated router system that makes it possible to navigate between pages easily. +- **Much more:** Take a look at the other documentation items to learn how to use all the features provided by Alem. [**Learn how to use Alem in your project**](https://near.org/alem-lib.near/widget/Index). diff --git a/lib/build.js b/lib/build.js index bdc2aa3..cc9b97d 100644 --- a/lib/build.js +++ b/lib/build.js @@ -10,6 +10,11 @@ const { read_bos_config } = require("./config"); const pkg = require("../package.json"); const path = require("path"); const fs = require("fs"); +const { + checkImportFeatures, + checkFeaturesMarker, + replaceMarkers, +} = require("./organize.js"); const distFolder = process.env.DIST_FOLDER || "build"; @@ -82,10 +87,25 @@ function process_dist() { // loop through all files inside the './src' and get their content for_rfile(path.join(".", "src"), ["js", "jsx", "ts", "tsx"], (file) => { + // Verifica se a instancia dos objetos importados já estão no bundle body + // caso nao esteja, adicinar marcadores para inserir na posicao correta + // mais tarde + const pendingInstances = checkImportFeatures(file, fileBundleBody); + // console.log("PENDING INSTANCES", pendingInstances); + fileBundleBody += pendingInstances; + const fileBody = process_file(file); - fileBundleBody += fileBody; + + // Verificar se já existe um marcador de espaço para as instancias + // deste arquivo, se existir, deve colocar o conteúdo no espaço + // do marcador criado para ele + fileBundleBody = checkFeaturesMarker(fileBody, fileBundleBody); + + // fileBundleBody += fileBody; }); + fileBundleBody = replaceMarkers(fileBundleBody); + // finish the file body with the app indexer fileBundleBody += process_file( path.join(__dirname, "tools", "appIndexer.jsx"), diff --git a/lib/organize.js b/lib/organize.js new file mode 100644 index 0000000..a01621e --- /dev/null +++ b/lib/organize.js @@ -0,0 +1,172 @@ +/** + * Organize the sequence of instances and dependencies following an order of dependency. + * + * This is to avoid the usage of something before its definition + */ + +const fs = require("fs"); + +const ELEMENT_SPACE_MARKER = ":::SM:::"; + +function buildSpaceMarker(elementName) { + return `${ELEMENT_SPACE_MARKER}${elementName}${ELEMENT_SPACE_MARKER}`; +} + +function instanceElementExistsInBody(elementName, bundleBody) { + // Verificar se já tem algum "const/let/var " no corpo do arquivo + // se nao tiver, criar marcador de espaço para este elemento + // se tiver, apenas ignora + + return Boolean( + bundleBody.includes(`const ${elementName}`) || + bundleBody.includes(`let ${elementName}`) || + bundleBody.includes(`var ${elementName}`), + ); +} + +/** + * Vefirica se as instancias dos imports do arquivo já estao presentes dentro do bundleBody, caso não + * esteja, cria um marcador de espaço para alocar esse conteúdo pendente posteriormente. + * + * Isso é importante para manter as instancias na ordem correta e não ocorrer um error onde + * um recurso é chamado antes de ser implementado. + * @param {*} file + * @param {*} fileBundleBody + * @returns + */ +function checkImportFeatures(file, fileBundleBody) { + const fileContent = fs.readFileSync(file, "utf8"); + const foundItems = fileContent.match(/(?<=import)(.*?)(?=from)/gm); + + // List de pontos de espaço para inserir os conteúdos pendentes + let markers = ""; + + if (foundItems) { + foundItems.forEach((item) => { + // remove spaces and braces + const filteredItem = item + .replaceAll(" ", "") + .replaceAll("{", "") + .replaceAll("}", ""); + + // Check if there are more than one item + if (filteredItem.includes(",")) { + const subItems = filteredItem.split(","); + subItems.forEach((subItem) => { + if (!instanceElementExistsInBody(subItem, fileBundleBody)) { + // Insere um marcador de espaço para este elemento + markers += ` + ${buildSpaceMarker(subItem)} + `; + } + }); + + return; + } + + if (!instanceElementExistsInBody(filteredItem, fileBundleBody)) { + // Insere um marcador de espaço para este elemento + markers += ` + ${buildSpaceMarker(filteredItem)} + `; + } + }); + } + + return markers; +} + +const listInstancesContent = []; + +/** + * Verifica sem tem marcadores pendentes para as instancias dentro do corpo + * do arquivo atual, se tiver, coloca o conteúdo deste arquivo no marcador + * em questão + * @param {*} fileBody + * @param {*} bundleBody + */ +function checkFeaturesMarker(fileBody, bundleBody) { + // Regexp: buscar por palavras depois de const, let e var + const foundItems = fileBody.match( + /(?<=\bconst\s)(\w+)|(?<=\blet\s)(\w+)|(?<=\bvar\s)(\w+)/, + ); + + // Checar se possui marcador de espaço para as instancias encontradas + let hasMarker = false; + foundItems.forEach((instance) => { + if (bundleBody.includes(buildSpaceMarker(instance)) && !hasMarker) { + hasMarker = true; + + listInstancesContent.push({ + instanceName: instance, + marker: buildSpaceMarker(instance), + content: fileBody, + }); + } + }); + + // Se nenhum marcador for encontrado, simplesmente adiciona o conteúdo + // do arquivo atual ao conteúdo do bundle + if (!hasMarker) { + bundleBody += fileBody; + } + + return bundleBody; +} + +/** + * Troca os marcadores por seu respectivo conteúdo. Também verifica se um conteúdo de outro + * marcador deve ser colocado acima do marcador sendo tratado no momento. + * + * @param {*} bundleBody + * @returns + */ +function replaceMarkers(bundleBody) { + // console.log("LISTAAAA:", listInstancesContent); + const completed = []; + + // Varre a lista de instancias marcadas + listInstancesContent.forEach((instanceContent, index) => { + // Para cada marcador, verificar se dentro dele esta sendo usado a outras instancias + // dentro do "listInstancesContent". Se tiver, coloca primeiro o conteúdo dessa instancia + // e só depois coloca o conteúdo da instancia atual. Se isso ocorrer, deve-se remover + // a instancia adicional colocada acima da lista "listInstancesContent" + let markerContent = ""; + + if (!completed.includes(instanceContent.instanceName)) { + // Verifica sub items + listInstancesContent.forEach((subInstanceContent, subIndex) => { + // Se nao for o mesmo item e o item principal tem parte do item secundario... + if ( + instanceContent.content.includes(subInstanceContent.instanceName) && + instanceContent.instanceName !== subInstanceContent.instanceName + ) { + // Possui o sub item, coloca o conteúdo do subitem primeiro + // listInstancesContent[subIndex].done = true; + completed.push(listInstancesContent[subIndex].instanceName); + markerContent += listInstancesContent[subIndex].content; + } + }); + + // Coloca o conteúdo do item principal + // listInstancesContent[index].done = true; + completed.push(listInstancesContent[index].instanceName); + markerContent += listInstancesContent[index].content; + + // Adiciona o conteudo do marcador no corpo do bundle principal + bundleBody = bundleBody.replace(instanceContent.marker, markerContent); + } + }); + + // Remove o restante dos marcadores que não foram tratados. Esses possivelmente são + // de biblitecas, nao de arquivos do projeto + bundleBody = bundleBody.replaceAll(/(:::SM:::)(.*?)(:::SM:::)/g, ""); + + return bundleBody; +} + +module.exports = { + checkImportFeatures, + checkFeaturesMarker, + replaceMarkers, +};