UNPKG

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
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 } }