diff options
Diffstat (limited to 'tree-sitter/dsk/dsk-cli/src/utils/template-processor.ts')
-rw-r--r-- | tree-sitter/dsk/dsk-cli/src/utils/template-processor.ts | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/tree-sitter/dsk/dsk-cli/src/utils/template-processor.ts b/tree-sitter/dsk/dsk-cli/src/utils/template-processor.ts new file mode 100644 index 0000000..e237048 --- /dev/null +++ b/tree-sitter/dsk/dsk-cli/src/utils/template-processor.ts @@ -0,0 +1,192 @@ +/** + * Template Processor + * + * Processes template files by replacing placeholders with actual values + */ + +import { readFileSync, writeFileSync, readdirSync, statSync, mkdirSync, copyFileSync } from 'fs'; +import { join, dirname, basename, extname } from 'path'; +import { LanguageArchitecture, LanguageFeatures, LanguageSyntax } from '../commands/new.js'; + +export interface TemplateContext { + architecture: LanguageArchitecture; + features: LanguageFeatures; + syntax: LanguageSyntax; +} + +/** + * Process a template directory and create a project + */ +export function processTemplate( + templateDir: string, + outputDir: string, + context: TemplateContext +): void { + // Create output directory + mkdirSync(outputDir, { recursive: true }); + + // Process all files in template directory + processDirectory(templateDir, outputDir, context); +} + +/** + * Process a directory recursively + */ +function processDirectory( + sourceDir: string, + targetDir: string, + context: TemplateContext +): void { + const items = readdirSync(sourceDir); + + for (const item of items) { + const sourcePath = join(sourceDir, item); + const targetPath = join(targetDir, processFileName(item, context)); + + const stat = statSync(sourcePath); + + if (stat.isDirectory()) { + mkdirSync(targetPath, { recursive: true }); + processDirectory(sourcePath, targetPath, context); + } else { + processFile(sourcePath, targetPath, context); + } + } +} + +/** + * Process a single file + */ +function processFile( + sourcePath: string, + targetPath: string, + context: TemplateContext +): void { + const content = readFileSync(sourcePath, 'utf-8'); + const processedContent = processContent(content, context); + + // Ensure target directory exists + mkdirSync(dirname(targetPath), { recursive: true }); + + writeFileSync(targetPath, processedContent, 'utf-8'); +} + +/** + * Process file name placeholders + */ +function processFileName(fileName: string, context: TemplateContext): string { + const replacements = getReplacements(context); + + let processed = fileName; + for (const [placeholder, value] of Object.entries(replacements)) { + processed = processed.replace(new RegExp(placeholder, 'g'), value); + } + + return processed; +} + +/** + * Process file content placeholders + */ +function processContent(content: string, context: TemplateContext): string { + const replacements = getReplacements(context); + + let processed = content; + for (const [placeholder, value] of Object.entries(replacements)) { + processed = processed.replace(new RegExp(placeholder, 'g'), value); + } + + return processed; +} + +/** + * Get all placeholder replacements + */ +function getReplacements(context: TemplateContext): Record<string, string> { + const { architecture, features, syntax } = context; + + return { + '__DSL_NAME__': architecture.name, + '__PARADIGM__': architecture.paradigm, + '__PURPOSE__': architecture.purpose, + '__DATA_PHILOSOPHY__': architecture.dataPhilosophy, + + // Syntax elements + '__VARIABLE_KEYWORD__': syntax.variables.keyword, + '__ASSIGNMENT_OPERATOR__': syntax.variables.operator, + '__TERMINATOR__': syntax.variables.terminator, + '__VARIABLE_EXAMPLE__': syntax.variables.example, + + '__COMMENT_EXAMPLE__': syntax.comments.pattern, + '__STRING_EXAMPLE__': syntax.strings.examples[0] || '"hello"', + '__NUMBER_EXAMPLE__': syntax.numbers.examples[0] || '42', + '__IDENTIFIER_EXAMPLE__': syntax.identifiers.examples[0] || 'myVar', + + // Paradigm-specific examples + '__PARADIGM_EXAMPLE__': getParadigmExample(architecture, syntax), + + // File extension + '__EXT__': getFileExtension(architecture.name), + + // Feature lists + '__FEATURES_LIST__': generateFeaturesList(features), + '__DATA_STRUCTURES__': features.dataStructures.join(', ') || 'Basic types', + + // Control flow + '__CONTROL_FLOW__': features.controlFlow.join(', ') || 'Sequential execution' + }; +} + +/** + * Get paradigm-specific example code + */ +function getParadigmExample(architecture: LanguageArchitecture, syntax: LanguageSyntax): string { + if (syntax.paradigmExamples.class) { + return syntax.paradigmExamples.class; + } + if (syntax.paradigmExamples.function) { + return syntax.paradigmExamples.function; + } + if (syntax.paradigmExamples.rule) { + return syntax.paradigmExamples.rule; + } + + // Fallback to variable example + return syntax.variables.example; +} + +/** + * Get appropriate file extension for the language + */ +function getFileExtension(languageName: string): string { + // Simple heuristic - could be made configurable + const name = languageName.toLowerCase(); + + if (name.includes('script')) return 'script'; + if (name.includes('lang')) return 'lang'; + if (name.includes('dsl')) return 'dsl'; + + // Default: use first 3 characters of name + return name.substring(0, 3); +} + +/** + * Generate features list for README + */ +function generateFeaturesList(features: LanguageFeatures): string { + const items: string[] = []; + + if (features.controlFlow.length > 0) { + items.push(`- **Control Flow**: ${features.controlFlow.join(', ')}`); + } + + if (features.dataStructures.length > 0) { + items.push(`- **Data Structures**: ${features.dataStructures.join(', ')}`); + } + + if (features.functionTypes.length > 0) { + items.push(`- **Functions**: ${features.functionTypes.join(', ')}`); + } + + return items.length > 0 ? items.join('\n') : '- Basic language constructs'; +} |