import path from 'node:path' import fs from 'node:fs' import cluster from "node:cluster"; import { PlataFs } from './fs' import { glob } from 'glob' declare global { interface PlataRuntime extends PlataGlobalRuntime { } } export class PlataGlobalRuntime { public readonly files = PlataFs public readonly ProjectDir: string public readonly PlataDir: string public readonly ProjectJson: any public readonly PlataJson: any public readonly nodeRequire: typeof require = module.constructor.prototype.require // Cluster public readonly NodeCluster = cluster public readonly cluster: { isPrimary: true, clusters: Cluster.ClusterConfig[] } | { isPrimary: false, clusters?: undefined } // Knex public _knexExtended: boolean = false // Wasm public readonly _loadedsWasms: Set = new Set() // Env public config: PlataEnvAutoComplete = process.env private effectLib: (typeof import('effect').Effect) | null = null constructor() { // Caminhos da Plata this.ProjectDir = process.cwd() this.ProjectJson = JSON.parse( fs.readFileSync( path.join(this.ProjectDir, 'package.json') ).toString() ) this.PlataDir = path.resolve('.', 'node_modules', this.ProjectJson.plata_name?.toString() ?? '..') this.PlataJson = JSON.parse( fs.readFileSync( path.join(this.PlataDir, 'package.json') ).toString() ) if (this.NodeCluster.isPrimary) { this.cluster = { isPrimary: true, clusters: [] } } else { this.cluster = { isPrimary: false } } } private getEffectLib(): typeof import('effect').Effect { if (this.effectLib === null) { this.effectLib = require('effect').Effect as typeof import('effect').Effect } return this.effectLib } public MakeDisposable(newFunction: (...args: A) => T, ...a: A): PlataDisposable { return new Proxy(newFunction(...a), { get(target, prop, reciver) { if (prop === Symbol.dispose || prop === Symbol.asyncDispose) { return () => target.close() } return Reflect.get(target, prop, reciver) } }) as PlataDisposable } public CacheClass(newFunction: (...args: any) => T): T { const p = process as NodeJS.Process & PlataProcess if (p._plata_cache === undefined) { p._plata_cache = new Map() } let value = p._plata_cache.get(newFunction) if (value === undefined) { value = newFunction() p._plata_cache.set(newFunction, value) } return value as T } public async PromiseAll }>>(promises: T): PlataPromiseAllReturn { if (promises.length === 0) { return [] as any } const Effect = this.getEffectLib() const results = new Array(promises.length) let error: PlataError | null = null const effect = Effect.forEach(promises as Promise[], (p, i) => Effect.gen(function* (_) { const result: PlataResult = yield* _(Effect.promise(() => p)) if (result.errorID !== undefined) { error = result return yield* _(Effect.interrupt) } results[i] = result }), { concurrency: 'unbounded' }) await Effect.runPromise(effect).catch((err) => { if (error === null) error = { errorID: 'PBRUNEFFPROALL001', msg: 'Erro ao realizar a operação', error: { message: err?.toString(), stack: err?.stack ?? new Error().stack } } }) if (error !== null) { return error } return results as any } public FastPromise(p: () => Promise): Promise { return Promise.resolve().then(p) } public BuildPlataError(e: PlataError): PlataError { return e } /** @deprecated */ public BuildObject(o: T): T { return o } public keyof(obj: T): (keyof T)[] { return Object.keys(obj) as (keyof T)[] } public valuesOf(obj: T): T[keyof T][] { return Object.values(obj) as T[keyof T][] } public async RequireAsync(p: string): RequireAsyncReturn { try { return { filePath: p, name: path.basename(p).replace('.ts', '').replace('.js', '').replace('.jsc', ''), exports: require(p) as T } } catch (err) { return { errorID: 'PLTRF0001', msg: `Error while importing file ${p}`, error: { message: err?.toString(), stack: err?.stack ?? new Error().stack } } } } public async RequireFolder(p: string): RequireFolderReturn { const promises: PlataPromise>[] = [] glob.sync(`${p.replace(/\\/g, '/')}/**/*.+(js|ts|jsc)`) .filter(file => !file.endsWith('.d.ts')) .forEach(file => { file = file.replace(/(\.ts|\.js|\.jsc)$/, '') promises.push(this.FastPromise(() => this.RequireAsync(file))) }) ; return Promise.all(promises).then( rs => { const errors: PlataError[] = [] const result: RequiredInterface[] = [] rs.forEach(r => { if (r.errorID !== undefined) { errors.push(r) } else { result.push(r) } }) if (errors.length !== 0) { return { errorID: 'PLTRF0003', msg: `Errors while importing folder: ${p}`, error: errors } } return result }, err => { return { errorID: 'PLTRF0002', msg: `Error while importing folder: ${p}`, error: { message: err?.toString(), stack: err?.stack ?? new Error().stack } } } ) } public async ReadEnvFileToPromise(p: string) { const envFile = Object.create(null) if (await this.files.access(p.replace('__BUILD__/', ''))) { p = p.replace('__BUILD__/', '') } const result = await this.files.ReadFileAsync(p, async line => { if (line[0] === '#') return if (line !== '') { const env = line.split('=') if (env.length >= 2) { const [ key, ...v ] = env let value = v.join('=') if (value[0] === '{' && value.slice(-1) === '}') value = process.env[value.slice(1, -1)] ?? '' ; if (value !== '') envFile[key] = value ; } } }) if (result !== null) { return result } return envFile } /** @deprecated */ public TimeZoneDate(d: Date): Sql.TimeZoneDate { return new Date(d.getTime() - (d.getTimezoneOffset() * 1000 * 60)) as any } public async switchUnion>(value: V, cases: C): PlataPromise>> { const f = cases[value] as any if (f === undefined) return cases['_default'](value as any) as any ; return f(value as any) as any } public async switchUnionObject, K extends keyof V, C extends SwitchUnionObjectFunctionCases = SwitchUnionObjectFunctionCases>(v: V, chave: K, cases: C): PlataPromise>> { if (v === undefined || v === null) return cases['_default'](v) as any ; const f = cases[v[chave]] if (f === undefined) return cases['_default'](v) as any ; return f(v) as any } public trimObject>(x: T): T { if (x === null || x === undefined) { return x } for (const key in x) { if (x[key] === null || x[key] === undefined) continue ; if ((x[key] as any) instanceof Date) continue ; if (typeof x[key] === 'string') { x[key] = x[key].trim() continue } if (Array.isArray(x[key])) { for (let i = 0; i < x[key].length; i++) { if (typeof x[key][i] === 'string') { x[key][i] = x[key][i].trim() continue } x[key][i] = Plata.trimObject(x[key][i]) } continue } if (typeof x[key] === 'object') x[key] = Plata.trimObject(x[key]) ; } return x } public Brand(_k: K, value: Brands[K]): Brand { return value as Brand } public RefFrom(obj: T, key: K): PlataRef { return { get value() { return obj[key] }, applyTo(key: K, target: Omit): Readonly { const descriptor = Object.getOwnPropertyDescriptor(this, "value") if (!descriptor || (!descriptor.get && !descriptor.set)) { return { ...target, [key]: this.value } as Readonly } Object.defineProperty(target, key, { get: descriptor.get, set: descriptor.set, enumerable: true, configurable: true }) return target as Readonly } } } } type PlataPromiseAllReturn }>> = PlataPromise< R extends [] ? T extends Promise[] ? RemovePlataResult[] : never : R > type SwitchUnionObjectFunctionCases, K extends keyof V> = { [type in V[K] | '_default']: type extends '_default' ? (v: V) => Promise : V extends { [P in K]: type } ? (v: V) => Promise : never } type SwitchUnionFunctionCases = { [T in (V | '_default')]: T extends V ? (v: T) => Promise : (v: unknown) => Promise }