Skip to content

Commit 23e9240

Browse files
committed
added transformWidgetInChildProps: useful to transform widgets within other components props
1 parent 748cbda commit 23e9240

File tree

5 files changed

+136
-99
lines changed

5 files changed

+136
-99
lines changed

lib/actions/handleNames.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ const getExportsOrganizer = (fileSchemas) => {
141141
// Verifica se já tem os nomes de elementos no conteúdo anterior
142142
// exports = [...exports, ...getExportConsts(schema.content)];
143143

144+
// TODO: melhorar isso usando Babel
144145
exports = [
145146
...getExportConsts(schema.content),
146147
...getExportLets(schema.content),

lib/actions/loadFilesInfo.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ const prepareAlemDependencies = require("./prepareAlemDependencies");
2525
const replaceStatefulReferencesToJSX = (initialFileSchema) => {
2626
let content = initialFileSchema.content;
2727
initialFileSchema.toImport.forEach((filePath) => {
28-
let importItemContent = fs.readFileSync(filePath, "utf8");
28+
// let importItemContent = fs.readFileSync(filePath, "utf8");
29+
let importItemContent = filesContentCache.getFileContent(filePath);
2930
const importComponentName = helpers.getComponentName(importItemContent);
3031
const isImportStatefulComponent = hasWidgetPropsCheck(
3132
removeImports(importItemContent),
@@ -250,7 +251,7 @@ const loadFilesInfo = (entryFile) => {
250251
const initialFileSchemas = _.cloneDeep(contentOrderer);
251252

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

255256
return {
256257
hasError,

lib/actions/transformSchemaToWidget.js

Lines changed: 129 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,48 @@ const processSchema = (fileSchema) => {
330330
return fileSchema;
331331
};
332332

333+
/**
334+
* Processa os Widgets dentro das propriedades, como por exemplo a propriedade
335+
* <Foo renderItem={project => <A_192 projectId={project.registrant_id} />} />
336+
* onde o "A_192" é um Widget
337+
*
338+
* ATENCAO: Isso trata especificamente os casos em que um widget (stateful component) é encontrado
339+
* nas propriedades
340+
*
341+
* @param {*} childProps
342+
* @param {*} fileSchemas
343+
* @returns
344+
*/
345+
const transformWidgetInChildProps = (childProps, fileSchemas) => {
346+
const childPropEntries = Object.entries(childProps);
347+
348+
childPropEntries.forEach((entry) => {
349+
// Skip children prop
350+
if (entry[0] === "children") {
351+
return childProps;
352+
}
353+
354+
const entryKey = entry[0];
355+
let entryValue = entry[1];
356+
357+
// Ignora se nao tiver conteúdo JSX
358+
if (!entryValue.includes("/>")) {
359+
return;
360+
}
361+
362+
const foundJSXs = extractJSX(entryValue);
363+
if (foundJSXs.length > 0) {
364+
foundJSXs.forEach((jsx) => {
365+
const widgetContent = processChildrenWidget(`<>${jsx}</>`, fileSchemas);
366+
entryValue = entryValue.replace(jsx, widgetContent);
367+
});
368+
}
369+
childProps[entryKey] = entryValue;
370+
});
371+
372+
return childProps;
373+
};
374+
333375
/**
334376
* Faz o procedimento de trocar componentes nome de componentes por <Widget code={...} />
335377
*
@@ -367,18 +409,15 @@ const swapComponentsForStatelessFiles = (fileSchemas, fileSchema) => {
367409
Object.keys(fileSchema.componentImportItems).forEach((importItem) => {
368410
// Se for um arquivo disponível, segue (null quer dizer que é um import de alguma lib nao local no src)
369411
const importItemFilePath = fileSchema.componentImportItems[importItem];
412+
370413
// Nao deve processar (copiar e colar) o conteúdo do arquivo mais de uma vez
371414
if (importItemFilePath && !pastedFiles.includes(importItemFilePath)) {
372415
// Adiciona na lista de items ja processados
373416
pastedFiles.push(importItemFilePath);
374417

375-
// INFO: Verifica se o caminho do arquivo a ser processado não é "null"
376-
const importItemFileSource = fileSchema.componentImportItems[importItem]; // src/path/to/file.tsx | null
377-
378418
// Le o nome do Widget dependente (usando o fileSchema dele)
379419
let importItemWidget = fileSchemas.find(
380-
(importFileSchema) =>
381-
importFileSchema.filePath === importItemFileSource,
420+
(importFileSchema) => importFileSchema.filePath === importItemFilePath,
382421
);
383422

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

405444
// Files without source are the ones that not live in the src directory
445+
// NOTE: Aqui que a magica acontece!!!!
446+
447+
const importItemWidgetComponentName =
448+
importItemWidget.widgetName ||
449+
getComponentName(importItemWidget.finalFileBundle);
450+
451+
if (importItemWidgetComponentName && !importItemWidget.isStateless) {
452+
// Processa todos os componentes filhos
453+
// Cada elemento do mesmo tipo é um filho diferente que foi adicionado ao elemento pai
454+
// const importItemElements =
455+
// fileSchema.htmlElementsProps[importItemWidgetComponentName] || [];
456+
457+
// Usa o rootHTML (conteúdo html do componente) para pegar a lista de Componentes do tipo desejado. ex: Title
458+
// const componentElements = rootHTML.getElementsByTagName(
459+
// importItemWidgetComponentName,
460+
// );
461+
// INFO: Esses comentarios acima creio que podem ser apagados, verificar
462+
// se ainda estou usando o modulo html parse
463+
464+
const jsxOnly = extractJSX(fileSchema.content);
465+
466+
const fixedJsxOnly =
467+
jsxOnly.length > 1
468+
? `<>${jsxOnly.join("\n")}</>`
469+
: jsxOnly.join("\n");
470+
471+
const componentElements = extractJSXElements(
472+
fixedJsxOnly,
473+
importItemWidgetComponentName,
474+
);
475+
476+
// Seta qualquer erro se tiver
477+
if (!processError && componentElements.error) {
478+
processError = `${fileSchema.filePath}: ${componentElements.error}`;
479+
}
480+
if (processError) return;
406481

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

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

415-
const importItemWidgetComponentName =
416-
importItemWidget.widgetName ||
417-
getComponentName(importItemWidget.finalFileBundle);
492+
const childSpreads = extractPropsResult.spreads;
418493

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

425-
// Usa o rootHTML (conteúdo html do componente) para pegar a lista de Componentes do tipo desejado. ex: Title
426-
// const componentElements = rootHTML.getElementsByTagName(
427-
// importItemWidgetComponentName,
428-
// );
429-
// INFO: Esses comentarios acima creio que podem ser apagados, verificar
430-
// se ainda estou usando o modulo html parse
497+
if (childChildren) {
498+
childChildren = processChildrenWidget(childChildren, fileSchemas);
499+
childProps = { ...childProps, children: childChildren };
500+
}
501+
502+
// Processa os Widgets dentro das propriedades, como por exemplo a propriedade
503+
// <Foo renderItem={project => <A_192 projectId={project.registrant_id} />} />
504+
// onde o "A_192" é um Widget
505+
childProps = transformWidgetInChildProps(childProps, fileSchemas);
431506

432-
const jsxOnly = extractJSX(fileSchema.content);
507+
let importItemPropsStringSequence =
508+
convertObjectToArray(childProps).join(",");
509+
510+
// Adiciona os spreads junto com as propriedades do elemento JSX. Ex:
511+
// <Widget code="..." {...{foo: 2, bar: "oi", ...mySpread1, ...mySpread2}}
512+
// no caso os spreads sao: ...mySpread1 e ...mySpread2
513+
if (childSpreads.length > 0) {
514+
importItemPropsStringSequence += `${importItemPropsStringSequence.length > 0 ? "," : ""} ${childSpreads.join(",")}`;
515+
}
433516

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

439-
const componentElements = extractJSXElements(
440-
fixedJsxOnly,
524+
// Transform components generated by .jsx / .tsx into <Widget code={code} .../>
525+
fileBundle = replaceJSXElement(
526+
fileBundle,
441527
importItemWidgetComponentName,
528+
0,
529+
`<Widget loading=" " code={props.alem.componentsCode.${importItemWidgetComponentName}} props={{ ...({${importItemPropsStringSequence ? `${importItemPropsStringSequence},` : ""} ...props}) }} />`,
442530
);
443531

444-
// Seta qualquer erro se tiver
445-
if (!processError && componentElements.error) {
446-
processError = `${fileSchema.filePath}: ${componentElements.error}`;
447-
}
448-
if (processError) return;
449-
450-
// Transfor cada componente em Widget com suas propriedades
451-
componentElements.elements.forEach((div, divIndex) => {
452-
const htmlElementString = componentElements.elements[divIndex]
453-
.toString()
454-
.replaceAll(LINE_BREAKS, "")
455-
.replaceAll(MORE_THAN_ONE_SPACE, " ");
456-
457-
const extractPropsResult = extractPropsFromJSX(htmlElementString);
458-
let childProps = extractPropsResult.keyValueProps;
459-
460-
const childSpreads = extractPropsResult.spreads;
461-
462-
// get the children
463-
let childChildren = extractJSXChildren(htmlElementString);
464-
if (childChildren) {
465-
childChildren = processChildrenWidget(
466-
childChildren,
467-
fileSchemas,
468-
);
469-
childProps = { ...childProps, children: childChildren };
470-
}
471-
472-
let importItemPropsStringSequence =
473-
convertObjectToArray(childProps).join(",");
474-
475-
// Adiciona os spreads junto com as propriedades do elemento JSX. Ex:
476-
// <Widget code="..." {...{foo: 2, bar: "oi", ...mySpread1, ...mySpread2}}
477-
// no caso os spreads sao: ...mySpread1 e ...mySpread2
478-
if (childSpreads.length > 0) {
479-
importItemPropsStringSequence += `${importItemPropsStringSequence.length > 0 ? "," : ""} ${childSpreads.join(",")}`;
480-
}
481-
482-
// Babel segue os padroes JS, por isso:
483-
// 1 - Adiciona uma uma função no topo
484-
// 2 - Fecha a função no final
485-
fileBundle = `const TempMethod = () => {\n${fileBundle}\n}`;
486-
// NOTE: nao adicionando a ultima linha, mas estou removendo a ultima linha
487-
// Caso quebre, ver isso. [Provavelmente o escape acima esta adicionando o } no final]
488-
489-
// Transform components generated by .jsx / .tsx into <Widget code={code} .../>
490-
fileBundle = replaceJSXElement(
491-
fileBundle,
492-
importItemWidgetComponentName,
493-
0,
494-
`<Widget loading=" " code={props.alem.componentsCode.${importItemWidgetComponentName}} props={{ ...({${importItemPropsStringSequence ? `${importItemPropsStringSequence},` : ""} ...props}) }} />`,
495-
);
496-
497-
// Remove funcao no topo e ultima linha fechando a funcao
498-
fileBundle = fileBundle.replace("const TempMethod = () => {", "");
499-
fileBundle = removeLastLineFromText(fileBundle);
500-
});
501-
}
502-
503-
// Altera o jsContent com os Widgets
504-
fileSchema.jsContent = fileBundle;
505-
// Altera o finalBundle que é usado posteriormente
506-
fileSchema.finalFileBundle = fileBundle;
532+
// Remove funcao no topo e ultima linha fechando a funcao
533+
fileBundle = fileBundle.replace("const TempMethod = () => {", "");
534+
fileBundle = removeLastLineFromText(fileBundle);
535+
});
507536
}
537+
538+
// Altera o jsContent com os Widgets
539+
fileSchema.jsContent = fileBundle;
540+
// Altera o finalBundle que é usado posteriormente
541+
fileSchema.finalFileBundle = fileBundle;
508542
}
509543
}
510544
});

lib/compiler.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { create_dist, log } = require("./utils");
1+
const { create_dist, log, reset_name_counter } = require("./utils");
22
const path = require("path");
33
const fs = require("fs");
44
const loadFilesInfo = require("./actions/loadFilesInfo");
@@ -126,6 +126,7 @@ function run_final_process(filesInfo, opts) {
126126
* @param {*} opts Opcoes da CLI
127127
*/
128128
function compile_files(opts) {
129+
reset_name_counter();
129130
create_dist(distFolder);
130131

131132
let entryFile = path.join(".", "src", "index.tsx");

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "alem",
33
"description": "Create web3 applications for NEAR BOS with a focus on performance and friendly development.",
4-
"version": "1.0.0",
4+
"version": "1.0.1",
55
"main": "main.js",
66
"types": "index.d.ts",
77
"author": "Wenderson Pires - wendersonpires.near",

0 commit comments

Comments
 (0)