diff --git a/docs/router/use-location.md b/docs/router/use-location.md index 26a0ca0..e146824 100644 --- a/docs/router/use-location.md +++ b/docs/router/use-location.md @@ -2,13 +2,15 @@ This hook returns the current location object. It can be useful if you'd like to perform some side effect whenever the current location changes. +Use `useLocation().isRoutesReady` to get to know when the routes are ready to be accessed. + ```ts // http://127.0.0.1:8080/alem-lib.near/widget/Index?path=profile import { useLocation } from "alem/hooks"; export const SomeComponent = () => { const location = useLocation(); - console.log(location); // { pathname: "profile", routes: ["home", "profile"] } + console.log(location); // { isRoutesReady: true, pathname: "profile", routes: ["home", "profile"] } return ""; }; diff --git a/lib/actions/addSignatures.js b/lib/actions/addSignatures.js new file mode 100644 index 0000000..593b901 --- /dev/null +++ b/lib/actions/addSignatures.js @@ -0,0 +1,24 @@ +const path = require("path"); +const fs = require("fs"); +const alemPkg = require("../../package.json"); + +const addSignatures = (bundleContent) => { + const projectPkg = JSON.parse( + fs.readFileSync(path.join("package.json"), "utf-8"), + ); + + const projectRepositoryLink = + projectPkg?.repository && typeof projectPkg?.repository === "string" + ? projectPkg?.repository + : projectPkg.repository?.url || ""; + + bundleContent = ` + /** Bundle generated by Além Library v${alemPkg.version} - See more here: https://github.com/wpdas/alem */ + ${projectRepositoryLink ? `/** Project repository: ${projectRepositoryLink.replaceAll("git+", "").replaceAll(".git", "")} */` : ""} + ${bundleContent} + `; + + return bundleContent; +}; + +module.exports = addSignatures; diff --git a/lib/actions/loadFilesContent.js b/lib/actions/loadFilesContent.js new file mode 100644 index 0000000..6b7b177 --- /dev/null +++ b/lib/actions/loadFilesContent.js @@ -0,0 +1,80 @@ +const { process_file } = require("../parse"); + +// Load App Files Content based on files schema +// const loadFilesContent = (orderedFilesToImport) => { +// let bundleFile = ""; +// orderedFilesToImport.forEach((filePath) => { +// bundleFile += process_file(filePath); +// }); + +// return bundleFile; +// }; + +/** + * (Recommended) + * Load files based on the filePath sequence + */ +const loadFilesContent = (filesToLoad) => { + let bundleFile = ""; + filesToLoad.forEach((filePath) => { + bundleFile += process_file(filePath); + }); + + return bundleFile; +}; + +/** + * NOTE: Esse modelo joga as dependencias pra cima + */ +// const loadFilesContentSendingImportsToTheTop = (filesSchema) => { +// let bundleFile = ""; + +// // 1 - carrega o "filePath" +// // 2 - carrega os arquivos "toImport" acima do "filePath" +// // 3 - verificar se o conteúdo já nao existe antes de adicionar +// // se existir, ignora a adicao +// // 4 - Se conteudo já existir e estiver abaixo do "filePath", remove ele +// // e tras pra cima + +// const addContent = (content) => { +// if (!bundleFile.includes(content)) { +// bundleFile = ` +// ${content} + +// ${bundleFile} +// `; +// } +// }; + +// filesSchema.forEach((fileSchema) => { +// const filePathContent = process_file(fileSchema.filePath); +// addContent(filePathContent); + +// // Adiciona os "toImport" deste File Schema +// fileSchema.toImport.forEach((dependencyFilePath) => { +// const dependentFileContent = process_file(dependencyFilePath); + +// // Checa se o conteudo dependente já existe e se esta acima do elemento +// // pai (filePath), se estiver embaixo, manda pra cima +// const filePathPosition = bundleFile.indexOf(filePathContent); +// const dependentPosition = bundleFile.indexOf(dependentFileContent); + +// // Se existir tanto um quanto outro... +// if (filePathPosition > 0 && dependentPosition > 0) { +// // Se o dependent estiver abaixo do filePathContent +// if (dependentPosition > filePathPosition) { +// // Remove o dependente do conteudo do bundle +// // Ele vai ser adicionado dnv no "addContent" abaixo, só que +// // acima do arquivo "filePath" +// bundleFile.replace(dependentFileContent, ""); +// } +// } + +// addContent(dependentFileContent); +// }); +// }); + +// return bundleFile; +// }; + +module.exports = loadFilesContent; diff --git a/lib/actions/loadFilesInfo.js b/lib/actions/loadFilesInfo.js new file mode 100644 index 0000000..2692904 --- /dev/null +++ b/lib/actions/loadFilesInfo.js @@ -0,0 +1,125 @@ +const path = require("path"); +const fs = require("fs"); +const helpers = require("../helpers"); +const { removeComments } = require("../parse"); + +/** + * To be like: + * + * ```ts + * [ + * { + * filePath: "file/path/ModuleFile.tsx", + * toImport: ["path/moduleFile1.tsx", "path/moduleFile2.tsx"] + * nextFilesToLoad: [ + * "path/to/import/ModuleFile1.tsx", + * "path/to/import/ModuleFile2.tsx", + * ] + * }, + * {...} + * {...} + * ] + * ``` + * + * Then, load files in a unique bundle, filtering to not add duplicated content + */ +let contentOrderer = []; +// Arquivos já processados (evita duplicidade) +let processedFiles = []; +// Lista em ordem de arquivos para carregar / importar +let orderedFilesToImport = []; +const processFileSchema = (filePath) => { + // Se estiver vazio no primeiro processo, adiciona o arquivo de entrada 1 + // (entry point File) + if (orderedFilesToImport.length === 0) { + orderedFilesToImport.push(filePath); + } + // console.log("\n\n"); + // console.log("Processando:", filePath, "||"); + let parentFolder = "."; + if (filePath) { + const parentPathParts = filePath.split("/"); + parentPathParts.pop(); + parentFolder = parentPathParts.join("/"); + } + + let fileContent = fs.readFileSync(filePath, "utf8"); + + // Remove comments from file + fileContent = removeComments(fileContent); + + const fileImportsPath = helpers.getImportsPath(fileContent); + const currentFileSchema = { + filePath: filePath, + // usado para guiar as proximas cargas + // pode ser deletado no final do processo + nextFilesToLoad: [], + toImport: [], + }; + fileImportsPath.forEach((importPath) => { + // Usa src para inicio ou o caminho do pai do arquivo sendo processado atualmente + let importedFileContentPath = path.join(parentFolder, importPath); + + importedFileContentPath = helpers.getFilePathWithType( + importedFileContentPath, + ); + + // Registra todos os arquivos que o arquivo atual pede para importar + if (importedFileContentPath) { + currentFileSchema.toImport.push(importedFileContentPath); + } + + // Registra os arquivos necessarios para o arquivo atual (imports) + // Esse dado da seguimento na busca de dados dos arquivos dos imports + if (!processedFiles.includes(importedFileContentPath)) { + if (importedFileContentPath) { + currentFileSchema.nextFilesToLoad.push(importedFileContentPath); + orderedFilesToImport.push(importedFileContentPath); + } else { + console.log( + `${filePath} -> Arquivo dependente nao encontrado: ${importPath}`, + ); + } + + processedFiles.push(importedFileContentPath); + } + }); + + // Push current schema result + contentOrderer.push(currentFileSchema); + + // Recursividade + // console.log("RECURSIVIDADE:"); + currentFileSchema.nextFilesToLoad.forEach((fileToImport) => { + processFileSchema(fileToImport); + }); +}; + +const loadFilesInfo = (entryFile) => { + // Reset state + contentOrderer = []; + processedFiles = []; + // 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(entryFile); + + // Finaliza o processo do contentOrderer deletando o campo "filesToImport" + // de todos os filhos, já que agora náo são mais necessarios + contentOrderer.map((item) => { + delete item.filesToImport; + return item; + }); + + return { + filesSchema: contentOrderer, + // orderedFilesToImport: orderedFilesToImport.reverse(), + orderedFilesToImport: contentOrderer + .map((schema) => schema.filePath) + .reverse(), + }; +}; + +module.exports = loadFilesInfo; diff --git a/lib/actions/saveFinalBundleFile.js b/lib/actions/saveFinalBundleFile.js new file mode 100644 index 0000000..6a4b3d5 --- /dev/null +++ b/lib/actions/saveFinalBundleFile.js @@ -0,0 +1,19 @@ +const path = require("path"); +const fs = require("fs"); +const { read_bos_config } = require("../config"); + +// Save final bundle file +// Note: must save inside a ./src folder. This is the only folder bos-clir-rs recognizes +const saveFinalBundleFile = (bundleContent) => { + const config = read_bos_config(); + const finalFileName = config.isIndex + ? "Index" + : config.name.replaceAll(" ", "-").toLowerCase(); + + fs.writeFileSync( + path.join(`./build/src/${finalFileName}.jsx`), + bundleContent, + ); +}; + +module.exports = saveFinalBundleFile; diff --git a/lib/actions/toolsFiles.js b/lib/actions/toolsFiles.js new file mode 100644 index 0000000..787c9dd --- /dev/null +++ b/lib/actions/toolsFiles.js @@ -0,0 +1,68 @@ +const path = require("path"); +const { process_file } = require("../parse"); +const { read_bos_config } = require("../config"); +const { for_rfile } = require("../utils"); + +const TOOLS_FOLDER = "../tools"; + +const loadHeaderFilesContent = () => { + const config = read_bos_config(); + + // Utils + let bundleFileBody = process_file( + path.join(__dirname, TOOLS_FOLDER, "utils.js"), + ); + + // Components + bundleFileBody += process_file( + path.join(__dirname, TOOLS_FOLDER, "components.jsx"), + ); + + // State manager + bundleFileBody += process_file( + path.join(__dirname, TOOLS_FOLDER, "stateManager.jsx"), + ); + + // Routes manager + bundleFileBody += process_file( + path.join(__dirname, TOOLS_FOLDER, "routes.jsx"), + ); + + // Hooks + bundleFileBody += process_file( + path.join(__dirname, TOOLS_FOLDER, "hooks.js"), + ); + + // Check if AlemSpinner should be used + if (!config?.options?.showFallbackSpinner) { + bundleFileBody = bundleFileBody.replace( + "return ;", + 'return "";', + ); + } + + // Load .CSS files + // Loop through all .css files inside the './src' and get their content + bundleFileBody += "const alemCssBody = `"; + for_rfile(path.join(".", "src"), ["css", "sass"], (file) => { + const fileBody = process_file(file); + bundleFileBody += fileBody; + }); + bundleFileBody += "`;"; + + // Theme + bundleFileBody += process_file( + path.join(__dirname, TOOLS_FOLDER, "theme.jsx"), + ); + + return bundleFileBody; +}; + +const loadIndexerContent = () => { + return process_file(path.join(__dirname, TOOLS_FOLDER, "appIndexer.jsx")); +}; + +module.exports = { + loadHeaderFilesContent, + loadIndexerContent, +}; diff --git a/lib/build.js b/lib/build.js index 122593b..447bf2f 100644 --- a/lib/build.js +++ b/lib/build.js @@ -1,29 +1,13 @@ const { generate_data_json } = require("./data.js"); -const { create_dist, for_rfile, log } = require("./utils.js"); -const { - process_file, - removeComments, - removeBlankLines, - mimify, - applyEnvironment, - parseOptions, -} = require("./parse.js"); -const { read_bos_config } = require("./config"); -const alemPkg = require("../package.json"); -const path = require("path"); -const fs = require("fs"); -const { - checkImportFeatures, - checkFeaturesMarker, - replaceMarkers, -} = require("./organize.js"); +const { create_dist, log } = require("./utils.js"); +const { compile_files } = require("./compiler.js"); const distFolder = process.env.DIST_FOLDER || "build"; // Main function to orchestrate the build script async function build() { create_dist(distFolder); - process_dist(); + compile_files(); generate_data_json(); } @@ -38,125 +22,7 @@ async function build_with_log() { log.sucess("Build complete"); } -// walk through each app folder -function process_dist() { - const config = read_bos_config(); - const finalFileName = config.isIndex - ? "Index" - : config.name.replaceAll(" ", "-").toLowerCase(); - - // built in utils - let fileBundleBody = process_file(path.join(__dirname, "tools", "utils.js")); - - // built in components - fileBundleBody += process_file( - path.join(__dirname, "tools", "components.jsx"), - ); - - // built in state manager - fileBundleBody += process_file( - path.join(__dirname, "tools", "stateManager.jsx"), - ); - - // built in route manager - fileBundleBody += process_file(path.join(__dirname, "tools", "routes.jsx")); - - // built in hooks - fileBundleBody += process_file(path.join(__dirname, "tools", "hooks.js")); - - // check if AlemSpinner should be used - if (!config?.options?.showFallbackSpinner) { - fileBundleBody = fileBundleBody.replace( - "return ;", - 'return "";', - ); - } - - // loop through all .css files inside the './src' and get their content - fileBundleBody += "const alemCssBody = `"; - for_rfile(path.join(".", "src"), ["css", "sass"], (file) => { - const fileBody = process_file(file); - fileBundleBody += fileBody; - }); - fileBundleBody += "`;"; - fileBundleBody += process_file(path.join(__dirname, "tools", "theme.jsx")); - - // loop through all files inside the './plugins' and get their content - for_rfile(path.join(".", "plugins"), ["js", "jsx", "ts", "tsx"], (file) => { - const fileBody = process_file(file); - fileBundleBody += fileBody; - }); - - // 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); - - // 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"), - ); - - // Remove comments - fileBundleBody = removeComments(fileBundleBody); - - // Remove blank lines - fileBundleBody = removeBlankLines(fileBundleBody); - - // Apply ports - works for development only - // this won't affect production because the state of enviroment is going to be - // production - fileBundleBody = applyEnvironment(fileBundleBody); - - // Apply changes depending of the config.options - fileBundleBody = parseOptions(fileBundleBody); - - // Mimify - fileBundleBody = mimify(fileBundleBody); - - // Add Alem signature + repository info if available - // TODO: abstract this in a separated file - const projectPkg = JSON.parse( - fs.readFileSync(path.join("package.json"), "utf-8"), - ); - - const projectRepositoryLink = - projectPkg?.repository && typeof projectPkg?.repository === "string" - ? projectPkg?.repository - : projectPkg.repository?.url || ""; - - fileBundleBody = ` - /** Bundle generated by Além Library v${alemPkg.version} - See more here: https://github.com/wpdas/alem */ - ${projectRepositoryLink ? `/** Project repository: ${projectRepositoryLink.replaceAll("git+", "").replaceAll(".git", "")} */` : ""} - ${fileBundleBody} - `; - - // Note: Save unified file - // Note: must save inside a ./src folder. This is the only folder bos-clir-rs recognizes - fs.writeFileSync( - path.join(`./build/src/${finalFileName}.jsx`), - fileBundleBody, - ); -} - module.exports = { build, - process_dist, build_with_log, }; diff --git a/lib/compiler.js b/lib/compiler.js new file mode 100644 index 0000000..efdc138 --- /dev/null +++ b/lib/compiler.js @@ -0,0 +1,77 @@ +const { create_dist } = require("./utils"); +const path = require("path"); +const loadFilesInfo = require("./actions/loadFilesInfo"); +const toolsFiles = require("./actions/toolsFiles"); +const loadFilesContent = require("./actions/loadFilesContent"); +const { + removeComments, + removeBlankLines, + applyEnvironment, + parseOptions, + mimify, +} = require("./parse"); +const saveFinalBundleFile = require("./actions/saveFinalBundleFile"); +const addSignatures = require("./actions/addSignatures"); + +const distFolder = process.env.DIST_FOLDER || "build"; + +function compile_files() { + create_dist(distFolder); + + const entryFile = path.join(".", "src", "index.tsx"); + + // TEST + // #1 - Load imported files content + // NOTE: Fazer isso recursivo, carregando o conteudo de todos os arquivos + // e fazer todo o processo de carga dnv + + const filesInfo = loadFilesInfo(entryFile); + + // console.log("Files Schema:"); + // console.log(filesInfo.filesSchema); + + // NOTE + /** + * Se essa ordem abaixo nao funcionar, mudar a hierarquia de carga pra carregar + * linearmente todo os items do arquivo sendo processado. + */ + // console.log("\n\n"); + // console.log("Ordered Files to Import:"); + // console.log(filesInfo.orderedFilesToImport); + + // Tools -> Header contents + let bundleContent = toolsFiles.loadHeaderFilesContent(); + + // Load App files content + bundleContent += loadFilesContent(filesInfo.orderedFilesToImport); + + // Tools -> Indexer + bundleContent += toolsFiles.loadIndexerContent(); + + // Remove the remaining comments + bundleContent = removeComments(bundleContent); + + // Remove blank lines + bundleContent = removeBlankLines(bundleContent); + + // Apply ports - works for development only + // this won't affect production because the state of enviroment is going to be + // production + bundleContent = applyEnvironment(bundleContent); + + // Apply changes depending of the config.options + bundleContent = parseOptions(bundleContent); + + // Mimify + bundleContent = mimify(bundleContent); + + // Add sinatures + bundleContent = addSignatures(bundleContent); + + // Save final bundle file + saveFinalBundleFile(bundleContent); +} + +module.exports = { + compile_files, +}; diff --git a/lib/dev.js b/lib/dev.js index 92cbf3f..249706c 100644 --- a/lib/dev.js +++ b/lib/dev.js @@ -21,6 +21,7 @@ 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`); + await build().catch((err) => { loading.error(); log.error(err); diff --git a/lib/helpers.js b/lib/helpers.js new file mode 100644 index 0000000..2034362 --- /dev/null +++ b/lib/helpers.js @@ -0,0 +1,95 @@ +const fs = require("fs"); +const regexp = require("./regexp"); + +// Get all elements imports. ex: +/** + * [ + 'AppBackground', + 'AppContainer', + 'Sidebar', + 'ContentView', + 'Footer', + 'Modals', + 'styled', + 'Row' + ] + */ +const getFileImportsElements = (fileContent) => { + let fileImports = []; + fileContent.match(/(?<=import)(.*?)(?=from)/gm).forEach((value) => { + value.split(",").forEach((subValue) => { + fileImports.push( + subValue.replaceAll(regexp.SPECIAL_CHARACTERS_AND_SPACES, ""), + ); + }); + }); + return fileImports; +}; + +/** + * Get import statements only + * ex: + * import Sidebar from "./components/Sidebar"; + * import ContentView from "./components/ContentView"; + * @param {*} fileContent + * @returns + */ +const getImportStatements = (fileContent) => + fileContent.match(regexp.IMPORT_STATEMENT); + +/** + * Get Import's path + * ex: + * give: import Sidebar from "./components/Sidebar"; + * return: ./components/Sidebar + * @param {*} fileContent + * @returns + */ +const getImportsPath = (fileContent) => { + let result = []; + const importStatements = fileContent.match(regexp.IMPORT_STATEMENT_2); + + if (importStatements) { + importStatements.forEach((value) => + value + .match(regexp.BETWEEN_QUOTES) + .forEach((subValue) => result.push(subValue)), + ); + } + + return result; +}; + +/** + * Given a file path, try to return the path + file type (ts, tsx, js, jsx). + * It supports these types at the moment: ts, tsx, js, jsx + * @param {*} filePath + * @returns + */ +const getFilePathWithType = (filePath) => { + if (fs.existsSync(`${filePath}.ts`)) { + return `${filePath}.ts`; + } else if (fs.existsSync(`${filePath}.tsx`)) { + return `${filePath}.tsx`; + } else if (fs.existsSync(`${filePath}.js`)) { + return `${filePath}.js`; + } else if (fs.existsSync(`${filePath}.jsx`)) { + return `${filePath}.jsx`; + } else if (fs.existsSync(`${filePath}/index.ts`)) { + return `${filePath}/index.ts`; + } else if (fs.existsSync(`${filePath}/index.tsx`)) { + return `${filePath}/index.tsx`; + } else if (fs.existsSync(`${filePath}/index.js`)) { + return `${filePath}/index.js`; + } else if (fs.existsSync(`${filePath}/index.jsx`)) { + return `${filePath}/index.jsx`; + } + return null; +}; + +module.exports = { + getFileImportsElements, + getImportStatements, + getImportsPath, + getFilePathWithType, +}; diff --git a/lib/organize.js b/lib/organize.js deleted file mode 100644 index 0db4832..0000000 --- a/lib/organize.js +++ /dev/null @@ -1,175 +0,0 @@ -/** - * 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 - // TODO: refactor using regexp - 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; -} - -let 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) { - 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, ""); - - // Reset the markers organizer list - listInstancesContent = []; - - return bundleBody; -} - -module.exports = { - checkImportFeatures, - checkFeaturesMarker, - replaceMarkers, -}; diff --git a/lib/parse.js b/lib/parse.js index 31d3350..84bf73b 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -1,5 +1,4 @@ const fs = require("fs"); -// const path = require("path"); const sucrase = require("sucrase"); const { read_bos_config } = require("./config"); @@ -15,8 +14,6 @@ const sucraseOptions = { function process_file(filePath) { let fileContent = fs.readFileSync(filePath, "utf8"); - if (shouldSkipFile(fileContent)) return; - if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) { fileContent = transpileTypescript(fileContent); } @@ -29,41 +26,6 @@ function process_file(filePath) { return fileContent; } -const shouldSkipFile = (c) => /\/\*__@skip__\*\//.test(c); - -// process comment commands and replace content in files -// const processCommentCommands = (fileContent, aliases, account) => { -// // Process the aliases -// if (aliases) { -// for (let alias in aliases) { -// let replacePattern = new RegExp(`/\\*__@replace:${alias}__\\*/`, "g"); -// fileContent = fileContent.replace(replacePattern, aliases[alias]); -// } -// } - -// // Replace the account -// if (account) { -// let accountPattern = /\/\*__@account__\*\//g; -// fileContent = fileContent.replace(accountPattern, account); -// } - -// return fileContent; -// }; - -// import modules from /modules folder -// const importModules = (fileContent) => { -// let importPattern = /\/\*__@import:(.+?)__\*\//g; -// let match; - -// while ((match = importPattern.exec(fileContent)) !== null) { -// let modulePath = path.join("./modules", `${match[1]}.js`); -// let moduleContent = fs.readFileSync(modulePath, "utf8"); -// fileContent = fileContent.replace(match[0], moduleContent); -// } - -// return fileContent; -// }; - // transpile typescript files to valid BOS Lang const transpileTypescript = (fileContent) => { const transpiledCode = sucrase.transform(fileContent, sucraseOptions).code; @@ -158,12 +120,8 @@ const injectHTML = (html, injections) => { }; module.exports = { - // processCommentCommands, process_file, - // importModules, - shouldSkipFile, ignoreFiles, - // noStringifyJsonFiles, removeComments, injectHTML, removeExports, diff --git a/lib/regexp.js b/lib/regexp.js new file mode 100644 index 0000000..79bcdb0 --- /dev/null +++ b/lib/regexp.js @@ -0,0 +1,28 @@ +// # TODAS AS CARACTERES ESPECIAIS +const SPECIAL_CHARACTERS = /[^0-9A-záéíóúàèìòùâêîôûãõç\s]/gm; +// # TODAS AS CARACTERES ESPECIAIS E ESPAÇOS +const SPECIAL_CHARACTERS_AND_SPACES = /[^0-9A-záéíóúàèìòùâêîôûãõç\s]|\s/gm; +// # TUDO ENTRE import e from +// ex: { AppBackground, AppContainer } +const GET_ALL_BETWEEN_IMPORT_AND_FROM = /(?<=import)(.*?)(?=from)/gm; +// # ALL SPACES +const SPACES = /\s/g; +// # LINE BREAKS +const LINE_BREAKS = /\r?\n|\r/g; +// # IMPORT STATEMENT. ex: import { AppBackground, AppContainer } from "./styles"; +const IMPORT_STATEMENT = /^(import)(?:.*?(as))?(?:.*?(as))?(?:.*?(from))*.*$/gm; +const IMPORT_STATEMENT_2 = + /^[ \t]*(import)\s+(?:\{[^}]*\}|\w+)\s+(from\s+)?["']([^"']+)["'];?$/gm; // USAR ESSE! +// # BETWEEN quotation marks +const BETWEEN_QUOTES = /(?<=")(.*?)(?=")/gm; + +module.exports = { + SPECIAL_CHARACTERS, + SPECIAL_CHARACTERS_AND_SPACES, + GET_ALL_BETWEEN_IMPORT_AND_FROM, + SPACES, + LINE_BREAKS, + IMPORT_STATEMENT, + IMPORT_STATEMENT_2, + BETWEEN_QUOTES, +}; diff --git a/lib/tools/hooks.js b/lib/tools/hooks.js index 68da811..55ca262 100644 --- a/lib/tools/hooks.js +++ b/lib/tools/hooks.js @@ -11,5 +11,6 @@ const useLocation = () => { return { pathname: activeRoute, routes, + isRoutesReady: routes && routes.length > 0, }; }; diff --git a/package.json b/package.json index fa2db78..5fbcb81 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 while using concepts that are based on ReactJS.", - "version": "0.0.1-alpha.16", + "version": "0.0.1-alpha.17", "main": "main.js", "types": "index.d.ts", "author": "Wenderson Pires - wendersonpires.near", diff --git a/roadmap.md b/roadmap.md index aec10e8..55ba2bd 100644 --- a/roadmap.md +++ b/roadmap.md @@ -1,5 +1,7 @@ - Implement support for Testnet. -- Implement `loadExternalStyles` API to load external css files. - ✔ +- Implement `loadExternalStyles` API to load external fonts and css files. - ✔ - E2E Tests - Add parameter `parameterName` for `Routes` component. This is going to allow changing the default route param name ("path") that's used to control and watch all routes. - ✔ - Implement feature to the compiler that changes the consts/lets/vars names to avoid conflicts. +- Add support to tsconfig.json `baseUrl` and `paths`. +- Support to use same const names in defferent files. diff --git a/router.d.ts b/router.d.ts index 65dbdce..d4b10a5 100644 --- a/router.d.ts +++ b/router.d.ts @@ -89,4 +89,8 @@ export declare const useLocation: () => { * Routes available */ routes: string[]; + /** + * Is routes ready? + */ + isRoutesReady: boolean; };