Skip to content

Commit

Permalink
Merge pull request #25 from wpdas/feat/eject-stateful-components
Browse files Browse the repository at this point in the history
Feat: Eject stateful components
  • Loading branch information
wpdas authored Jun 3, 2024
2 parents 19f6aa2 + 06f4c03 commit d5f2dd3
Show file tree
Hide file tree
Showing 21 changed files with 1,020 additions and 70 deletions.
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18.0.0
18.17.0
2 changes: 2 additions & 0 deletions gateway/config/flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const envConfig = document.getElementById("env-config").textContent;
const config = JSON.parse(envConfig);

export const flags = {
mainWidgetSrc: config.mainWidgetSrc,
mainWidgetLink: config.mainWidgetLink,
network: process.env.NETWORK || config.network || "mainnet",
bosLoaderUrl:
process.env.BOS_LOADER_URL ||
Expand Down
6 changes: 6 additions & 0 deletions gateway/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ function Home() {
const { components: redirectMap } = useRedirectMap();
const widgets = {};

// Force going to the main widget src (indexer)
if (location.pathname === "/" && flags.mainWidgetSrc) {
navigate(flags.mainWidgetSrc);
return "";
}

Object.keys(redirectMap).forEach((key) => {
const parts = key.split("/widget/");
if (!widgets[parts[0]]) {
Expand Down
3 changes: 2 additions & 1 deletion gateway/src/navigation/NavigationWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";
import styled from "styled-components";
import { Link } from "react-router-dom";
import logo from "../assets/near-script-logo-white.png";
import { flags } from "../../config/flags";

const StyledNavigation = styled.div`
position: sticky;
Expand Down Expand Up @@ -59,7 +60,7 @@ export function NavigationWrapper(props) {
<StyledNavigation>
<div className="container">
<Link
to="/"
to={flags.mainWidgetLink || "/"}
className="text-white text-2xl font-black"
style={{
display: "flex",
Expand Down
31 changes: 31 additions & 0 deletions lib/actions/asStatefulCheck.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const { removeBlankLines } = require("../parse");

/**
* Checa se a assinatura "as stateful" foi encontrado no topo do arquivo.
* @param {*} content
* @returns
*/
const asStatefulCheck = (content) => {
// NOTE: Checa se tem "as stateful", se tiver, deve ser tratado como um Widget/Stateful
const hasAsStatefulType =
content.includes('"as stateful"') || content.includes("'as stateful'");

if (hasAsStatefulType) {
content = content.replace('"as stateful";', "");
content = content.replace("'as stateful';", "");
content = content.replace('"as stateful"', "");
content = content.replace("'as stateful'", "");

return {
updatedContent: removeBlankLines(content),
asStatefulSignalFound: true,
};
}

return {
updatedContent: content,
asStatefulSignalFound: false,
};
};

module.exports = asStatefulCheck;
22 changes: 22 additions & 0 deletions lib/actions/getProjectName.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const { read_alem_config } = require("../config");

/**
* Get the project name based on configuration
* @returns
*/
const getProjectName = (skipCheckers = false) => {
const appConfig = read_alem_config();
let projectName = appConfig.name.replaceAll(" ", "-").toLowerCase();

// Se ignorar a checagem do nome final do projeto
if (skipCheckers) {
return projectName;
}

projectName = appConfig.isIndex ? "Index" : projectName;
return appConfig.options?.createLoaderWidget
? `${projectName}Loader`
: projectName;
};

module.exports = getProjectName;
30 changes: 26 additions & 4 deletions lib/actions/loadFilesContent.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
const parseAlemFeatures = require("../config/parseAlemFeatures");
const { scapeBacktick } = require("../helpers");
const getProjectName = require("./getProjectName");
const transformSchemaToWidget = require("./transformSchemaToWidget");

/**
* Load the "componentCodes" from all Widgets based on file schemas
* @param {{filePath: string, toImport: string[], content: string}[]} fileSchemas
* the process starts. This is util to inject previous schema files like Além importable items.
*/
const loadComponentCodesObjectByFileSchemas = (fileSchemas) => {
const loadComponentCodesObjectByFileSchemas = (fileSchemas, network) => {
let componentsCodes = "";

/**
Expand All @@ -19,21 +20,40 @@ const loadComponentCodesObjectByFileSchemas = (fileSchemas) => {
fileSchemas = fileSchemas.reverse();

// Get Normal js files & Widget files (components transformed to BOS Widgets)
const completeFileSchemas = transformSchemaToWidget(fileSchemas);
const completeFileSchemas = transformSchemaToWidget(fileSchemas, network);

// Processa também os módulos
let modulesCodes = "";

// Ejected Files Codes
let ejectedFiles = [];

completeFileSchemas.fileSchemas.forEach((fileSchema) => {
// Prepare Widgets (stateful components)
if (fileSchema.widgetName && !fileSchema.isStateless) {
if (
fileSchema.widgetName &&
!fileSchema.isStateless &&
!fileSchema.toBeEjected
) {
componentsCodes += `
${fileSchema.widgetName}: \`${scapeBacktick(fileSchema.finalFileBundle)}\`,
`;
}

// Ejectables - Arquivos a serem criado fora do indexador principal
if (fileSchema.toBeEjected) {
// O nome do projeto deve vir na frente para evitar conflitos com outros
// aplicativos publicados na mesma conta
const newWidgetName = `${getProjectName(true)}.${fileSchema.widgetName}`;

ejectedFiles.push({
name: newWidgetName,
content: fileSchema.finalFileBundle,
});
}

// Prepare modules
if (fileSchema.isModule) {
if (fileSchema.isModule && !fileSchema.toBeEjected) {
// let modulesValues = "{";
// const valuesEntries = Object.entries(fileSchema.moduleProps.values);
// valuesEntries.forEach((entrie) => {
Expand Down Expand Up @@ -62,6 +82,8 @@ const loadComponentCodesObjectByFileSchemas = (fileSchemas) => {
componentsCodes,
/** Código final de todos os módulos. Eles serão inseridos no escopo global e disponível para todos os subcomponents */
modulesCodes,
/** Lista de objetos (de arquivos ejetados e serem salvos separadamente) contento {name: nome da pagina/arquivo/widget, content: conteúdo do arquivo processado} */
ejectedFiles,
/** Código final do componente App de entrada do projet apenas. (src/index.tsx | .jsx) */
appComponentFinalBundle,
/** Esquema final de todos os arquivos processados */
Expand Down
67 changes: 53 additions & 14 deletions lib/actions/loadFilesInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const filesContentCache = require("../config/filesContentCache");
const replaceRegexWithReferences = require("../parsers/regex-parser/convertRegexToStringLiteral");
const regexObjects = require("../parsers/regex-parser/regexObjects");
const prepareAlemDependencies = require("./prepareAlemDependencies");
const processImportsToBase64 = require("../parsers/processImportsToBase64");
// const extractTopLevelDeclarations = require("../parsers/extractTopLevelDeclarations");
/**
* Transform statefull components references to JSX (this applies for stateful and stateless components)
Expand Down Expand Up @@ -150,6 +151,7 @@ const processFileSchema = (filePath, processOnlyThisFile) => {
content: fileContent,
isModule: false,
moduleProps: {},
base64Images: [],
};

fileImportsPath.forEach((importPath) => {
Expand Down Expand Up @@ -198,21 +200,58 @@ const processFileSchema = (filePath, processOnlyThisFile) => {
}
});

// Transform statefull components references to JSX
currentFileSchema = replaceStatefulReferencesToJSX(currentFileSchema);

// Push current schema result
contentOrderer.push(currentFileSchema);
const finalize = () => {
// Transform statefull components references to JSX
currentFileSchema = replaceStatefulReferencesToJSX(currentFileSchema);

// Push current schema result
contentOrderer.push(currentFileSchema);

if (!processOnlyThisFile) {
// 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);
// }
});
}
// Note: Chamando diretamente pois o processo de transformar imagem para base64
// ainda nao esta completo
finalize();

/**
* TODO: Terminar a implantação. No momento, está usando async e como o metodo "processFileSchema"
* é sync, ele continua antes de acabar o processo abaixo async. Deve-se transformar o processFilesSchema
* em async e espelhar isso em todos os recursos que o usa.
*
* "processImportsToBase64" abaixo retorna uma lista de
* {imageKey: "nome do import da imagem", imageBase64Content: "conteúdo base64 da imagem"}
*
* Esses dados devem ser usados posteriormente:
* 1 - Inserir um const no topo do arquivo (para stateful) ou
* 1.1 - Inserir um const na primeira linha após o início da função (para stateless)
* 2 - esse const inserido tem o nome da "imageKey" e seu valor é o "imageBase64Content"
*
* Configuraçao (alem.config.json):
* options: {
* base64Images: {
* enabled: false,
* quality: 80, // aqui é fator de no máximo 100
* }
* }
*/

// processImportsToBase64(fileContent, filePath, 80)
// .then((data) => {
// if (data.length > 0) {
// currentFileSchema.base64Images = data;
// }
// finalize();
// })
// .catch(finalize);
};

/**
Expand Down
36 changes: 29 additions & 7 deletions lib/actions/processChildrenWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const extractJSXChildren = require("../parsers/extractJSXChildren");
const extractPropsFromJSX = require("../parsers/extractPropsFromJSX");
const extractTopLevelJSXElements = require("../parsers/extractTopLevelJSXElements");
const replaceJSXElement = require("../parsers/replaceJSXElement");
const getProjectName = require("./getProjectName");

/**
* Usado para remover o endChar do texto se o endChar for a última caractere no texto
Expand All @@ -33,7 +34,7 @@ function removeEndCharacter(text, endChar) {
*
* @param {string} htmlContent
*/
const processChildrenWidget = (htmlContent, fileSchemas) => {
const processChildrenWidget = (htmlContent, fileSchemas, account) => {
const componentElements = extractTopLevelJSXElements(htmlContent);
const finalElements = [];

Expand Down Expand Up @@ -71,12 +72,33 @@ const processChildrenWidget = (htmlContent, fileSchemas) => {

htmlElement = `const TempMethod = () => { return ${htmlElement} \n}`;

htmlElement = replaceJSXElement(
htmlElement,
componentElementName,
0,
`<Widget loading=" " code={props.alem.componentsCode.${componentElementName}} props={{ ...({${importItemPropsStringSequence ? `${importItemPropsStringSequence},` : ""} ...props}) }} />`,
);
if (componentSchema.toBeEjected) {
// O nome do projeto deve vir na frente para evitar conflitos com outros
// aplicativos publicados na mesma conta
const newWidgetName = `${getProjectName(true)}.${componentElementName}`;
const src = `"${account}/widget/${newWidgetName}"`;

htmlElement = replaceJSXElement(
htmlElement,
componentElementName,
0,
`<Widget loading=" " src={${src}} props={{ ...({${importItemPropsStringSequence ? `${importItemPropsStringSequence},` : ""} ...props}) }} />`,
);
} else {
htmlElement = replaceJSXElement(
htmlElement,
componentElementName,
0,
`<Widget loading=" " code={props.alem.componentsCode.${componentElementName}} props={{ ...({${importItemPropsStringSequence ? `${importItemPropsStringSequence},` : ""} ...props}) }} />`,
);
}

// htmlElement = replaceJSXElement(
// htmlElement,
// componentElementName,
// 0,
// `<Widget loading=" " code={props.alem.componentsCode.${componentElementName}} props={{ ...({${importItemPropsStringSequence ? `${importItemPropsStringSequence},` : ""} ...props}) }} />`,
// );

// Remove method and last line
htmlElement = htmlElement.replace(
Expand Down
4 changes: 2 additions & 2 deletions lib/actions/saveFinalBundleFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ const getMainWidgetName = require("./getMainWidgetName");

// Save final bundle file
// Note: must save inside a ./src folder. This is the only folder bos-clir-rs recognizes
const saveFinalBundleFile = (bundleContent) => {
const finalFileName = getMainWidgetName();
const saveFinalBundleFile = (bundleContent, fileName) => {
const finalFileName = fileName || getMainWidgetName();

fs.writeFileSync(
path.join(`./build/src/${finalFileName}.jsx`),
Expand Down
Loading

0 comments on commit d5f2dd3

Please sign in to comment.