From 6e24fe6ba81dd3f4d4fe6f4d0e8dbddb2c9566a8 Mon Sep 17 00:00:00 2001 From: imfozilbek Date: Sun, 23 Nov 2025 21:43:40 +0500 Subject: [PATCH] feat(core): add infrastructure layer services Add infrastructure implementations: - BaseRepository with in-memory storage - GitService for git operations using simple-git - CodeParser for JS/TS parsing using tree-sitter --- .../core/src/infrastructure/git/GitService.ts | 42 ++++++++++++++ packages/core/src/infrastructure/index.ts | 3 + .../src/infrastructure/parsers/CodeParser.ts | 56 +++++++++++++++++++ .../repositories/BaseRepository.ts | 39 +++++++++++++ 4 files changed, 140 insertions(+) create mode 100644 packages/core/src/infrastructure/git/GitService.ts create mode 100644 packages/core/src/infrastructure/index.ts create mode 100644 packages/core/src/infrastructure/parsers/CodeParser.ts create mode 100644 packages/core/src/infrastructure/repositories/BaseRepository.ts diff --git a/packages/core/src/infrastructure/git/GitService.ts b/packages/core/src/infrastructure/git/GitService.ts new file mode 100644 index 0000000..615bfec --- /dev/null +++ b/packages/core/src/infrastructure/git/GitService.ts @@ -0,0 +1,42 @@ +import simpleGit, { SimpleGit, SimpleGitOptions } from 'simple-git'; + +/** + * Git operations service using simple-git + */ +export class GitService { + private readonly git: SimpleGit; + + constructor(baseDir: string, options?: Partial) { + this.git = simpleGit(baseDir, options); + } + + public async clone(repoUrl: string, localPath: string): Promise { + await this.git.clone(repoUrl, localPath); + } + + public async status(): Promise { + const statusSummary = await this.git.status(); + return JSON.stringify(statusSummary, null, 2); + } + + public async log(maxCount: number = 10): Promise { + const logResult = await this.git.log({ maxCount }); + return JSON.stringify(logResult, null, 2); + } + + public async add(files: string | string[]): Promise { + await this.git.add(files); + } + + public async commit(message: string): Promise { + await this.git.commit(message); + } + + public async push(remote: string = 'origin', branch: string = 'main'): Promise { + await this.git.push(remote, branch); + } + + public async pull(remote: string = 'origin', branch: string = 'main'): Promise { + await this.git.pull(remote, branch); + } +} \ No newline at end of file diff --git a/packages/core/src/infrastructure/index.ts b/packages/core/src/infrastructure/index.ts new file mode 100644 index 0000000..c0bad36 --- /dev/null +++ b/packages/core/src/infrastructure/index.ts @@ -0,0 +1,3 @@ +export * from './repositories/BaseRepository'; +export * from './git/GitService'; +export * from './parsers/CodeParser'; \ No newline at end of file diff --git a/packages/core/src/infrastructure/parsers/CodeParser.ts b/packages/core/src/infrastructure/parsers/CodeParser.ts new file mode 100644 index 0000000..aefd137 --- /dev/null +++ b/packages/core/src/infrastructure/parsers/CodeParser.ts @@ -0,0 +1,56 @@ +import Parser from 'tree-sitter'; +import JavaScript from 'tree-sitter-javascript'; +import TypeScript from 'tree-sitter-typescript'; + +/** + * Code parser service using tree-sitter + */ +export class CodeParser { + private readonly parser: Parser; + + constructor() { + this.parser = new Parser(); + } + + public parseJavaScript(code: string): Parser.Tree { + this.parser.setLanguage(JavaScript); + return this.parser.parse(code); + } + + public parseTypeScript(code: string): Parser.Tree { + this.parser.setLanguage(TypeScript.typescript); + return this.parser.parse(code); + } + + public parseTsx(code: string): Parser.Tree { + this.parser.setLanguage(TypeScript.tsx); + return this.parser.parse(code); + } + + public extractFunctions(tree: Parser.Tree): string[] { + const functions: string[] = []; + const cursor = tree.walk(); + + const visit = (): void => { + const node = cursor.currentNode; + + if ( + node.type === 'function_declaration' || + node.type === 'arrow_function' || + node.type === 'function_expression' + ) { + functions.push(node.text); + } + + if (cursor.gotoFirstChild()) { + do { + visit(); + } while (cursor.gotoNextSibling()); + cursor.gotoParent(); + } + }; + + visit(); + return functions; + } +} \ No newline at end of file diff --git a/packages/core/src/infrastructure/repositories/BaseRepository.ts b/packages/core/src/infrastructure/repositories/BaseRepository.ts new file mode 100644 index 0000000..10bb878 --- /dev/null +++ b/packages/core/src/infrastructure/repositories/BaseRepository.ts @@ -0,0 +1,39 @@ +import { BaseEntity } from '../../domain/entities/BaseEntity'; +import { IRepository } from '../../domain/repositories/IRepository'; + +/** + * Abstract base repository implementation + * Provides common repository functionality + */ +export abstract class BaseRepository implements IRepository { + protected readonly items: Map = new Map(); + + public async findById(id: string): Promise { + return this.items.get(id) ?? null; + } + + public async findAll(): Promise { + return Array.from(this.items.values()); + } + + public async save(entity: T): Promise { + this.items.set(entity.id, entity); + return entity; + } + + public async update(entity: T): Promise { + if (!this.items.has(entity.id)) { + throw new Error(`Entity with id ${entity.id} not found`); + } + this.items.set(entity.id, entity); + return entity; + } + + public async delete(id: string): Promise { + return this.items.delete(id); + } + + public async exists(id: string): Promise { + return this.items.has(id); + } +} \ No newline at end of file