made-beta
Version:
It allows you to create tasks in your project manager (e.g., Github) automatically based on predefined processes. Additionally, it generates documentation based on the project.
284 lines (206 loc) • 8.41 kB
text/typescript
import { Util } from '../service/util.js';
import { createPath } from '../../generator-utils.js'
import path from "path";
import lodash from 'lodash'
import { LowSync } from 'lowdb';
import { JSONFileSync } from 'lowdb/node';
import { Mutex } from 'async-mutex';
import {IssuesDTO,Issue} from "made-lib-beta";
import { Model } from '../../../language/generated/ast.js';
import { IssueBuilder } from './builders/IssueBuilder.js';
const mutex = new Mutex();
export abstract class AbstractApplication {
DB_PATH: string
model: Model
jsonFile: string
protected items: Map<string, any>;
constructor(target_folder: string, model: Model ) {
Util.mkdirSync(target_folder)
this.model = model
this.DB_PATH = createPath(target_folder, 'db')
this.jsonFile = "data.json"
this.items = new Map<string, any>();
}
protected async addItem (value:any){
const id = value.id.toLocaleLowerCase()
this.items.set(id, value)
}
protected async _idExists(id:string){
const ISSUEPATH = path.join(this.DB_PATH, this.jsonFile);
const adapter = new JSONFileSync <IssuesDTO>(ISSUEPATH);
const defaultData: IssuesDTO = { data: [] };
const db = new LowSync<IssuesDTO>(adapter,defaultData)
await db.read()
const exists = lodash.chain(db.data).get('data').some({ id: id }).value();
if (exists) return true;
return false;
}
protected async retrieve(id:string){
const ISSUEPATH = path.join(this.DB_PATH, this.jsonFile);
const adapter = new JSONFileSync <IssuesDTO>(ISSUEPATH);
const defaultData: IssuesDTO = { data: [] };
const db = new LowSync<IssuesDTO>(adapter,defaultData)
await db.read()
return lodash.chain(db.data).get('data').find({ id: id }).value();
}
protected async retrieveByExternal(id:string){
const ISSUEPATH = path.join(this.DB_PATH, this.jsonFile);
const adapter = new JSONFileSync <IssuesDTO>(ISSUEPATH);
const defaultData: IssuesDTO = { data: [] };
const db = new LowSync<IssuesDTO>(adapter,defaultData)
await db.read()
return lodash.chain(db.data).get('data').find({ id: id }).value();
}
protected async retrieveByExternalData(data:string){
const ISSUEPATH = path.join(this.DB_PATH, this.jsonFile);
const adapter = new JSONFileSync <IssuesDTO>(ISSUEPATH);
const defaultData: IssuesDTO = { data: [] };
const db = new LowSync<IssuesDTO>(adapter,defaultData)
await db.read()
return lodash.chain(db.data).get('data').find(data).value();
}
protected async createAndSave(parentID: string, data: any){
const issue = await this.createIssue (parentID, data, 0)
await this.saveorUpdate (issue)
}
protected async createIssue (parentID: string, data: any, depth: number = 0): Promise<Issue> {
// Proteção contra recursão infinita
if (depth > 50) {
console.warn(`Max depth reached for issue: ${parentID}.${data.id}`);
throw new Error(`Maximum recursion depth exceeded for issue: ${parentID}.${data.id}`);
}
const id = parentID+"."+data.id.toLocaleLowerCase()
let depends: Issue[] = []
let childIssues: Issue[] = [] // Array para acumular todas as issues filhas
const builder: IssueBuilder = new IssueBuilder()
.setId(id)
.setTitle(data.name)
.setDescription(data.description ?? "")
.setType(data.$type.toLocaleLowerCase())
// Processar user stories
if (data.userstories && data.userstories.length > 0) {
const userStoryIssues = await Promise.all(
data.userstories.map(async (value: any) =>
await this.createIssue(id, value, depth + 1)
)
);
childIssues.push(...userStoryIssues); // Adicionar ao array
}
// Processar tasks
if (data.tasks && data.tasks.length > 0) {
const taskIssues = await Promise.all(
data.tasks.map(async (value: any) =>
await this.createIssue(id, value, depth + 1)
)
);
childIssues.push(...taskIssues); // Adicionar ao array (não sobrescrever)
}
// Definir todas as issues filhas de uma vez
if (childIssues.length > 0) {
builder.setIssues(childIssues);
}
if (data.depends){
if (data.depends.length >0){
await Promise.all(data.depends?.map(async (value:any) =>
depends.push ({
id:value.$refNode?.text.toLocaleLowerCase()
}as Issue )
))
}
if (data.depend){
depends.push ({
id:data.depend.$refNode?.text.toLocaleLowerCase()
}as Issue )
}
}
builder.setDepends(depends)
return builder.build()
}
protected async saveorUpdate (data: any){
const value = await this.retrieve(data.id)
if (!value){
this.save (data)
}
else{
this.update(data.id, data)
}
}
protected async save(issueDTO: any) {
await mutex.runExclusive(async () => {
const ISSUEPATH = path.join(this.DB_PATH, this.jsonFile);
const adapter = new JSONFileSync <IssuesDTO>(ISSUEPATH);
const defaultData: IssuesDTO = { data: [] };
const db = new LowSync<IssuesDTO>(adapter,defaultData)
await db.read();
db.data ||= defaultData;
if (db.data?.data) {
db.data.data.push(issueDTO);
}
await db.write();
});
}
protected async remove(issueId: string) {
await mutex.runExclusive(async () => {
const ISSUEPATH = path.join(this.DB_PATH, this.jsonFile);
const adapter = new JSONFileSync<IssuesDTO>(ISSUEPATH);
const defaultData: IssuesDTO = { data: [] };
const db = new LowSync<IssuesDTO>(adapter, defaultData);
await db.read();
db.data ||= defaultData;
if (db.data?.data) {
// Encontra o índice do item a ser removido
const itemIndex = db.data.data.findIndex(item => item.id === issueId);
// Se encontrou o item, remove-o do array
if (itemIndex !== -1) {
db.data.data.splice(itemIndex, 1);
await db.write();
return true;
}
return false;
}
return false;
});
}
protected async update(issueId: string, newData: Partial<any>) {
await mutex.runExclusive(async () => {
const ISSUEPATH = path.join(this.DB_PATH, this.jsonFile);
const adapter = new JSONFileSync<IssuesDTO>(ISSUEPATH);
const defaultData: IssuesDTO = { data: [] };
const db = new LowSync<IssuesDTO>(adapter, defaultData);
// Ler o banco de dados
await db.read();
db.data ||= defaultData;
// Encontra o índice do item que deseja atualizar
const issueIndex = db.data.data.findIndex((issue) => issue.id === issueId);
if (issueIndex !== -1) {
// Atualiza o item com os novos dados
db.data.data[issueIndex] = { ...db.data.data[issueIndex], ...newData };
await db.write();
}
});
}
protected async retrieveAll(){
const ISSUEPATH = path.join(this.DB_PATH, this.jsonFile);
const adapter = new JSONFileSync<IssuesDTO>(ISSUEPATH);
const defaultData: IssuesDTO = { data: [] };
const db = new LowSync<IssuesDTO>(adapter, defaultData);
await db.read();
return db.data.data.sort((a, b) => {
return Number(a.id) - Number(b.id);
});
}
protected async clean(){
const issues = this.retrieveAll();
(await issues).map (issue => {
const id = issue.id
const result = this.items.has(id)
//Caso não existe o ID apagar
if (!result){
this.remove(issue.id)
}
})
// criar uma lista de issues com ID, usar uma hash para isso
// caso não existe ... remover
//depois é necessário remover os filhos de um arvore, US que nao existem mais de uma EPIC, e task qeu nao existem mais em um US ou epic
}
}