diff --git a/frontends/nextjs/src/lib/db/packages/get-installed-packages.test.ts b/frontends/nextjs/src/lib/db/packages/get-installed-packages.test.ts new file mode 100644 index 000000000..3bdd4d153 --- /dev/null +++ b/frontends/nextjs/src/lib/db/packages/get-installed-packages.test.ts @@ -0,0 +1,33 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest' + +const mockList = vi.fn() +const mockAdapter = { list: mockList } + +vi.mock('../dbal-client', () => ({ + getAdapter: () => mockAdapter, +})) + +import { getInstalledPackages } from './get-installed-packages' + +describe('getInstalledPackages', () => { + beforeEach(() => { + mockList.mockReset() + }) + + it('returns mapped installed packages', async () => { + mockList.mockResolvedValue({ + data: [ + { packageId: 'pkg_one', installedAt: BigInt(100), version: '1.0.0', enabled: true }, + { packageId: 'pkg_two', installedAt: BigInt(200), version: '2.0.0', enabled: false }, + ], + }) + + const result = await getInstalledPackages() + + expect(mockList).toHaveBeenCalledWith('InstalledPackage') + expect(result).toEqual([ + { packageId: 'pkg_one', installedAt: 100, version: '1.0.0', enabled: true }, + { packageId: 'pkg_two', installedAt: 200, version: '2.0.0', enabled: false }, + ]) + }) +}) diff --git a/frontends/nextjs/src/lib/db/packages/install-package.test.ts b/frontends/nextjs/src/lib/db/packages/install-package.test.ts new file mode 100644 index 000000000..93f1dcbbb --- /dev/null +++ b/frontends/nextjs/src/lib/db/packages/install-package.test.ts @@ -0,0 +1,52 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest' + +const mockFindFirst = vi.fn() +const mockCreate = vi.fn() +const mockAdapter = { findFirst: mockFindFirst, create: mockCreate } + +vi.mock('../dbal-client', () => ({ + getAdapter: () => mockAdapter, +})) + +import { installPackage } from './install-package' + +describe('installPackage', () => { + beforeEach(() => { + mockFindFirst.mockReset() + mockCreate.mockReset() + }) + + it('creates package when not installed', async () => { + mockFindFirst.mockResolvedValue(null) + + await installPackage({ + packageId: 'pkg_one', + installedAt: 1234, + version: '1.2.3', + enabled: true, + }) + + expect(mockFindFirst).toHaveBeenCalledWith('InstalledPackage', { + where: { packageId: 'pkg_one' }, + }) + expect(mockCreate).toHaveBeenCalledWith('InstalledPackage', { + packageId: 'pkg_one', + installedAt: BigInt(1234), + version: '1.2.3', + enabled: true, + }) + }) + + it('does not create when already installed', async () => { + mockFindFirst.mockResolvedValue({ packageId: 'pkg_one' }) + + await installPackage({ + packageId: 'pkg_one', + installedAt: 1234, + version: '1.2.3', + enabled: true, + }) + + expect(mockCreate).not.toHaveBeenCalled() + }) +}) diff --git a/frontends/nextjs/src/lib/nerd-mode-ide/append-node.ts b/frontends/nextjs/src/lib/nerd-mode-ide/append-node.ts new file mode 100644 index 000000000..f6ac704ed --- /dev/null +++ b/frontends/nextjs/src/lib/nerd-mode-ide/append-node.ts @@ -0,0 +1,16 @@ +import type { FileNode } from './types' + +export function appendNode(nodes: FileNode[], parentId: string | null, newNode: FileNode): FileNode[] { + if (!parentId) return [...nodes, newNode] + + return nodes.map((node) => { + if (node.id === parentId && node.type === 'folder') { + const children = node.children ? [...node.children, newNode] : [newNode] + return { ...node, children, expanded: true } + } + if (node.children) { + return { ...node, children: appendNode(node.children, parentId, newNode) } + } + return node + }) +} diff --git a/frontends/nextjs/src/lib/nerd-mode-ide/create-file-node.ts b/frontends/nextjs/src/lib/nerd-mode-ide/create-file-node.ts new file mode 100644 index 000000000..bc67c7cef --- /dev/null +++ b/frontends/nextjs/src/lib/nerd-mode-ide/create-file-node.ts @@ -0,0 +1,20 @@ +import { createNodeId } from './create-node-id' +import { getLanguageFromFilename } from './get-language-from-filename' +import type { FileNode } from './types' + +interface CreateFileNodeOptions { + name: string + content?: string + exportPath?: string +} + +export function createFileNode({ name, content = '', exportPath }: CreateFileNodeOptions): FileNode { + return { + id: createNodeId('file'), + name, + type: 'file', + content, + language: getLanguageFromFilename(name), + exportPath, + } +} diff --git a/frontends/nextjs/src/lib/nerd-mode-ide/create-folder-node.ts b/frontends/nextjs/src/lib/nerd-mode-ide/create-folder-node.ts new file mode 100644 index 000000000..42b0b11b3 --- /dev/null +++ b/frontends/nextjs/src/lib/nerd-mode-ide/create-folder-node.ts @@ -0,0 +1,20 @@ +import { createNodeId } from './create-node-id' +import type { FileNode } from './types' + +interface CreateFolderNodeOptions { + name: string + children?: FileNode[] + expanded?: boolean + exportPath?: string +} + +export function createFolderNode({ name, children = [], expanded = false, exportPath }: CreateFolderNodeOptions): FileNode { + return { + id: createNodeId('folder'), + name, + type: 'folder', + children, + expanded, + exportPath, + } +}