Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 09:04:14 +08:00
commit 70c36b5eff
248 changed files with 47482 additions and 0 deletions

View File

@@ -0,0 +1,250 @@
/**
* Template Helper Functions for Gluegun
* Useful utilities for EJS templates
*/
/**
* String case conversions
*/
export const caseConverters = {
/**
* Convert to PascalCase
* Example: "hello-world" => "HelloWorld"
*/
pascalCase: (str: string): string => {
return str
.replace(/[-_\s](.)/g, (_, char) => char.toUpperCase())
.replace(/^(.)/, (_, char) => char.toUpperCase())
},
/**
* Convert to camelCase
* Example: "hello-world" => "helloWorld"
*/
camelCase: (str: string): string => {
return str
.replace(/[-_\s](.)/g, (_, char) => char.toUpperCase())
.replace(/^(.)/, (_, char) => char.toLowerCase())
},
/**
* Convert to kebab-case
* Example: "HelloWorld" => "hello-world"
*/
kebabCase: (str: string): string => {
return str
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/[\s_]+/g, '-')
.toLowerCase()
},
/**
* Convert to snake_case
* Example: "HelloWorld" => "hello_world"
*/
snakeCase: (str: string): string => {
return str
.replace(/([a-z])([A-Z])/g, '$1_$2')
.replace(/[\s-]+/g, '_')
.toLowerCase()
},
/**
* Convert to Title Case
* Example: "hello world" => "Hello World"
*/
titleCase: (str: string): string => {
return str
.toLowerCase()
.split(/[\s-_]+/)
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ')
}
}
/**
* Pluralization helpers
*/
export const pluralize = {
/**
* Simple pluralization
*/
plural: (word: string): string => {
if (word.endsWith('y')) {
return word.slice(0, -1) + 'ies'
}
if (word.endsWith('s') || word.endsWith('x') || word.endsWith('z')) {
return word + 'es'
}
return word + 's'
},
/**
* Simple singularization
*/
singular: (word: string): string => {
if (word.endsWith('ies')) {
return word.slice(0, -3) + 'y'
}
if (word.endsWith('es')) {
return word.slice(0, -2)
}
if (word.endsWith('s')) {
return word.slice(0, -1)
}
return word
}
}
/**
* File path helpers
*/
export const pathHelpers = {
/**
* Convert name to file path
* Example: "UserProfile" => "user-profile.ts"
*/
toFilePath: (name: string, extension: string = 'ts'): string => {
const kebab = caseConverters.kebabCase(name)
return `${kebab}.${extension}`
},
/**
* Convert name to directory path
* Example: "UserProfile" => "user-profile"
*/
toDirPath: (name: string): string => {
return caseConverters.kebabCase(name)
}
}
/**
* Comment generators
*/
export const comments = {
/**
* Generate file header comment
*/
fileHeader: (filename: string, description: string, author?: string): string => {
const lines = [
'/**',
` * ${filename}`,
` * ${description}`,
]
if (author) {
lines.push(` * @author ${author}`)
}
lines.push(` * @generated ${new Date().toISOString()}`)
lines.push(' */')
return lines.join('\n')
},
/**
* Generate JSDoc comment
*/
jsDoc: (description: string, params?: Array<{ name: string; type: string; description: string }>, returns?: string): string => {
const lines = [
'/**',
` * ${description}`
]
if (params && params.length > 0) {
lines.push(' *')
params.forEach(param => {
lines.push(` * @param {${param.type}} ${param.name} - ${param.description}`)
})
}
if (returns) {
lines.push(' *')
lines.push(` * @returns {${returns}}`)
}
lines.push(' */')
return lines.join('\n')
}
}
/**
* Import statement generators
*/
export const imports = {
/**
* Generate TypeScript import
*/
typescript: (items: string[], from: string): string => {
if (items.length === 1) {
return `import { ${items[0]} } from '${from}'`
}
return `import {\n ${items.join(',\n ')}\n} from '${from}'`
},
/**
* Generate CommonJS require
*/
commonjs: (name: string, from: string): string => {
return `const ${name} = require('${from}')`
}
}
/**
* Code formatting helpers
*/
export const formatting = {
/**
* Indent text by specified spaces
*/
indent: (text: string, spaces: number = 2): string => {
const indent = ' '.repeat(spaces)
return text
.split('\n')
.map(line => indent + line)
.join('\n')
},
/**
* Wrap text in quotes
*/
quote: (text: string, style: 'single' | 'double' = 'single'): string => {
const quote = style === 'single' ? "'" : '"'
return `${quote}${text}${quote}`
}
}
/**
* Validation helpers
*/
export const validate = {
/**
* Check if string is valid identifier
*/
isValidIdentifier: (str: string): boolean => {
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(str)
},
/**
* Check if string is valid package name
*/
isValidPackageName: (str: string): boolean => {
return /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(str)
}
}
/**
* All helpers combined for easy import
*/
export const helpers = {
...caseConverters,
pluralize,
pathHelpers,
comments,
imports,
formatting,
validate
}
export default helpers

