@vibe-dev-kit/cli
Version:
Advanced Command-line toolkit that analyzes your codebase and deploys project-aware rules, memories, commands and agents to any AI coding assistant - VDK is the world's first Vibe Development Kit
195 lines (169 loc) • 6.66 kB
JavaScript
/**
* Light Templating Utility
* ------------------------
* Provides simple, fast string interpolation as an alternative to Handlebars.
* Uses ${variable} syntax for project-specific customization of rules.
*
* Benefits over Handlebars:
* - 10x faster performance (no compilation step)
* - Simple syntax, no complex logic
* - Compatible with existing remote .mdc rules
* - No dependency on external templating libraries
*/
/**
* Applies light templating to content using ${variable} syntax
* @param {string} content - Content to template
* @param {Object} variables - Variables to substitute
* @returns {string} Templated content
*/
export function applyLightTemplating(content, variables = {}) {
if (!content || typeof content !== 'string') {
return content;
}
// Simple string replacement for ${variable} patterns
return content.replace(/\$\{([^}]+)\}/g, (match, variableName) => {
const value = getNestedValue(variables, variableName.trim());
return value !== undefined ? value : match; // Keep original if not found
});
}
/**
* Gets nested object values using dot notation (e.g., 'project.name')
* @param {Object} obj - Object to search
* @param {string} path - Dot notation path
* @returns {*} Value or undefined
*/
function getNestedValue(obj, path) {
return path.split('.').reduce((current, key) => {
return current && current[key] !== undefined ? current[key] : undefined;
}, obj);
}
/**
* Prepares common template variables from analysis data
* @param {Object} analysisData - Analysis data from project scanning
* @returns {Object} Template variables
*/
export function prepareTemplateVariables(analysisData) {
const projectStructure = analysisData.projectStructure || {};
const techData = analysisData.technologyData || {};
const patterns = analysisData.patterns || {};
return {
// Project basics
projectName: getProjectName(projectStructure),
projectPath: projectStructure.root || process.cwd(),
projectType: determineProjectType(techData),
// Technology stack
primaryLanguage: techData.primaryLanguage || 'Unknown',
languages: techData.languages || [],
frameworks: techData.frameworks || [],
libraries: techData.libraries || [],
// Architecture patterns
architecturalPattern: patterns.architecturalPatterns?.[0]?.name || 'Unknown',
patterns: patterns.architecturalPatterns || [],
// Project structure
hasTests: hasTestDirectory(projectStructure),
hasComponents: hasComponentsDirectory(projectStructure),
hasDocs: hasDocsDirectory(projectStructure),
// Version info
version: getProjectVersion(techData),
nodeVersion: techData.nodeVersion,
// Common paths
srcPath: findSourceDirectory(projectStructure),
testPath: findTestDirectory(projectStructure),
docsPath: findDocsDirectory(projectStructure),
// Utilities for templates
join: (array, separator = ', ') => (Array.isArray(array) ? array.join(separator) : ''),
capitalize: (str) => (str ? str.charAt(0).toUpperCase() + str.slice(1) : ''),
lowercase: (str) => (str ? str.toLowerCase() : ''),
};
}
/**
* Helper functions for template variable preparation
*/
function getProjectName(projectStructure) {
// Try to get from package.json, fallback to directory name
const packageJson = projectStructure.packageJson;
if (packageJson && packageJson.name) {
return packageJson.name;
}
const root = projectStructure.root || process.cwd();
return root.split('/').pop() || 'UnknownProject';
}
function determineProjectType(techData) {
const frameworks = techData.frameworks || [];
const libraries = techData.libraries || [];
if (frameworks.includes('React') || libraries.includes('react')) return 'React App';
if (frameworks.includes('Vue') || libraries.includes('vue')) return 'Vue App';
if (frameworks.includes('Angular') || libraries.includes('@angular/core')) return 'Angular App';
if (frameworks.includes('Next.js') || libraries.includes('next')) return 'Next.js App';
if (frameworks.includes('Express') || libraries.includes('express')) return 'Express API';
if (frameworks.includes('Django')) return 'Django App';
if (frameworks.includes('Rails')) return 'Rails App';
return 'Application';
}
function hasTestDirectory(projectStructure) {
const directories = projectStructure.directories || [];
return directories.some((dir) => /^(test|tests|__tests__|spec|specs)$/i.test(dir.name));
}
function hasComponentsDirectory(projectStructure) {
const directories = projectStructure.directories || [];
return directories.some(
(dir) => /^(components|component)$/i.test(dir.name) || dir.path.includes('/components/')
);
}
function hasDocsDirectory(projectStructure) {
const directories = projectStructure.directories || [];
return directories.some((dir) => /^(docs|doc|documentation)$/i.test(dir.name));
}
function getProjectVersion(techData) {
const packageJson = techData.packageJson;
return packageJson && packageJson.version ? packageJson.version : '1.0.0';
}
function findSourceDirectory(projectStructure) {
const directories = projectStructure.directories || [];
const srcDir = directories.find((dir) => /^(src|source|lib|app)$/i.test(dir.name));
return srcDir ? srcDir.path : './src';
}
function findTestDirectory(projectStructure) {
const directories = projectStructure.directories || [];
const testDir = directories.find((dir) => /^(test|tests|__tests__|spec|specs)$/i.test(dir.name));
return testDir ? testDir.path : './test';
}
function findDocsDirectory(projectStructure) {
const directories = projectStructure.directories || [];
const docsDir = directories.find((dir) => /^(docs|doc|documentation)$/i.test(dir.name));
return docsDir ? docsDir.path : './docs';
}
/**
* Template helper functions for processing template variables
*/
export const templateHelpers = {
capitalize: (str) => (str ? str.charAt(0).toUpperCase() + str.slice(1) : ''),
lowercase: (str) => (str ? str.toLowerCase() : ''),
join: (array, separator = ', ') => (Array.isArray(array) ? array.join(separator) : ''),
ifCond: (v1, operator, v2) => {
switch (operator) {
case '==':
return v1 == v2;
case '===':
return v1 === v2;
case '!=':
return v1 != v2;
case '!==':
return v1 !== v2;
case '<':
return v1 < v2;
case '<=':
return v1 <= v2;
case '>':
return v1 > v2;
case '>=':
return v1 >= v2;
case '&&':
return v1 && v2;
case '||':
return v1 || v2;
default:
return false;
}
},
};