Skip to content

Commit

Permalink
started the resource to convert imported images to base64 and add the…
Browse files Browse the repository at this point in the history
…m to the code
  • Loading branch information
wpdas committed May 24, 2024
1 parent 3ff86ba commit a80b228
Show file tree
Hide file tree
Showing 8 changed files with 782 additions and 42 deletions.
28 changes: 28 additions & 0 deletions lib/actions/asStatefulCheck.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
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"');

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

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

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

module.exports = asStatefulCheck;
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
46 changes: 21 additions & 25 deletions lib/actions/transformSchemaToWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const getFunctionExportDeclarationKeys = require("../parsers/getFunctionExportDe
const { read_alem_config } = require("../config");
const filterReturn = require("../parsers/filterReturn");
const getProjectName = require("./getProjectName");
const asStatefulCheck = require("./asStatefulCheck");

const config = read_alem_config();

Expand Down Expand Up @@ -107,6 +108,16 @@ const processSchema = (fileSchema) => {

// isStateless = Arquivo sem controle de estado
let isStateless = !hasWidgetPropsCheck(fileSchema.content) && !isIndex;

// Checa se tem a assinatura "as stateful" no conteúdo original do arquivo
if (isStateless) {
const checkResult = asStatefulCheck(fileSchema.content);
if (checkResult.asStatefulSignalFound) {
fileSchema.content = checkResult.updatedContent;
isStateless = false;
}
}

fileSchema.isStateless = isStateless;

// ITEM 2
Expand All @@ -125,31 +136,16 @@ const processSchema = (fileSchema) => {
transpileTypescript,
);

// É uma página? Se for, deve criar um arquivo separado
// const isPage =
// fileSchema.filePath.includes("page.ts") ||
// fileSchema.filePath.includes("page.js"); // isso pega tbm tsx e jsx

// Deve ser ejetado? (cria um arquivo separado do arquivo principal Indexador)
const toBeEjected =
config.options?.ejectStatefulComponents &&
hasWidgetPropsCheck(fileSchema.content);

if (toBeEjected) {
// INICIO: Feature para pegar o nome da pasta da pagina e usar como nome de rota
// Unix
// TODO: Windows
// const fileDirParts = fileSchema.filePath.split("/");
// const pageFolderIndex = fileDirParts.length - 2;
// const pageFolderName = fileDirParts[pageFolderIndex];
// console.log(fileSchema.filePath, fileSchema.pageName);
// fileSchema.pageName = pageFolderName;
// FIM

// Componentes ejetados devem ser setadas como statefull para impedir a injecao delas
// nos arquivos que dependem delas.
fileSchema.isStateless = isStateless = false;
}
/**
* Deve ser ejetado os arquivos stateful? (cria um arquivo separado do arquivo principal Indexador)
*
* Configuraçao (alem.config.json):
* options: {
* ejectStatefulComponents: true
* }
*/
const toBeEjected = config.options?.ejectStatefulComponents && !isStateless;

fileSchema.toBeEjected = toBeEjected;

// isModule = Arquivos que estão na pasta "src/modules". Estes são inseridos no state global para serem acessados por todos
Expand Down
15 changes: 14 additions & 1 deletion lib/alem-vm/alem-vm.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
// ALEM Items:

type Children = JSX.Element | ReactElement | JSX.Element[] | string | number;

type ReturnChildren = (
params,
) => JSX.Element | ReactElement | JSX.Element[] | string | number;

/**
* As a Stateful Widget. Tells the compiler to generate this component as a stateful widget (even though it is stateless). When using this type, the file must have only one component present.
*
* This is useful for when you want to avoid unnecessary re-renders caused by stateless components manipulating the state of the main component.
*/
export type AsStateful = ReturnChildren | Children;

export type ChildrenProps = {
children: JSX.Element | ReactElement | JSX.Element[] | string | number;
children: Children;
};

export type ModuleResponseData = { response: any; forCallId: number };
Expand Down
58 changes: 58 additions & 0 deletions lib/parsers/hasSignatureType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");

/**
* Verifica se o componente é de um tipo específico, se for, retorna true, senão, false.
*
* ex:
*
* ```
* const code = `const Foo: AsStateful = () => {...}`
* const code2 = `const Foo: Other = () => {...}`
* const signatureType = "AsStateful";
*
* hasSignatureType(code, signatureType); // true;
* hasSignatureType(code2, signatureType); // false;
* ```
*
* @param {*} code
* @param {*} signatureType
* @returns
*/
function hasSignatureType(code, signatureType) {
const ast = parser.parse(code, {
sourceType: "module",
plugins: ["jsx", "typescript"],
});

let found = false;

traverse(ast, {
VariableDeclarator(path) {
if (
path.node.id.typeAnnotation &&
t.isTSTypeReference(path.node.id.typeAnnotation.typeAnnotation) &&
path.node.id.typeAnnotation.typeAnnotation.typeName.name ===
signatureType
) {
found = true;
path.stop();
}
},
FunctionDeclaration(path) {
if (
path.node.returnType &&
t.isTSTypeReference(path.node.returnType.typeAnnotation) &&
path.node.returnType.typeAnnotation.typeName.name === signatureType
) {
found = true;
path.stop();
}
},
});

return found;
}

module.exports = hasSignatureType;
66 changes: 66 additions & 0 deletions lib/parsers/processImportsToBase64.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const nodePath = require("path");
const sharp = require("sharp");

function isImageFile(filePath) {
const imageExtensions = [".png", ".jpg", ".jpeg", ".gif", ".svg"];
return imageExtensions.includes(nodePath.extname(filePath).toLowerCase());
}

async function getBase64(filePath, quality = 80) {
const fileBuffer = await sharp(filePath)
.resize({ width: 800 }) // Adjust the size as needed
.jpeg({ quality }) // Adjust the quality as needed
.toBuffer();

return `data:image/${nodePath
.extname(filePath)
.slice(1)};base64,${fileBuffer.toString("base64")}`;
}

/**
* Processo que captura os imports de imagens e guarda seu conteúdo em base64 para
* ser usado posteriormente no processo do compilador.
* @param {*} code
* @param {*} fileDir
* @param {*} quality
* @returns
*/
async function processImportsToBase64(code, fileDir, quality) {
const ast = parser.parse(code, {
sourceType: "module",
plugins: ["jsx", "typescript"],
});

const imageImports = [];

const promises = [];

traverse(ast, {
ImportDeclaration(path) {
const importPath = path.node.source.value;
const importName = path.node.specifiers[0].local.name;
const fullImportPath = nodePath.resolve(
nodePath.dirname(fileDir),
importPath,
);

if (isImageFile(fullImportPath)) {
promises.push(
getBase64(fullImportPath, quality).then((base64Content) => {
imageImports.push({
imageKey: importName,
imageBase64Content: base64Content,
});
}),
);
}
},
});

await Promise.all(promises);
return imageImports;
}

module.exports = processImportsToBase64;
Loading

0 comments on commit a80b228

Please sign in to comment.