View File

@@ -0,0 +1,120 @@
#!/bin/bash
# Test Gluegun CLI build process
# Usage: ./test-cli-build.sh <cli-directory>
set -e
CLI_DIR="${1:-.}"
ERRORS=0
echo "🧪 Testing Gluegun CLI build: $CLI_DIR"
echo ""
# Check if directory exists
if [ ! -d "$CLI_DIR" ]; then
echo "❌ Directory not found: $CLI_DIR"
exit 1
fi
cd "$CLI_DIR"
# Check for package.json
if [ ! -f "package.json" ]; then
echo "❌ package.json not found"
exit 1
fi
echo "📦 Checking dependencies..."
# Check if node_modules exists
if [ ! -d "node_modules" ]; then
echo "⚠️ node_modules not found, running npm install..."
npm install
fi
# Check if gluegun is installed
if [ -d "node_modules/gluegun" ]; then
echo " ✅ gluegun installed"
else
echo " ❌ gluegun not installed"
((ERRORS++))
fi
# Check for TypeScript
if [ -f "tsconfig.json" ]; then
echo ""
echo "🔨 TypeScript detected, checking compilation..."
if npm run build > /dev/null 2>&1; then
echo " ✅ TypeScript compilation successful"
else
echo " ❌ TypeScript compilation failed"
echo " Run 'npm run build' for details"
((ERRORS++))
fi
fi
# Check for tests
echo ""
echo "🧪 Checking for tests..."
if [ -d "test" ] || [ -d "tests" ] || [ -d "__tests__" ]; then
echo " ✅ Test directory found"
# Try to run tests
if npm test > /dev/null 2>&1; then
echo " ✅ Tests passed"
else
echo " ⚠️ Tests failed or not configured"
fi
else
echo " ⚠️ No test directory found"
fi
# Check CLI execution
echo ""
echo "🚀 Testing CLI execution..."
# Get CLI entry point
cli_entry=""
if [ -f "bin/cli" ]; then
cli_entry="bin/cli"
elif [ -f "bin/run" ]; then
cli_entry="bin/run"
elif [ -f "dist/cli.js" ]; then
cli_entry="node dist/cli.js"
fi
if [ -n "$cli_entry" ]; then
echo " Found CLI entry: $cli_entry"
# Test help command
if $cli_entry --help > /dev/null 2>&1; then
echo " ✅ CLI --help works"
else
echo " ⚠️ CLI --help failed"
((ERRORS++))
fi
# Test version command
if $cli_entry --version > /dev/null 2>&1; then
echo " ✅ CLI --version works"
else
echo " ⚠️ CLI --version failed"
fi
else
echo " ⚠️ CLI entry point not found"
fi
# Summary
echo ""
echo "================================"
if [ $ERRORS -eq 0 ]; then
echo "✅ All build tests passed!"
exit 0
else
echo "❌ Found $ERRORS error(s) during build test"
exit 1
fi

View File

