Skip to content

Commit

Permalink
added transformWidgetInChildProps: useful to transform widgets within…
Browse files Browse the repository at this point in the history
… other components props
  • Loading branch information
wpdas committed May 3, 2024
1 parent 748cbda commit 23e9240
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 99 deletions.
1 change: 1 addition & 0 deletions lib/actions/handleNames.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ const getExportsOrganizer = (fileSchemas) => {
// 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),
Expand Down
5 changes: 3 additions & 2 deletions lib/actions/loadFilesInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ const prepareAlemDependencies = require("./prepareAlemDependencies");
const replaceStatefulReferencesToJSX = (initialFileSchema) => {
let content = initialFileSchema.content;
initialFileSchema.toImport.forEach((filePath) => {
let importItemContent = fs.readFileSync(filePath, "utf8");
// let importItemContent = fs.readFileSync(filePath, "utf8");
let importItemContent = filesContentCache.getFileContent(filePath);
const importComponentName = helpers.getComponentName(importItemContent);
const isImportStatefulComponent = hasWidgetPropsCheck(
removeImports(importItemContent),
Expand Down Expand Up @@ -250,7 +251,7 @@ const loadFilesInfo = (entryFile) => {
const initialFileSchemas = _.cloneDeep(contentOrderer);

// Handle names -> remove const duplicates
contentOrderer = handleNames(contentOrderer);
contentOrderer = handleNames(contentOrderer); // INFO: parte que esta consumindo bastante recurso

return {
hasError,
Expand Down
224 changes: 129 additions & 95 deletions lib/actions/transformSchemaToWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,48 @@ const processSchema = (fileSchema) => {
return fileSchema;
};

/**
* Processa os Widgets dentro das propriedades, como por exemplo a propriedade
* <Foo renderItem={project => <A_192 projectId={project.registrant_id} />} />
* onde o "A_192" é um Widget
*
* ATENCAO: Isso trata especificamente os casos em que um widget (stateful component) é encontrado
* nas propriedades
*
* @param {*} childProps
* @param {*} fileSchemas
* @returns
*/
const transformWidgetInChildProps = (childProps, fileSchemas) => {
const childPropEntries = Object.entries(childProps);

childPropEntries.forEach((entry) => {
// Skip children prop
if (entry[0] === "children") {
return childProps;
}

const entryKey = entry[0];
let entryValue = entry[1];

// Ignora se nao tiver conteúdo JSX
if (!entryValue.includes("/>")) {
return;
}

const foundJSXs = extractJSX(entryValue);
if (foundJSXs.length > 0) {
foundJSXs.forEach((jsx) => {
const widgetContent = processChildrenWidget(`<>${jsx}</>`, fileSchemas);
entryValue = entryValue.replace(jsx, widgetContent);
});
}
childProps[entryKey] = entryValue;
});

return childProps;
};

/**
* Faz o procedimento de trocar componentes nome de componentes por <Widget code={...} />
*
Expand Down Expand Up @@ -367,18 +409,15 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => {
Object.keys(fileSchema.componentImportItems).forEach((importItem) => {
// Se for um arquivo disponível, segue (null quer dizer que é um import de alguma lib nao local no src)
const importItemFilePath = fileSchema.componentImportItems[importItem];

// Nao deve processar (copiar e colar) o conteúdo do arquivo mais de uma vez
if (importItemFilePath && !pastedFiles.includes(importItemFilePath)) {
// Adiciona na lista de items ja processados
pastedFiles.push(importItemFilePath);

// INFO: Verifica se o caminho do arquivo a ser processado não é "null"
const importItemFileSource = fileSchema.componentImportItems[importItem]; // src/path/to/file.tsx | null

// Le o nome do Widget dependente (usando o fileSchema dele)
let importItemWidget = fileSchemas.find(
(importFileSchema) =>
importFileSchema.filePath === importItemFileSource,
(importFileSchema) => importFileSchema.filePath === importItemFilePath,
);

// MODULOS - INICIO
Expand All @@ -403,108 +442,103 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => {
// const rootHTML = parse(fileBundle, {});

// Files without source are the ones that not live in the src directory
// NOTE: Aqui que a magica acontece!!!!

const importItemWidgetComponentName =
importItemWidget.widgetName ||
getComponentName(importItemWidget.finalFileBundle);

if (importItemWidgetComponentName && !importItemWidget.isStateless) {
// Processa todos os componentes filhos
// Cada elemento do mesmo tipo é um filho diferente que foi adicionado ao elemento pai
// const importItemElements =
// fileSchema.htmlElementsProps[importItemWidgetComponentName] || [];

// Usa o rootHTML (conteúdo html do componente) para pegar a lista de Componentes do tipo desejado. ex: Title
// const componentElements = rootHTML.getElementsByTagName(
// importItemWidgetComponentName,
// );
// INFO: Esses comentarios acima creio que podem ser apagados, verificar
// se ainda estou usando o modulo html parse

const jsxOnly = extractJSX(fileSchema.content);

const fixedJsxOnly =
jsxOnly.length > 1
? `<>${jsxOnly.join("\n")}</>`
: jsxOnly.join("\n");

const componentElements = extractJSXElements(
fixedJsxOnly,
importItemWidgetComponentName,
);

// Seta qualquer erro se tiver
if (!processError && componentElements.error) {
processError = `${fileSchema.filePath}: ${componentElements.error}`;
}
if (processError) return;

// // INFO: Verifica se o caminho do arquivo a ser processado não é "null"
// const importItemFileSource =
// fileSchema.componentImportItems[importItem]; // src/path/to/file.tsx | null
// Transfor cada componente em Widget com suas propriedades
componentElements.elements.forEach((div, divIndex) => {
const htmlElementString = componentElements.elements[divIndex]
.toString()
.replaceAll(LINE_BREAKS, "")
.replaceAll(MORE_THAN_ONE_SPACE, " ");

// Se existir o conteúdo localmente... segue...
if (importItemFileSource) {
// NOTE: Aqui que a magica acontece!!!!
const extractPropsResult = extractPropsFromJSX(htmlElementString);
let childProps = extractPropsResult.keyValueProps;

const importItemWidgetComponentName =
importItemWidget.widgetName ||
getComponentName(importItemWidget.finalFileBundle);
const childSpreads = extractPropsResult.spreads;

if (importItemWidgetComponentName && !importItemWidget.isStateless) {
// Processa todos os componentes filhos
// Cada elemento do mesmo tipo é um filho diferente que foi adicionado ao elemento pai
// const importItemElements =
// fileSchema.htmlElementsProps[importItemWidgetComponentName] || [];
// get the children (pega o filho(s) do elemento principal)
let childChildren = extractJSXChildren(htmlElementString);

// Usa o rootHTML (conteúdo html do componente) para pegar a lista de Componentes do tipo desejado. ex: Title
// const componentElements = rootHTML.getElementsByTagName(
// importItemWidgetComponentName,
// );
// INFO: Esses comentarios acima creio que podem ser apagados, verificar
// se ainda estou usando o modulo html parse
if (childChildren) {
childChildren = processChildrenWidget(childChildren, fileSchemas);
childProps = { ...childProps, children: childChildren };
}

// Processa os Widgets dentro das propriedades, como por exemplo a propriedade
// <Foo renderItem={project => <A_192 projectId={project.registrant_id} />} />
// onde o "A_192" é um Widget
childProps = transformWidgetInChildProps(childProps, fileSchemas);

const jsxOnly = extractJSX(fileSchema.content);
let importItemPropsStringSequence =
convertObjectToArray(childProps).join(",");

// Adiciona os spreads junto com as propriedades do elemento JSX. Ex:
// <Widget code="..." {...{foo: 2, bar: "oi", ...mySpread1, ...mySpread2}}
// no caso os spreads sao: ...mySpread1 e ...mySpread2
if (childSpreads.length > 0) {
importItemPropsStringSequence += `${importItemPropsStringSequence.length > 0 ? "," : ""} ${childSpreads.join(",")}`;
}

const fixedJsxOnly =
jsxOnly.length > 1
? `<>${jsxOnly.join("\n")}</>`
: jsxOnly.join("\n");
// Babel segue os padroes JS, por isso:
// 1 - Adiciona uma uma função no topo
// 2 - Fecha a função no final
fileBundle = `const TempMethod = () => {\n${fileBundle}\n}`;
// NOTE: nao adicionando a ultima linha, mas estou removendo a ultima linha
// Caso quebre, ver isso. [Provavelmente o escape acima esta adicionando o } no final]

const componentElements = extractJSXElements(
fixedJsxOnly,
// Transform components generated by .jsx / .tsx into <Widget code={code} .../>
fileBundle = replaceJSXElement(
fileBundle,
importItemWidgetComponentName,
0,
`<Widget loading=" " code={props.alem.componentsCode.${importItemWidgetComponentName}} props={{ ...({${importItemPropsStringSequence ? `${importItemPropsStringSequence},` : ""} ...props}) }} />`,
);

// Seta qualquer erro se tiver
if (!processError && componentElements.error) {
processError = `${fileSchema.filePath}: ${componentElements.error}`;
}
if (processError) return;

// Transfor cada componente em Widget com suas propriedades
componentElements.elements.forEach((div, divIndex) => {
const htmlElementString = componentElements.elements[divIndex]
.toString()
.replaceAll(LINE_BREAKS, "")
.replaceAll(MORE_THAN_ONE_SPACE, " ");

const extractPropsResult = extractPropsFromJSX(htmlElementString);
let childProps = extractPropsResult.keyValueProps;

const childSpreads = extractPropsResult.spreads;

// get the children
let childChildren = extractJSXChildren(htmlElementString);
if (childChildren) {
childChildren = processChildrenWidget(
childChildren,
fileSchemas,
);
childProps = { ...childProps, children: childChildren };
}

let importItemPropsStringSequence =
convertObjectToArray(childProps).join(",");

// Adiciona os spreads junto com as propriedades do elemento JSX. Ex:
// <Widget code="..." {...{foo: 2, bar: "oi", ...mySpread1, ...mySpread2}}
// no caso os spreads sao: ...mySpread1 e ...mySpread2
if (childSpreads.length > 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
fileBundle = `const TempMethod = () => {\n${fileBundle}\n}`;
// NOTE: nao adicionando a ultima linha, mas estou removendo a ultima linha
// Caso quebre, ver isso. [Provavelmente o escape acima esta adicionando o } no final]

// Transform components generated by .jsx / .tsx into <Widget code={code} .../>
fileBundle = replaceJSXElement(
fileBundle,
importItemWidgetComponentName,
0,
`<Widget loading=" " code={props.alem.componentsCode.${importItemWidgetComponentName}} props={{ ...({${importItemPropsStringSequence ? `${importItemPropsStringSequence},` : ""} ...props}) }} />`,
);

// Remove funcao no topo e ultima linha fechando a funcao
fileBundle = fileBundle.replace("const TempMethod = () => {", "");
fileBundle = removeLastLineFromText(fileBundle);
});
}

// Altera o jsContent com os Widgets
fileSchema.jsContent = fileBundle;
// Altera o finalBundle que é usado posteriormente
fileSchema.finalFileBundle = fileBundle;
// Remove funcao no topo e ultima linha fechando a funcao
fileBundle = fileBundle.replace("const TempMethod = () => {", "");
fileBundle = removeLastLineFromText(fileBundle);
});
}

// Altera o jsContent com os Widgets
fileSchema.jsContent = fileBundle;
// Altera o finalBundle que é usado posteriormente
fileSchema.finalFileBundle = fileBundle;
}
}
});
Expand Down
3 changes: 2 additions & 1 deletion lib/compiler.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { create_dist, log } = require("./utils");
const { create_dist, log, reset_name_counter } = require("./utils");
const path = require("path");
const fs = require("fs");
const loadFilesInfo = require("./actions/loadFilesInfo");
Expand Down Expand Up @@ -126,6 +126,7 @@ function run_final_process(filesInfo, opts) {
* @param {*} opts Opcoes da CLI
*/
function compile_files(opts) {
reset_name_counter();
create_dist(distFolder);

let entryFile = path.join(".", "src", "index.tsx");
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
"version": "1.0.1",
"main": "main.js",
"types": "index.d.ts",
"author": "Wenderson Pires - wendersonpires.near",
Expand Down

0 comments on commit 23e9240

Please sign in to comment.