diff --git a/backend/src/build-system/handlers/file-manager/file-arch/index.ts b/backend/src/build-system/handlers/file-manager/file-arch/index.ts index 0ff3241b..ca2ee0b2 100644 --- a/backend/src/build-system/handlers/file-manager/file-arch/index.ts +++ b/backend/src/build-system/handlers/file-manager/file-arch/index.ts @@ -14,13 +14,14 @@ import { ModelUnavailableError, } from 'src/build-system/errors'; import { VirtualDirectory } from 'src/build-system/virtual-dir'; + +import { FileStructureHandler } from '../file-structure'; +import { UXDMDHandler } from '../../ux/datamap'; +import { BuildNode, BuildNodeRequire } from 'src/build-system/hanlder-manager'; import { buildDependencyGraph, validateAgainstVirtualDirectory, } from 'src/build-system/utils/file_generator_util'; -import { FileStructureHandler } from '../file-structure'; -import { UXDMDHandler } from '../../ux/datamap'; -import { BuildNode, BuildNodeRequire } from 'src/build-system/hanlder-manager'; @BuildNode() @BuildNodeRequire([FileStructureHandler, UXDMDHandler]) @@ -36,6 +37,7 @@ export class FileFAHandler implements BuildHandler { const fileStructure = context.getNodeData(FileStructureHandler); const datamapDoc = context.getNodeData(UXDMDHandler); + this.logger.log('fileStructure:', fileStructure); if (!fileStructure || !datamapDoc) { throw new InvalidParameterError( 'Missing required parameters: fileStructure or datamapDoc.', @@ -57,7 +59,7 @@ export class FileFAHandler implements BuildHandler { ${datamapDoc} - Next, I'll provide the **Directory Structure**.`, + Next, I will provide the **Directory Structure** to help you understand the full project architecture.`, }, { role: 'user' as const, @@ -67,13 +69,15 @@ export class FileFAHandler implements BuildHandler { ${fileStructure} - Please generate the full File Architecture JSON object now, ensuring adherence to all the rules.`, + Based on this structure and the analysis provided earlier, please generate the File Architecture JSON object. Ensure the output adheres to all rules and guidelines specified in the system prompt.`, }, { role: 'user' as const, - content: `**Final Check:** - - Ensure the JSON structure is correct. - - Ensure all files and dependencies are included.`, + content: `**Final Check** + Before returning the output, ensure the following: + - The JSON structure is correctly formatted and wrapped in tags. + - File extensions and paths match those in the Directory Structure. + - All files and dependencies are included.`, }, ]; @@ -93,28 +97,43 @@ export class FileFAHandler implements BuildHandler { throw new ModelUnavailableError('Model is unavailable:' + error); } - const tagContent = parseGenerateTag(fileArchContent); - const jsonData = extractJsonFromText(tagContent); + try { + const tagContent = parseGenerateTag(fileArchContent); + const jsonData = extractJsonFromText(tagContent); - if (!jsonData) { - this.logger.error('Failed to extract JSON from text'); - throw new ResponseParsingError('Failed to extract JSON from text.'); - } + if (!jsonData) { + this.logger.error('Failed to extract JSON from text'); + throw new ResponseParsingError('Failed to extract JSON from text.'); + } - if (!this.validateJsonData(jsonData)) { - this.logger.error('File architecture JSON validation failed.'); - throw new ResponseParsingError( - 'File architecture JSON validation failed.', + if (!this.validateJsonData(jsonData)) { + this.logger.error('File architecture JSON validation failed.'); + throw new ResponseParsingError( + 'File architecture JSON validation failed.', + ); + } + + // validate with virutual dir + const { graph, nodes, fileInfos } = buildDependencyGraph(jsonData); + + const invalidFiles = validateAgainstVirtualDirectory( + nodes, + this.virtualDir, ); - } - console.log(jsonData); - // validate with virutual dir - const { graph, nodes, fileInfos } = buildDependencyGraph(jsonData); - if (!validateAgainstVirtualDirectory(nodes, this.virtualDir)) { - this.logger.error('Validate Against Virtual Directory Fail !!!'); + if (invalidFiles) { + this.logger.error('Validate Against Virtual Directory Fail !!!'); + this.logger.error(`Invalid files detected:\n${invalidFiles}`); + this.logger.error(`${fileArchContent}`); + this.logger.error(`${fileStructure}`); + throw new ResponseParsingError( + 'Failed to validate against virtualDirectory.', + ); + } + } catch (error) { + this.logger.error('File architecture validation failed.'); throw new ResponseParsingError( - 'Failed to validate against virtualDirectory.', + `File architecture JSON validation failed. ${error.message}`, ); } diff --git a/backend/src/build-system/handlers/file-manager/file-arch/prompt.ts b/backend/src/build-system/handlers/file-manager/file-arch/prompt.ts index 480da7ab..c19f0c02 100644 --- a/backend/src/build-system/handlers/file-manager/file-arch/prompt.ts +++ b/backend/src/build-system/handlers/file-manager/file-arch/prompt.ts @@ -4,18 +4,19 @@ export const generateFileArchPrompt = (): string => { ### Instructions 1. **Analyze the Inputs**: - Use the directory structure to identify all files and folders. + - Do not assume any additional files or paths. The structure must be based exclusively on the given list. - Leverage the page-by-page analysis to understand the roles and interactions of different components and pages. - Determine the role of each file based on its path and the provided analysis (e.g., page, component, context, hook, styles). - Identify direct dependencies for each file by considering typical imports based on roles, naming conventions, and the provided analysis. 2. **Generate File Dependency JSON**: + - Each file must be represented using its full path starting from src/. + - Ensure dependencies are strictly limited to files in the "Paths" array. + - Use absolute file paths from "Paths" for all "dependsOn" values. + Do not use relative paths (./, ../). + Every dependency must match exactly one of the files in "Paths". + - Any file without dependencies should have "dependsOn": []. - For each file, list its direct dependencies as an array of relative paths in the \`dependsOn\` field. - - Use relative paths for dependencies whenever possible. For example: - - If a file \`index.tsx\` references a CSS file \`index.css\` in the same folder, the dependency should be listed as \`"./index.css"\`. - - If a file references another file in its parent folder, use \`"../filename"\`. - - Only use absolute paths (e.g., starting with \`src/\`) when no shorter relative path is available. - - Include CSS/SCSS files as dependencies for any JavaScript or TypeScript files that reference them (e.g., through imports or implied usage). - - Include files that have no dependencies with an empty \`dependsOn\` array. - Organize the output in a \`files\` object where keys are file paths, and values are their dependency objects. - For the router, remember to include all the page components as dependencies, as the router imports them to define the application routes. - For the src/index.tsx, remember to include router.ts. @@ -37,20 +38,18 @@ export const generateFileArchPrompt = (): string => { \`\`\` - Keys: Every file must be represented with its full path, starting from src/. - - Dependencies: - Files with no dependencies must have "dependsOn": []. - Every file except src/index.ts must appear in at least one dependsOn array. - - Use relative paths for dependencies wherever possible (./filename for same-folder dependencies, ../filename for parent-folder dependencies). + - Dependency Rules: + All dependencies must exist in the "Paths" array. + No inferred or assumed files should be added. - Wrap the JSON output with \`\` tags. ### Notes -- **CSS Dependencies**: Any file that relies on a CSS/SCSS module file (e.g., \`Header.module.css\`) must list it in the \`dependsOn\` array. -- **Use Relative Paths When Possible**: Ensure dependencies are listed using the shortest possible path (e.g., \`"./filename"\` for files in the same folder). -- **Dependency Inclusion Rule**: All files, except for \`src/index.ts\`, must be depended upon by at least one other file. This means they should appear in the \`dependsOn\` array of at least one other file. - The \`dependsOn\` field should reflect logical dependencies inferred from both the directory structure and the page-by-page analysis. - Use common project patterns to deduce dependencies (e.g., pages depend on components, contexts, hooks, and styles). - Include all files in the output, even if they have no dependencies. ### Output -Return only the JSON object wrapped in \`\` tags.`; +Return only the JSON object wrapped in \`\` tags. +Do not forget tags. +`; }; diff --git a/backend/src/build-system/handlers/file-manager/file-generate/index.ts b/backend/src/build-system/handlers/file-manager/file-generate/index.ts index 2c45df49..c8f15989 100644 --- a/backend/src/build-system/handlers/file-manager/file-generate/index.ts +++ b/backend/src/build-system/handlers/file-manager/file-generate/index.ts @@ -138,9 +138,9 @@ export class FileGeneratorHandler implements BuildHandler { const currentDir = path.dirname(currentFile); const hasExtension = path.extname(dependency).length > 0; - if (!hasExtension) { - dependency = path.join(dependency, 'index.ts'); - } + // if (!hasExtension) { + // dependency = path.join(dependency, 'index.ts'); + // } const resolvedPath = path.join(currentDir, dependency).replace(/\\/g, '/'); this.logger.log(`Resolved dependency: ${resolvedPath}`); diff --git a/backend/src/build-system/handlers/file-manager/file-structure/index.ts b/backend/src/build-system/handlers/file-manager/file-structure/index.ts index ff760500..18721fe3 100644 --- a/backend/src/build-system/handlers/file-manager/file-structure/index.ts +++ b/backend/src/build-system/handlers/file-manager/file-structure/index.ts @@ -2,7 +2,10 @@ import { BuildHandler, BuildOpts, BuildResult } from 'src/build-system/types'; import { BuilderContext } from 'src/build-system/context'; import { prompts } from './prompt'; import { Logger } from '@nestjs/common'; -import { removeCodeBlockFences } from 'src/build-system/utils/strings'; +import { + parseGenerateTag, + removeCodeBlockFences, +} from 'src/build-system/utils/strings'; import { chatSyncWithClocker } from 'src/build-system/utils/handler-helper'; import { ResponseParsingError, @@ -10,7 +13,6 @@ import { } from 'src/build-system/errors'; import { UXSMDHandler } from '../../ux/sitemap-document'; import { UXDMDHandler } from '../../ux/datamap'; -import { parseGenerateTag } from 'src/build-system/utils/strings'; import { BuildNode, BuildNodeRequire } from 'src/build-system/hanlder-manager'; /** @@ -35,7 +37,7 @@ export class FileStructureHandler implements BuildHandler { const sitemapDoc = context.getNodeData(UXSMDHandler); const datamapDoc = context.getNodeData(UXDMDHandler); // const projectPart = opts?.projectPart ?? 'frontend'; - const projectPart = 'frontend'; + const projectPart = opts?.projectPart ?? 'frontend'; const framework = context.getGlobalContext('framework') ?? 'react'; // Validate required arguments @@ -88,6 +90,7 @@ export class FileStructureHandler implements BuildHandler { }, ]; + // Get the generated file structure content let fileStructureContent: string; try { fileStructureContent = await chatSyncWithClocker( @@ -106,35 +109,19 @@ export class FileStructureHandler implements BuildHandler { ); } } catch (error) { - return { success: false, error }; + this.logger.error( + `Failed to generate file structure: ${error.message}`, + error.stack, + ); + return { + success: false, + error: new ResponseParsingError( + `File structure generation failed. ${error.message}`, + ), + }; } - // Convert the tree structure to JSON - // const convertToJsonPrompt = - // prompts.convertTreeToJsonPrompt(fileStructureContent); - - // let fileStructureJsonContent: string; - // try { - // fileStructureJsonContent = await chatSyncWithClocker( - // context, - // { - // model: 'gpt-4o-mini', - // messages: [{ content: convertToJsonPrompt, role: 'system' }], - // }, - // 'convertToJsonPrompt', - // this.id, - // ); - - // if (!fileStructureJsonContent || fileStructureJsonContent.trim() === '') { - // throw new ResponseParsingError( - // `Generated content is empty during op:FILE:STRUCT 2.`, - // ); - // } - // } catch (error) { - // return { success: false, error }; - // } - - // Build the virtual directory + // Parse the file structure content let fileStructureJsonContent = ''; try { fileStructureJsonContent = parseGenerateTag(fileStructureContent); @@ -142,37 +129,40 @@ export class FileStructureHandler implements BuildHandler { return { success: false, error: new ResponseParsingError( - 'Failed to parse file Structure Json Content.', + `Failed to parse file Structure Json Content. ${error.message}`, ), }; } + // Build the virtual directory + this.logger.log('start building'); try { const successBuild = context.buildVirtualDirectory( fileStructureJsonContent, ); if (!successBuild) { + this.logger.error( + 'Failed to build virtual directory.' + fileStructureJsonContent, + ); throw new ResponseParsingError('Failed to build virtual directory.'); } } catch (error) { - this.logger.error( - 'Non-retryable error during virtual directory build:', - error, - ); return { success: false, - error: new ResponseParsingError('Failed to build virtual directory.'), + error: new ResponseParsingError( + `Failed to build virtual directory. ${error.message}`, + ), }; } - this.logger.log( - `File structure JSON content and virtual directory built successfully. - ${removeCodeBlockFences(fileStructureJsonContent)}`, - ); + //debug script print all files + context.virtualDirectory.getAllFiles().forEach((file) => { + this.logger.log(file); + }); return { success: true, - data: removeCodeBlockFences(fileStructureJsonContent), + data: removeCodeBlockFences(fileStructureContent), }; } diff --git a/backend/src/build-system/handlers/file-manager/file-structure/prompt.ts b/backend/src/build-system/handlers/file-manager/file-structure/prompt.ts index 5c5e3956..3bb1ab72 100644 --- a/backend/src/build-system/handlers/file-manager/file-structure/prompt.ts +++ b/backend/src/build-system/handlers/file-manager/file-structure/prompt.ts @@ -15,49 +15,32 @@ export const prompts = { convertTreeToJsonPrompt: (): string => { return `You are a highly skilled developer. Your task is to convert the previous file and folder structure, currently represented in an ASCII tree format, into a JSON structure. The JSON structure must: - - - Represent directories and files in a hierarchical manner. - - Use objects with "type" and "name" keys. - - For directories: - - "type": "directory" - - "name": "" - - "children": [ ... ] (an array of files or directories) - - For files: - - "type": "file" - - "name": "" - - Maintain the same nesting as the original ASCII tree. - - **Output Format:** - Return a JSON object of the form: - \`\`\`json - { - "type": "directory", - "name": "", - "children": [ - { - "type": "directory", - "name": "subDirName", - "children": [ - { - "type": "file", - "name": "fileName.ext" - } - ] - }, - { - "type": "file", - "name": "anotherFile.ext" - } - ] - } - \`\`\` - - **Additional Rules:** - - Keep directory names and file names exactly as they appear (excluding trailing slashes). - - For directories that appear like "common/", in the JSON just use "common" as the name. - - Do not include comments or extra fields besides "type", "name", and "children". - - The root node should correspond to the top-level directory in the tree. - + + Represent all file paths in a flat list under the "Paths" array. + Maintain the full paths for each file exactly as they appear in the ASCII tree. + Directories should not be included—only file paths. + +Output Format: +Return a JSON object in the following format: +Surround the JSON object with tags. + + +{ + "Paths": [ + "/full/path/to/file1.ext", + "/full/path/to/file2.ext", + "/another/path/to/file3.ext" + ] +} + + +Additional Rules: + + Maintain the original directory structure but only return files in the JSON output. + Keep file names and paths exactly as they appear in the ASCII tree. + Remeber to start with src/ as the root directory (src/...). + The root node should correspond to the top-level directory in the tree. + Do not include comments or extra fields besides "Paths". Return only the JSON structure (no explanations, no additional comments). This JSON will be used directly in the application. `; }, @@ -79,26 +62,30 @@ export const prompts = { roleDescription = 'an expert frontend developer'; includeSections = ` Folder Structure: - components: Reusable UI elements grouped by category (e.g., common, layout, specific). - contexts: Global state management (e.g., auth, theme, player). - hooks: Custom hooks for data fetching and state management. - pages: Route-specific views (e.g., Home, Search, Playlist). - utils: Utility functions (e.g., constants, helpers, validators). - apis: Organized API logic (e.g., auth, music, user). - router.ts: Central routing configuration. - index.tsx: Application entry point. + src: Main source code folder. + components: Reusable UI elements grouped by category (e.g., common, layout, specific). + contexts: Global state management (e.g., auth, theme, player). + hooks: Custom hooks for data fetching and state management. + pages: Route-specific views (e.g., Home, Search, Playlist). + utils: Utility functions (e.g., constants, helpers, validators). + apis: Organized API logic (e.g., auth, music, user). + router.ts: Central routing configuration. + index.tsx: Application entry point. `; excludeSections = ` Do Not Include: Asset folders (e.g., images, icons, fonts). Test folders or files. Service folders unrelated to API logic. - Dont need .css files. + .css files. `; fileNamingGuidelines = ` - File Naming Guidelines: + File and Folder Naming Guidelines: Use meaningful and descriptive file names. + Do NOT use page_view_* and global_view_* prefixes for folder or file names. + For components, include an index.tsx file in each folder to simplify imports. Each component should have its own folder named after the component (e.g., Button/). + Use index.tsx as the main file inside the component folder. `; break; diff --git a/backend/src/build-system/utils/file_generator_util.ts b/backend/src/build-system/utils/file_generator_util.ts index e73c007b..d6d6f1af 100644 --- a/backend/src/build-system/utils/file_generator_util.ts +++ b/backend/src/build-system/utils/file_generator_util.ts @@ -22,6 +22,10 @@ interface GenerateFilesDependencyLayerResult { const logger = new Logger('FileGeneratorUtil'); +/** + * Generate Files Dependency With Layers. + * This function is mainly use for files generate. + */ export async function generateFilesDependencyWithLayers( jsonString: string, virtualDirectory: VirtualDirectory, @@ -38,9 +42,6 @@ export async function generateFilesDependencyWithLayers( // 4. Build concurrency layers with Kahn’s Algorithm const concurrencyLayers = buildConcurrencyLayers(nodes, fileInfos); - // Optionally check for cycles (if you didn’t do it inside buildConcurrencyLayers) - // detectCycles(...) or similar - logger.log('All files dependency layers generated successfully.'); return { @@ -69,40 +70,14 @@ function buildDependencyLayerGraph(jsonData: { // In the JSON, "dependsOn" is an array of file paths details.dependsOn.forEach((dep) => { - const resolvedDep = resolveDependency(fileName, dep); - nodes.add(resolvedDep); - - fileInfos[fileName].dependsOn.push(resolvedDep); + nodes.add(dep); + fileInfos[fileName].dependsOn.push(dep); }); }); return { fileInfos, nodes }; } -/** - * Generates files based on JSON extracted from a Markdown document. - * Ensures dependency order is maintained during file creation. - */ -export async function generateFilesDependency( - markdownContent: string, - virtualDirectory: VirtualDirectory, -): Promise { - const jsonData = extractJsonFromMarkdown(markdownContent); - - const { graph, nodes, fileInfos } = buildDependencyGraph(jsonData); - detectCycles(graph); - validateAgainstVirtualDirectory(nodes, virtualDirectory); - - const sortedFiles = getSortedFiles(graph, nodes); - - logger.log('All files dependency generated successfully.'); - - return { - sortedFiles, - fileInfos, - }; -} - /** * Constructs a dependency graph from the provided JSON structure. * Each file entry includes dependencies that must be resolved first. @@ -131,18 +106,41 @@ export function buildDependencyGraph(jsonData: { }; details.dependsOn.forEach((dep) => { - const resolvedDep = resolveDependency(fileName, dep); - graph.push([resolvedDep, fileName]); // [dependency, dependent] - nodes.add(resolvedDep); + graph.push([dep, fileName]); // [dependency, dependent] + nodes.add(dep); // store dependsOn - fileInfos[fileName].dependsOn.push(resolvedDep); + fileInfos[fileName].dependsOn.push(dep); }); }); return { graph, nodes, fileInfos }; } +/** + * Generates files based on JSON extracted from a Markdown document. + * Ensures dependency order is maintained during file creation. + */ +export async function generateFilesDependency( + markdownContent: string, + virtualDirectory: VirtualDirectory, +): Promise { + const jsonData = extractJsonFromMarkdown(markdownContent); + + const { graph, nodes, fileInfos } = buildDependencyGraph(jsonData); + detectCycles(graph); + validateAgainstVirtualDirectory(nodes, virtualDirectory); + + const sortedFiles = getSortedFiles(graph, nodes); + + logger.log('All files dependency generated successfully.'); + + return { + sortedFiles, + fileInfos, + }; +} + /** * Detects cycles in the dependency graph to prevent infinite loops. */ @@ -186,11 +184,6 @@ export function resolveDependency( dependency: string, ): string { const currentDir = path.dirname(currentFile); - const hasExtension = path.extname(dependency).length > 0; - - if (!hasExtension) { - dependency = path.join(dependency, 'index.ts'); - } const resolvedPath = path.join(currentDir, dependency).replace(/\\/g, '/'); logger.log(`Resolved dependency: ${resolvedPath}`); @@ -207,7 +200,7 @@ export function validateAgainstVirtualDirectory( const invalidFiles: string[] = []; nodes.forEach((filePath) => { - if (!virtualDir.isValidFile(filePath)) { + if (!virtualDir.hasFile(filePath)) { invalidFiles.push(filePath); } }); diff --git a/backend/src/build-system/virtual-dir/index.ts b/backend/src/build-system/virtual-dir/index.ts index 71e41bfc..ec64a45a 100644 --- a/backend/src/build-system/virtual-dir/index.ts +++ b/backend/src/build-system/virtual-dir/index.ts @@ -1,140 +1,158 @@ import { Logger } from '@nestjs/common'; -import normalizePath from 'normalize-path'; -import * as path from 'path'; - -interface VirtualNode { - name: string; - isFile: boolean; - children: Map; -} - -interface FileStructureNode { - type: 'file' | 'directory'; - name: string; - children?: FileStructureNode[]; -} export class VirtualDirectory { - private root: VirtualNode; - - constructor() { - this.root = { - name: 'src', - isFile: false, - children: new Map(), - }; - } + private filePaths: Set = new Set(); - private cleanJsonContent(content: string): string { - const jsonStart = content.indexOf('{'); - const jsonEnd = content.lastIndexOf('}'); - return content.slice(jsonStart, jsonEnd + 1); - } + private readonly logger: Logger = new Logger('VirtualDirectory'); public parseJsonStructure(jsonContent: string): boolean { try { const cleanedJson = this.cleanJsonContent(jsonContent); const structure = JSON.parse(cleanedJson); - this.buildTree(structure, this.root); + if (!Array.isArray(structure.Paths)) { + this.logger.error('Invalid JSON format: "Paths" should be an array.'); + return false; + } + + this.filePaths = new Set(structure.Paths); return true; } catch (error) { - Logger.error('Failed to parse JSON structure:', error); + this.logger.error('Failed to parse JSON structure:', error); return false; } } - private buildTree(node: FileStructureNode, virtualNode: VirtualNode): void { - if (node.children) { - for (const child of node.children) { - const newNode: VirtualNode = { - name: child.name, - isFile: child.type === 'file', - children: new Map(), - }; - virtualNode.children.set(child.name, newNode); - - if (child.type === 'directory' && child.children) { - this.buildTree(child, newNode); - } - } - } - } - - public isValidFile(filePath: string): boolean { - const node = this.findNode(filePath); - return node?.isFile ?? false; - } - - isValidDirectory(dirPath: string): boolean { - const node = this.findNode(dirPath); - return node !== null && !node.isFile; - } - - // private findNode(inputPath: string): VirtualNode | null { - // const normalizedPath = this.normalizePath(inputPath); - // const parts = normalizedPath.split('/').filter(Boolean); - - // if (parts[0] !== 'src') { - // return null; - // } - - // let current = this.root; - // for (let i = 1; i < parts.length; i++) { - // const next = current.children.get(parts[i]); - // if (!next) return null; - // current = next; - // } - // return current; - // } - - private findNode(inputPath: string): VirtualNode | null { - const normalizedPath = this.normalizePath(inputPath); - const parts = normalizedPath.split('/').filter(Boolean); - - if (parts.length === 0) { - return null; - } - - // Ensure consistent handling by always requiring 'src' prefix - if (parts[0] !== 'src') { - return null; - } - - parts.shift(); - - let current = this.root; - for (const part of parts) { - const next = current.children.get(part); - if (!next) return null; - current = next; - } - return current; - } - - private normalizePath(inputPath: string): string { - return normalizePath(inputPath); + private cleanJsonContent(jsonContent: string): string { + return jsonContent.trim(); } - resolveRelativePath(fromFile: string, toPath: string): string { - const fromDir = path.dirname(fromFile); - const resolvedPath = path.join(fromDir, toPath).replace(/\\/g, '/'); - return this.normalizePath(resolvedPath); + public hasFile(filePath: string): boolean { + return this.filePaths.has(filePath); } - getAllFiles(): string[] { - const files: string[] = []; - - const traverse = (node: VirtualNode, parentPath: string = '') => { - for (const [name, child] of node.children) { - const currentPath = parentPath ? `${parentPath}/${name}` : name; - if (child.isFile) { - files.push(`src/${currentPath}`); - } - traverse(child, currentPath); - } - }; - - traverse(this.root); - return files.sort(); + public getAllFiles(): string[] { + return Array.from(this.filePaths); } } + +// ---------------------------------- Virtual Directory legacy code for tree stucture---------------------------------- + +// interface VirtualNode { +// name: string; +// isFile: boolean; +// children: Map; +// } + +// interface FileStructureNode { +// type: 'file' | 'directory'; +// name: string; +// children?: FileStructureNode[]; +// } + +// export class VirtualDirectory { +// private root: VirtualNode; + +// constructor() { +// this.root = { +// name: 'src', +// isFile: false, +// children: new Map(), +// }; +// } + +// private cleanJsonContent(content: string): string { +// const jsonStart = content.indexOf('{'); +// const jsonEnd = content.lastIndexOf('}'); +// return content.slice(jsonStart, jsonEnd + 1); +// } + +// public parseJsonStructure(jsonContent: string): boolean { +// try { +// const cleanedJson = this.cleanJsonContent(jsonContent); +// const structure = JSON.parse(cleanedJson); +// this.buildTree(structure, this.root); +// return true; +// } catch (error) { +// Logger.error('Failed to parse JSON structure:', error); +// return false; +// } +// } + +// private buildTree(node: FileStructureNode, virtualNode: VirtualNode): void { +// if (node.children) { +// for (const child of node.children) { +// const newNode: VirtualNode = { +// name: child.name, +// isFile: child.type === 'file', +// children: new Map(), +// }; +// virtualNode.children.set(child.name, newNode); + +// if (child.type === 'directory' && child.children) { +// this.buildTree(child, newNode); +// } +// } +// } +// } + +// public isValidFile(filePath: string): boolean { +// const node = this.findNode(filePath); +// return node?.isFile ?? false; +// } + +// isValidDirectory(dirPath: string): boolean { +// const node = this.findNode(dirPath); +// return node !== null && !node.isFile; +// } + +// private findNode(inputPath: string): VirtualNode | null { +// const normalizedPath = this.normalizePath(inputPath); +// const parts = normalizedPath.split('/').filter(Boolean); + +// if (parts.length === 0) { +// return null; +// } + +// // Ensure consistent handling by always requiring 'src' prefix +// if (parts[0] !== 'src') { +// return null; +// } + +// parts.shift(); + +// let current = this.root; +// for (const part of parts) { +// const next = current.children.get(part); +// if (!next) return null; +// current = next; +// } +// return current; +// } + +// private normalizePath(inputPath: string): string { +// return normalizePath(inputPath); +// } + +// resolveRelativePath(fromFile: string, toPath: string): string { +// const fromDir = path.dirname(fromFile); +// const resolvedPath = path.join(fromDir, toPath).replace(/\\/g, '/'); +// return this.normalizePath(resolvedPath); +// } + +// getAllFiles(): string[] { +// const files: string[] = []; + +// const traverse = (node: VirtualNode, parentPath: string = '') => { +// for (const [name, child] of node.children) { +// const currentPath = parentPath ? `${parentPath}/${name}` : name; +// if (child.isFile) { +// files.push(`src/${currentPath}`); +// } +// traverse(child, currentPath); +// } +// }; + +// traverse(this.root); +// return files.sort(); +// } +// }