@@ -0,0 +1,122 @@
#!/bin/bash
# Validate Gluegun CLI structure
# Usage: ./validate-cli-structure.sh <cli-directory>
set -e
CLI_DIR="${1:-.}"
ERRORS=0
echo "🔍 Validating Gluegun CLI structure: $CLI_DIR"
echo ""
# Check if directory exists
if [ ! -d "$CLI_DIR" ]; then
echo "❌ Directory not found: $CLI_DIR"
exit 1
fi
cd "$CLI_DIR"
# Check for required files
echo "📁 Checking required files..."
required_files=(
"package.json"
"tsconfig.json"
)
for file in "${required_files[@]}"; do
if [ -f "$file" ]; then
echo "$file"
else
echo " ❌ Missing: $file"
((ERRORS++))
fi
done
# Check for required directories
echo ""
echo "📂 Checking directory structure..."
required_dirs=(
"src"
"src/commands"
)
for dir in "${required_dirs[@]}"; do
if [ -d "$dir" ]; then
echo "$dir/"
else
echo " ❌ Missing: $dir/"
((ERRORS++))
fi
done
# Check optional but recommended directories
optional_dirs=(
"src/extensions"
"templates"
"src/plugins"
)
echo ""
echo "📂 Checking optional directories..."
for dir in "${optional_dirs[@]}"; do
if [ -d "$dir" ]; then
echo "$dir/ (optional)"
else
echo " ⚠️ Missing: $dir/ (optional but recommended)"
fi
done
# Check package.json for gluegun dependency
echo ""
echo "📦 Checking dependencies..."
if [ -f "package.json" ]; then
if grep -q '"gluegun"' package.json; then
echo " ✅ gluegun dependency found"
else
echo " ❌ gluegun dependency not found in package.json"
((ERRORS++))
fi
fi
# Check for commands
echo ""
echo "🎯 Checking commands..."
if [ -d "src/commands" ]; then
command_count=$(find src/commands -type f \( -name "*.ts" -o -name "*.js" \) | wc -l)
echo " Found $command_count command file(s)"
if [ "$command_count" -eq 0 ]; then
echo " ⚠️ No command files found"
fi
fi
# Check for CLI entry point
echo ""
echo "🚀 Checking CLI entry point..."
if [ -f "src/cli.ts" ] || [ -f "src/index.ts" ]; then
echo " ✅ Entry point found"
else
echo " ❌ No entry point found (src/cli.ts or src/index.ts)"
((ERRORS++))
fi
# Summary
echo ""
echo "================================"
if [ $ERRORS -eq 0 ]; then
echo "✅ All checks passed!"
exit 0
else
echo "❌ Found $ERRORS error(s)"
exit 1
fi

View File

@@ -0,0 +1,103 @@
#!/bin/bash
# Validate Gluegun command files
# Usage: ./validate-commands.sh <commands-directory>
set -e
COMMANDS_DIR="${1:-src/commands}"
ERRORS=0
WARNINGS=0
echo "🔍 Validating Gluegun commands: $COMMANDS_DIR"
echo ""
# Check if directory exists
if [ ! -d "$COMMANDS_DIR" ]; then
echo "❌ Directory not found: $COMMANDS_DIR"
exit 1
fi
# Find all command files
command_files=$(find "$COMMANDS_DIR" -type f \( -name "*.ts" -o -name "*.js" \))
if [ -z "$command_files" ]; then
echo "❌ No command files found in $COMMANDS_DIR"
exit 1
fi
echo "Found $(echo "$command_files" | wc -l) command file(s)"
echo ""
# Validate each command file
while IFS= read -r file; do
echo "📄 Validating: $file"
# Check for required exports
if grep -q "module.exports" "$file" || grep -q "export.*GluegunCommand" "$file"; then
echo " ✅ Has command export"
else
echo " ❌ Missing command export"
((ERRORS++))
fi
# Check for name property
if grep -q "name:" "$file"; then
echo " ✅ Has name property"
else
echo " ❌ Missing name property"
((ERRORS++))
fi
# Check for run function
if grep -q "run:" "$file" || grep -q "run =" "$file"; then
echo " ✅ Has run function"
else
echo " ❌ Missing run function"
((ERRORS++))
fi
# Check for toolbox parameter
if grep -q "toolbox" "$file"; then
echo " ✅ Uses toolbox"
else
echo " ⚠️ No toolbox parameter (might be unused)"
((WARNINGS++))
fi
# Check for description (recommended)
if grep -q "description:" "$file"; then
echo " ✅ Has description (good practice)"
else
echo " ⚠️ Missing description (recommended)"
((WARNINGS++))
fi
# Check for async/await pattern
if grep -q "async" "$file"; then
echo " ✅ Uses async/await"
else
echo " ⚠️ No async/await detected"
fi
echo ""
done <<< "$command_files"
# Summary
echo "================================"
echo "Commands validated: $(echo "$command_files" | wc -l)"
echo "Errors: $ERRORS"
echo "Warnings: $WARNINGS"
echo ""
if [ $ERRORS -eq 0 ]; then
echo "✅ All critical checks passed!"
if [ $WARNINGS -gt 0 ]; then
echo "⚠️ Consider addressing $WARNINGS warning(s)"
fi
exit 0
else
echo "❌ Found $ERRORS error(s)"
exit 1
fi

