markpage
Version:
Build and manage markdown-based content with distributed navigation - framework agnostic content management system
1 lines • 20.2 kB
Source Map (JSON)
{"version":3,"file":"parser.cjs","sources":["../../src/builder/parser.ts"],"sourcesContent":["import { readFileSync, readdirSync, statSync, existsSync } from 'fs';\nimport { join, relative } from 'path';\nimport { validateIndexFile, NavigationItem, DocItem } from '../types.js';\n\nexport class ParserError extends Error {\n constructor(message: string, public filePath?: string) {\n super(message);\n this.name = 'ParserError';\n }\n}\n\nexport interface ParseOptions {\n basePath?: string;\n validateFiles?: boolean;\n autoDiscover?: boolean;\n}\n\nexport function parseIndexFile(filePath: string): DocItem[] {\n try {\n const content = readFileSync(filePath, 'utf-8');\n const data = JSON.parse(content);\n \n if (!validateIndexFile(data)) {\n throw new ParserError(\n `Invalid .index.json format: Invalid data structure`,\n filePath\n );\n }\n \n return data.items;\n } catch (error) {\n if (error instanceof ParserError) {\n throw error;\n }\n \n if (error instanceof SyntaxError) {\n throw new ParserError(\n `Invalid JSON in .index.json: ${error.message}`,\n filePath\n );\n }\n \n throw new ParserError(\n `Failed to read .index.json: ${error instanceof Error ? error.message : 'Unknown error'}`,\n filePath\n );\n }\n}\n\n/**\n * Auto-discovers content in a directory when no .index.json is present\n */\nfunction autoDiscoverContent(dirPath: string): DocItem[] {\n try {\n const items = readdirSync(dirPath, { withFileTypes: true });\n const discoveredItems: DocItem[] = [];\n \n // Filter and sort items\n const markdownFiles = items\n .filter(item => item.isFile() && item.name.endsWith('.md'))\n .map(item => ({ ...item, name: item.name.slice(0, -3) })) // Remove .md extension\n .sort((a, b) => a.name.localeCompare(b.name));\n \n const directories = items\n .filter(item => item.isDirectory() && !item.name.startsWith('.'))\n .sort((a, b) => a.name.localeCompare(b.name));\n \n // Add markdown files as pages, but exclude index.md and README.md\n for (const file of markdownFiles) {\n // Skip index.md and README.md as they will be handled as section roots\n if (file.name.toLowerCase() !== 'index' && file.name.toLowerCase() !== 'readme') {\n discoveredItems.push({\n name: file.name,\n type: 'page',\n label: generateLabel(file.name)\n });\n }\n }\n \n // Add directories as sections\n for (const dir of directories) {\n discoveredItems.push({\n name: dir.name,\n type: 'section',\n label: generateLabel(dir.name)\n });\n }\n \n return discoveredItems;\n } catch (error) {\n throw new ParserError(\n `Failed to auto-discover content in directory: ${error instanceof Error ? error.message : 'Unknown error'}`,\n dirPath\n );\n }\n}\n\n/**\n * Generates a human-readable label from a filename/directory name\n */\nfunction generateLabel(name: string): string {\n return name\n .replace(/[-_]/g, ' ') // Replace hyphens and underscores with spaces\n .replace(/\\b\\w/g, l => l.toUpperCase()) // Capitalize first letter of each word\n .trim();\n}\n\n/**\n * Checks if a directory has an .index.json file\n */\nfunction hasIndexFile(dirPath: string): boolean {\n try {\n const indexPath = join(dirPath, '.index.json');\n return statSync(indexPath).isFile();\n } catch {\n return false;\n }\n}\n\nexport function buildNavigationTree(\n contentPath: string,\n options: ParseOptions = {}\n): NavigationItem[] {\n const { basePath = contentPath, validateFiles = true, autoDiscover = true } = options;\n \n try {\n if (!statSync(contentPath).isDirectory()) {\n throw new ParserError(`Content path is not a directory: ${contentPath}`);\n }\n } catch (error) {\n if (error instanceof ParserError) {\n throw error;\n }\n throw new ParserError(`Content path does not exist: ${contentPath}`, contentPath);\n }\n \n const rootIndexPath = join(contentPath, '.index.json');\n let rootItems: DocItem[];\n \n // Check if .index.json exists\n const hasIndex = hasIndexFile(contentPath);\n \n if (hasIndex) {\n // Use existing .index.json\n try {\n rootItems = parseIndexFile(rootIndexPath);\n } catch (error) {\n if (error instanceof ParserError) {\n throw error;\n }\n throw new ParserError(`Root .index.json not found: ${rootIndexPath}`, rootIndexPath);\n }\n } else if (autoDiscover) {\n // Auto-discover content\n rootItems = autoDiscoverContent(contentPath);\n } else {\n // Auto-discovery disabled and no .index.json\n throw new ParserError(`Root .index.json not found: ${rootIndexPath}`, rootIndexPath);\n }\n \n const navigationItems: NavigationItem[] = [];\n \n for (const item of rootItems) {\n const navigationItem = processNavigationItem(\n item,\n contentPath,\n basePath,\n validateFiles,\n autoDiscover\n );\n navigationItems.push(navigationItem);\n }\n \n return navigationItems;\n}\n\nfunction processNavigationItem(\n item: DocItem,\n currentPath: string,\n basePath: string,\n validateFiles: boolean,\n autoDiscover: boolean\n): NavigationItem {\n const navigationItem: NavigationItem = { ...item };\n \n if (item.type === 'section') {\n const sectionPath = join(currentPath, item.name);\n \n // Check if section has .index.json\n if (hasIndexFile(sectionPath)) {\n // Use existing .index.json\n const sectionIndexPath = join(sectionPath, '.index.json');\n \n if (validateFiles) {\n try {\n if (!statSync(sectionIndexPath).isFile()) {\n throw new ParserError(\n `Section .index.json not found: ${sectionIndexPath}`,\n sectionIndexPath\n );\n }\n } catch (error) {\n if (error instanceof ParserError) {\n throw error;\n }\n throw new ParserError(\n `Section .index.json not found: ${sectionIndexPath}`,\n sectionIndexPath\n );\n }\n }\n \n try {\n const sectionItems = parseIndexFile(sectionIndexPath);\n navigationItem.items = sectionItems.map(subItem =>\n processNavigationItem(subItem, sectionPath, basePath, validateFiles, autoDiscover)\n );\n } catch (error) {\n if (error instanceof ParserError) {\n throw error;\n }\n throw new ParserError(\n `Failed to process section ${item.name}: ${error instanceof Error ? error.message : 'Unknown error'}`,\n sectionIndexPath\n );\n }\n } else if (autoDiscover) {\n // Auto-discover section content\n try {\n const sectionItems = autoDiscoverContent(sectionPath);\n navigationItem.items = sectionItems.map(subItem =>\n processNavigationItem(subItem, sectionPath, basePath, validateFiles, autoDiscover)\n );\n } catch (error) {\n if (error instanceof ParserError) {\n throw error;\n }\n throw new ParserError(\n `Failed to auto-discover section ${item.name}: ${error instanceof Error ? error.message : 'Unknown error'}`,\n sectionPath\n );\n }\n } else {\n // Auto-discovery disabled and no .index.json\n const sectionIndexPath = join(sectionPath, '.index.json');\n throw new ParserError(\n `Section .index.json not found: ${sectionIndexPath}`,\n sectionIndexPath\n );\n }\n \n // Check for index.md or README.md as section root (for all sections, regardless of .index.json)\n const indexPath = join(sectionPath, 'index.md');\n const readmePath = join(sectionPath, 'README.md');\n const readmeLowerPath = join(sectionPath, 'readme.md');\n \n let sectionRootPath: string | undefined;\n \n // Priority: index.md > README.md > readme.md\n if (validateFiles) {\n // When validating files, check each one individually\n try {\n if (statSync(indexPath).isFile()) {\n sectionRootPath = indexPath;\n }\n } catch {\n // index.md doesn't exist, try README.md\n try {\n if (statSync(readmePath).isFile()) {\n sectionRootPath = readmePath;\n }\n } catch {\n // README.md doesn't exist, try readme.md\n try {\n if (statSync(readmeLowerPath).isFile()) {\n sectionRootPath = readmeLowerPath;\n }\n } catch {\n // readme.md doesn't exist, continue without section root\n }\n }\n }\n } else {\n // If not validating files, just check if they exist\n if (existsSync(indexPath)) {\n sectionRootPath = indexPath;\n } else if (existsSync(readmePath)) {\n sectionRootPath = readmePath;\n } else if (existsSync(readmeLowerPath)) {\n sectionRootPath = readmeLowerPath;\n }\n }\n \n if (sectionRootPath) {\n navigationItem.path = relative(basePath, sectionRootPath);\n }\n } else if (item.type === 'page') {\n const pagePath = join(currentPath, `${item.name}.md`);\n const relativePath = relative(basePath, pagePath);\n \n if (validateFiles) {\n try {\n if (!statSync(pagePath).isFile()) {\n throw new ParserError(\n `Page markdown file not found: ${pagePath}`,\n pagePath\n );\n }\n } catch (error) {\n if (error instanceof ParserError) {\n throw error;\n }\n throw new ParserError(\n `Page markdown file not found: ${pagePath}`,\n pagePath\n );\n }\n }\n \n navigationItem.path = relativePath;\n }\n \n return navigationItem;\n}\n\nexport function validateContentStructure(contentPath: string, options: ParseOptions = {}): void {\n const { autoDiscover = true } = options;\n const errors: string[] = [];\n \n function validateDirectory(dirPath: string, depth = 0): void {\n if (depth > 10) {\n errors.push(`Maximum directory depth exceeded: ${dirPath}`);\n return;\n }\n \n const indexPath = join(dirPath, '.index.json');\n \n // Check if .index.json exists\n if (hasIndexFile(dirPath)) {\n // Validate using .index.json\n try {\n const items = parseIndexFile(indexPath);\n \n for (const item of items) {\n if (item.type === 'section') {\n const sectionPath = join(dirPath, item.name);\n \n try {\n if (!statSync(sectionPath).isDirectory()) {\n errors.push(`Section directory not found: ${sectionPath}`);\n continue;\n }\n } catch (error) {\n errors.push(`Section directory not found: ${sectionPath}`);\n continue;\n }\n \n validateDirectory(sectionPath, depth + 1);\n } else if (item.type === 'page') {\n const pagePath = join(dirPath, `${item.name}.md`);\n \n try {\n if (!statSync(pagePath).isFile()) {\n errors.push(`Page markdown file not found: ${pagePath}`);\n }\n } catch (error) {\n errors.push(`Page markdown file not found: ${pagePath}`);\n }\n }\n }\n } catch (error) {\n errors.push(`Failed to parse ${indexPath}: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n } else if (autoDiscover) {\n // Validate auto-discovered content\n try {\n const items = autoDiscoverContent(dirPath);\n \n for (const item of items) {\n if (item.type === 'section') {\n const sectionPath = join(dirPath, item.name);\n \n try {\n if (!statSync(sectionPath).isDirectory()) {\n errors.push(`Section directory not found: ${sectionPath}`);\n continue;\n }\n } catch (error) {\n errors.push(`Section directory not found: ${sectionPath}`);\n continue;\n }\n \n validateDirectory(sectionPath, depth + 1);\n } else if (item.type === 'page') {\n const pagePath = join(dirPath, `${item.name}.md`);\n \n try {\n if (!statSync(pagePath).isFile()) {\n errors.push(`Page markdown file not found: ${pagePath}`);\n }\n } catch (error) {\n errors.push(`Page markdown file not found: ${pagePath}`);\n }\n }\n }\n } catch (error) {\n errors.push(`Failed to auto-discover content in ${dirPath}: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n } else {\n // Auto-discovery disabled and no .index.json\n errors.push(`Missing .index.json: ${indexPath}`);\n return;\n }\n }\n \n validateDirectory(contentPath);\n \n if (errors.length > 0) {\n throw new ParserError(\n `Content structure validation failed:\\n${errors.join('\\n')}`,\n contentPath\n );\n }\n}"],"names":["readFileSync","validateIndexFile","readdirSync","join","statSync","existsSync","relative"],"mappings":"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"}