View File

@@ -0,0 +1,100 @@
#!/bin/bash
# Validate EJS template syntax
# Usage: ./validate-templates.sh <templates-directory>
set -e
TEMPLATES_DIR="${1:-templates}"
ERRORS=0
WARNINGS=0
echo "🔍 Validating EJS templates: $TEMPLATES_DIR"
echo ""
# Check if directory exists
if [ ! -d "$TEMPLATES_DIR" ]; then
echo "❌ Directory not found: $TEMPLATES_DIR"
exit 1
fi
# Find all template files
template_files=$(find "$TEMPLATES_DIR" -type f \( -name "*.ejs" -o -name "*.ejs.t" \))
if [ -z "$template_files" ]; then
echo "⚠️ No template files found in $TEMPLATES_DIR"
exit 0
fi
echo "Found $(echo "$template_files" | wc -l) template file(s)"
echo ""
# Validate each template
while IFS= read -r file; do
echo "📄 Validating: $file"
# Check for balanced EJS tags
open_tags=$(grep -o "<%[^>]*" "$file" | wc -l || echo "0")
close_tags=$(grep -o "%>" "$file" | wc -l || echo "0")
if [ "$open_tags" -eq "$close_tags" ]; then
echo " ✅ Balanced EJS tags ($open_tags opening, $close_tags closing)"
else
echo " ❌ Unbalanced EJS tags ($open_tags opening, $close_tags closing)"
((ERRORS++))
fi
# Check for common EJS patterns
if grep -q "<%=" "$file" || grep -q "<%_" "$file" || grep -q "<%#" "$file"; then
echo " ✅ Contains EJS output tags"
else
echo " ⚠️ No EJS output tags detected (might be plain template)"
((WARNINGS++))
fi
# Check for control flow
if grep -q "<%\s*if" "$file" || grep -q "<%\s*for" "$file"; then
echo " ✅ Uses control flow"
fi
# Check for variable usage
if grep -q "<%= [a-zA-Z]" "$file"; then
echo " ✅ Uses template variables"
else
echo " ⚠️ No template variables found"
((WARNINGS++))
fi
# Validate basic syntax (check for common errors)
if grep -q "<%\s*%>" "$file"; then
echo " ⚠️ Empty EJS tag detected"
((WARNINGS++))
fi
# Check for unclosed quotes in EJS tags
if grep -P '<%[^%]*"[^"]*%>' "$file" | grep -v '<%[^%]*"[^"]*"[^%]*%>' > /dev/null 2>&1; then
echo " ⚠️ Possible unclosed quotes in EJS tags"
((WARNINGS++))
fi
echo ""
done <<< "$template_files"
# Summary
echo "================================"
echo "Templates validated: $(echo "$template_files" | wc -l)"
echo "Errors: $ERRORS"
echo "Warnings: $WARNINGS"
echo ""
if [ $ERRORS -eq 0 ]; then
echo "✅ All critical checks passed!"
if [ $WARNINGS -gt 0 ]; then
echo "⚠️ Consider reviewing $WARNINGS warning(s)"
fi
exit 0
else
echo "❌ Found $ERRORS error(s)"
exit 1
fi