Initial commit
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import { GluegunCommand } from 'gluegun'
|
||||
|
||||
const command: GluegunCommand = {
|
||||
name: '<%= name %>',
|
||||
description: 'Interact with <%= apiName %> API',
|
||||
|
||||
run: async (toolbox) => {
|
||||
const { http, print, parameters, prompt } = toolbox
|
||||
|
||||
// Get API configuration
|
||||
const apiKey = process.env.<%= apiKeyEnv %> || parameters.options.key
|
||||
|
||||
if (!apiKey) {
|
||||
print.error('API key is required')
|
||||
print.info('Set <%= apiKeyEnv %> environment variable or use --key option')
|
||||
return
|
||||
}
|
||||
|
||||
// Create API client
|
||||
const api = http.create({
|
||||
baseURL: '<%= apiBaseUrl %>',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${apiKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
timeout: 10000
|
||||
})
|
||||
|
||||
// Show spinner while loading
|
||||
const spinner = print.spin('Fetching data from <%= apiName %>...')
|
||||
|
||||
try {
|
||||
// Make API request
|
||||
const response = await api.get('<%= endpoint %>')
|
||||
|
||||
// Check response
|
||||
if (!response.ok) {
|
||||
spinner.fail(`API Error: ${response.problem}`)
|
||||
if (response.data) {
|
||||
print.error(JSON.stringify(response.data, null, 2))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
spinner.succeed('Data fetched successfully')
|
||||
|
||||
// Display results
|
||||
const data = response.data
|
||||
|
||||
<% if (displayFormat === 'table') { %>
|
||||
// Display as table
|
||||
const tableData = data.map(item => [
|
||||
item.<%= field1 %>,
|
||||
item.<%= field2 %>,
|
||||
item.<%= field3 %>
|
||||
])
|
||||
|
||||
print.table([
|
||||
['<%= header1 %>', '<%= header2 %>', '<%= header3 %>'],
|
||||
...tableData
|
||||
])
|
||||
<% } else { %>
|
||||
// Display as JSON
|
||||
print.info(JSON.stringify(data, null, 2))
|
||||
<% } %>
|
||||
|
||||
// Optional: Save to file
|
||||
const shouldSave = await prompt.confirm('Save results to file?')
|
||||
if (shouldSave) {
|
||||
const filename = `<%= outputFile %>`
|
||||
await toolbox.filesystem.write(filename, JSON.stringify(data, null, 2))
|
||||
print.success(`Saved to ${filename}`)
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
spinner.fail('Request failed')
|
||||
print.error(error.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = command
|
||||
@@ -0,0 +1,33 @@
|
||||
import { GluegunCommand } from 'gluegun'
|
||||
|
||||
const command: GluegunCommand = {
|
||||
name: '<%= name %>',
|
||||
description: '<%= description %>',
|
||||
|
||||
run: async (toolbox) => {
|
||||
const { print, parameters } = toolbox
|
||||
|
||||
// Get parameters
|
||||
const options = parameters.options
|
||||
const args = parameters.array
|
||||
|
||||
// Command logic
|
||||
print.info(`Running <%= name %> command`)
|
||||
|
||||
// Process arguments
|
||||
if (args.length === 0) {
|
||||
print.warning('No arguments provided')
|
||||
return
|
||||
}
|
||||
|
||||
// Example: Process each argument
|
||||
for (const arg of args) {
|
||||
print.info(`Processing: ${arg}`)
|
||||
}
|
||||
|
||||
// Success message
|
||||
print.success('<%= name %> completed successfully')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = command
|
||||
@@ -0,0 +1,57 @@
|
||||
import { GluegunCommand } from 'gluegun'
|
||||
|
||||
const command: GluegunCommand = {
|
||||
name: 'generate',
|
||||
alias: ['g'],
|
||||
description: 'Generate <%= type %> from template',
|
||||
|
||||
run: async (toolbox) => {
|
||||
const { template, print, parameters, filesystem, strings } = toolbox
|
||||
|
||||
// Get name from parameters
|
||||
const name = parameters.first
|
||||
|
||||
if (!name) {
|
||||
print.error('Name is required')
|
||||
print.info('Usage: <%= cliName %> generate <name>')
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to different cases
|
||||
const pascalName = strings.pascalCase(name)
|
||||
const camelName = strings.camelCase(name)
|
||||
const kebabName = strings.kebabCase(name)
|
||||
|
||||
// Generate from template
|
||||
const target = `<%= outputPath %>/${kebabName}.<%= extension %>`
|
||||
|
||||
try {
|
||||
await template.generate({
|
||||
template: '<%= templateFile %>',
|
||||
target,
|
||||
props: {
|
||||
name: pascalName,
|
||||
camelName,
|
||||
kebabName,
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
})
|
||||
|
||||
print.success(`Generated <%= type %>: ${target}`)
|
||||
|
||||
// Optional: Add to index
|
||||
<% if (addToIndex) { %>
|
||||
const indexPath = '<%= outputPath %>/index.ts'
|
||||
if (filesystem.exists(indexPath)) {
|
||||
await filesystem.append(indexPath, `export { ${pascalName} } from './${kebabName}'\n`)
|
||||
print.info(`Added export to ${indexPath}`)
|
||||
}
|
||||
<% } %>
|
||||
|
||||
} catch (error) {
|
||||
print.error(`Failed to generate <%= type %>: ${error.message}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = command
|
||||
@@ -0,0 +1,71 @@
|
||||
import { GluegunToolbox } from 'gluegun'
|
||||
|
||||
// Extend the toolbox with custom functionality
|
||||
module.exports = (toolbox: GluegunToolbox) => {
|
||||
const { filesystem, strings, print } = toolbox
|
||||
|
||||
/**
|
||||
* Custom <%= extensionName %> extension
|
||||
*/
|
||||
toolbox.<%= extensionName %> = {
|
||||
/**
|
||||
* <%= methodDescription %>
|
||||
*/
|
||||
<%= methodName %>: async (input: string): Promise<string> => {
|
||||
// Implementation
|
||||
print.info(`Processing: ${input}`)
|
||||
|
||||
<% if (usesFilesystem) { %>
|
||||
// Filesystem operations
|
||||
const files = filesystem.find('.', { matching: '*.ts' })
|
||||
print.info(`Found ${files.length} TypeScript files`)
|
||||
<% } %>
|
||||
|
||||
<% if (usesStrings) { %>
|
||||
// String manipulation
|
||||
const pascalCase = strings.pascalCase(input)
|
||||
const camelCase = strings.camelCase(input)
|
||||
const kebabCase = strings.kebabCase(input)
|
||||
|
||||
print.info(`Formats: ${pascalCase}, ${camelCase}, ${kebabCase}`)
|
||||
<% } %>
|
||||
|
||||
return input
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate <%= resourceType %>
|
||||
*/
|
||||
validate: (data: any): boolean => {
|
||||
// Validation logic
|
||||
if (!data || typeof data !== 'object') {
|
||||
print.error('Invalid data format')
|
||||
return false
|
||||
}
|
||||
|
||||
<% validationFields.forEach(field => { %>
|
||||
if (!data.<%= field %>) {
|
||||
print.error('Missing required field: <%= field %>')
|
||||
return false
|
||||
}
|
||||
<% }) %>
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
/**
|
||||
* Format <%= resourceType %> for display
|
||||
*/
|
||||
format: (data: any): string => {
|
||||
// Format for display
|
||||
const lines = [
|
||||
`<%= resourceType %>:`,
|
||||
<% displayFields.forEach(field => { %>
|
||||
` <%= field %>: ${data.<%= field %>}`,
|
||||
<% }) %>
|
||||
]
|
||||
|
||||
return lines.join('\n')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
import { GluegunToolbox } from 'gluegun'
|
||||
|
||||
/**
|
||||
* Helper functions extension for <%= cliName %>
|
||||
*/
|
||||
module.exports = (toolbox: GluegunToolbox) => {
|
||||
const { filesystem, strings, print } = toolbox
|
||||
|
||||
toolbox.helpers = {
|
||||
/**
|
||||
* Read configuration file with validation
|
||||
*/
|
||||
readConfig: async (configPath: string = './<%= configFile %>'): Promise<any> => {
|
||||
if (!filesystem.exists(configPath)) {
|
||||
print.error(`Configuration file not found: ${configPath}`)
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
const config = await filesystem.read(configPath, 'json')
|
||||
|
||||
// Validate configuration
|
||||
if (!config.<%= requiredField %>) {
|
||||
print.warning('Configuration missing required field: <%= requiredField %>')
|
||||
}
|
||||
|
||||
return config
|
||||
} catch (error) {
|
||||
print.error(`Failed to read config: ${error.message}`)
|
||||
return null
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Write configuration file safely
|
||||
*/
|
||||
writeConfig: async (config: any, configPath: string = './<%= configFile %>'): Promise<boolean> => {
|
||||
try {
|
||||
await filesystem.write(configPath, config, { jsonIndent: 2 })
|
||||
print.success(`Configuration saved to ${configPath}`)
|
||||
return true
|
||||
} catch (error) {
|
||||
print.error(`Failed to write config: ${error.message}`)
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensure directory exists and is writable
|
||||
*/
|
||||
ensureDir: async (dirPath: string): Promise<boolean> => {
|
||||
try {
|
||||
await filesystem.dir(dirPath)
|
||||
print.debug(`Directory ensured: ${dirPath}`)
|
||||
return true
|
||||
} catch (error) {
|
||||
print.error(`Failed to create directory: ${error.message}`)
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Find files matching pattern
|
||||
*/
|
||||
findFiles: (pattern: string, directory: string = '.'): string[] => {
|
||||
const files = filesystem.find(directory, { matching: pattern })
|
||||
print.debug(`Found ${files.length} files matching: ${pattern}`)
|
||||
return files
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert string to various cases
|
||||
*/
|
||||
convertCase: (input: string) => {
|
||||
return {
|
||||
pascal: strings.pascalCase(input),
|
||||
camel: strings.camelCase(input),
|
||||
kebab: strings.kebabCase(input),
|
||||
snake: strings.snakeCase(input),
|
||||
upper: strings.upperCase(input),
|
||||
lower: strings.lowerCase(input)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Display success message with optional details
|
||||
*/
|
||||
success: (message: string, details?: string[]) => {
|
||||
print.success(message)
|
||||
if (details && details.length > 0) {
|
||||
details.forEach(detail => print.info(` ${detail}`))
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Display error message and exit
|
||||
*/
|
||||
fatal: (message: string, error?: Error) => {
|
||||
print.error(message)
|
||||
if (error) {
|
||||
print.error(error.message)
|
||||
if (error.stack) {
|
||||
print.debug(error.stack)
|
||||
}
|
||||
}
|
||||
process.exit(1)
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if command is available in PATH
|
||||
*/
|
||||
hasCommand: async (command: string): Promise<boolean> => {
|
||||
const result = await toolbox.system.which(command)
|
||||
return result !== null
|
||||
},
|
||||
|
||||
/**
|
||||
* Run command with error handling
|
||||
*/
|
||||
runCommand: async (command: string, options = {}): Promise<string | null> => {
|
||||
try {
|
||||
print.debug(`Running: ${command}`)
|
||||
const output = await toolbox.system.run(command, options)
|
||||
return output
|
||||
} catch (error) {
|
||||
print.error(`Command failed: ${command}`)
|
||||
print.error(error.message)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
125
skills/gluegun-patterns/templates/plugins/plugin-template.ts.ejs
Normal file
125
skills/gluegun-patterns/templates/plugins/plugin-template.ts.ejs
Normal file
@@ -0,0 +1,125 @@
|
||||
import { GluegunToolbox } from 'gluegun'
|
||||
|
||||
/**
|
||||
* <%= pluginName %> Plugin
|
||||
* <%= pluginDescription %>
|
||||
*/
|
||||
module.exports = (toolbox: GluegunToolbox) => {
|
||||
const { print, filesystem, template } = toolbox
|
||||
|
||||
// Plugin initialization
|
||||
print.debug('<%= pluginName %> plugin loaded')
|
||||
|
||||
// Add plugin namespace to toolbox
|
||||
toolbox.<%= pluginNamespace %> = {
|
||||
/**
|
||||
* Plugin version
|
||||
*/
|
||||
version: '<%= version %>',
|
||||
|
||||
/**
|
||||
* Check if plugin is initialized
|
||||
*/
|
||||
isInitialized: (): boolean => {
|
||||
const configPath = '<%= configPath %>'
|
||||
return filesystem.exists(configPath)
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize plugin configuration
|
||||
*/
|
||||
initialize: async (options: any = {}): Promise<void> => {
|
||||
print.info('Initializing <%= pluginName %>...')
|
||||
|
||||
// Create config from template
|
||||
await template.generate({
|
||||
template: '<%= configTemplate %>',
|
||||
target: '<%= configPath %>',
|
||||
props: {
|
||||
...options,
|
||||
createdAt: new Date().toISOString()
|
||||
}
|
||||
})
|
||||
|
||||
print.success('<%= pluginName %> initialized')
|
||||
},
|
||||
|
||||
/**
|
||||
* Get plugin configuration
|
||||
*/
|
||||
getConfig: async (): Promise<any> => {
|
||||
const configPath = '<%= configPath %>'
|
||||
|
||||
if (!filesystem.exists(configPath)) {
|
||||
print.warning('<%= pluginName %> not initialized')
|
||||
return null
|
||||
}
|
||||
|
||||
return await filesystem.read(configPath, 'json')
|
||||
},
|
||||
|
||||
/**
|
||||
* Update plugin configuration
|
||||
*/
|
||||
updateConfig: async (updates: any): Promise<void> => {
|
||||
const config = await toolbox.<%= pluginNamespace %>.getConfig()
|
||||
|
||||
if (!config) {
|
||||
print.error('Cannot update config: <%= pluginName %> not initialized')
|
||||
return
|
||||
}
|
||||
|
||||
const updatedConfig = { ...config, ...updates }
|
||||
await filesystem.write('<%= configPath %>', updatedConfig, { jsonIndent: 2 })
|
||||
|
||||
print.success('Configuration updated')
|
||||
},
|
||||
|
||||
<% if (hasCommands) { %>
|
||||
/**
|
||||
* Execute plugin-specific operation
|
||||
*/
|
||||
execute: async (operation: string, params: any = {}): Promise<any> => {
|
||||
print.info(`Executing <%= pluginName %> operation: ${operation}`)
|
||||
|
||||
switch (operation) {
|
||||
case '<%= operation1 %>':
|
||||
return await handle<%= operation1Pascal %>(toolbox, params)
|
||||
|
||||
case '<%= operation2 %>':
|
||||
return await handle<%= operation2Pascal %>(toolbox, params)
|
||||
|
||||
default:
|
||||
print.error(`Unknown operation: ${operation}`)
|
||||
return null
|
||||
}
|
||||
}
|
||||
<% } %>
|
||||
}
|
||||
}
|
||||
|
||||
<% if (hasCommands) { %>
|
||||
/**
|
||||
* Handle <%= operation1 %> operation
|
||||
*/
|
||||
async function handle<%= operation1Pascal %>(toolbox: GluegunToolbox, params: any) {
|
||||
const { print } = toolbox
|
||||
print.info('Handling <%= operation1 %>...')
|
||||
|
||||
// Implementation
|
||||
|
||||
return { success: true }
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle <%= operation2 %> operation
|
||||
*/
|
||||
async function handle<%= operation2Pascal %>(toolbox: GluegunToolbox, params: any) {
|
||||
const { print } = toolbox
|
||||
print.info('Handling <%= operation2 %>...')
|
||||
|
||||
// Implementation
|
||||
|
||||
return { success: true }
|
||||
}
|
||||
<% } %>
|
||||
@@ -0,0 +1,93 @@
|
||||
import { GluegunToolbox } from 'gluegun'
|
||||
|
||||
/**
|
||||
* <%= pluginName %> Plugin with Commands
|
||||
* Demonstrates how to add commands via plugins
|
||||
*/
|
||||
module.exports = (toolbox: GluegunToolbox) => {
|
||||
const { print, runtime } = toolbox
|
||||
|
||||
print.debug('<%= pluginName %> plugin loaded')
|
||||
|
||||
// Register plugin commands
|
||||
runtime.addPlugin({
|
||||
name: '<%= pluginName %>',
|
||||
commands: [
|
||||
{
|
||||
name: '<%= command1Name %>',
|
||||
description: '<%= command1Description %>',
|
||||
run: async (toolbox) => {
|
||||
const { print, parameters } = toolbox
|
||||
|
||||
print.info('Running <%= command1Name %> from <%= pluginName %>')
|
||||
|
||||
// Command logic
|
||||
const arg = parameters.first
|
||||
if (arg) {
|
||||
print.success(`Processed: ${arg}`)
|
||||
} else {
|
||||
print.warning('No argument provided')
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '<%= command2Name %>',
|
||||
description: '<%= command2Description %>',
|
||||
run: async (toolbox) => {
|
||||
const { print, filesystem, template } = toolbox
|
||||
|
||||
print.info('Running <%= command2Name %> from <%= pluginName %>')
|
||||
|
||||
// Generate from template
|
||||
await template.generate({
|
||||
template: '<%= template2 %>',
|
||||
target: '<%= output2 %>',
|
||||
props: {
|
||||
pluginName: '<%= pluginName %>',
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
})
|
||||
|
||||
print.success('Generated successfully')
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// Add plugin utilities to toolbox
|
||||
toolbox.<%= pluginNamespace %> = {
|
||||
/**
|
||||
* Shared utility function
|
||||
*/
|
||||
sharedUtility: (input: string): string => {
|
||||
print.debug(`<%= pluginName %> processing: ${input}`)
|
||||
return input.toUpperCase()
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate plugin requirements
|
||||
*/
|
||||
validateRequirements: async (): Promise<boolean> => {
|
||||
const { filesystem, system } = toolbox
|
||||
|
||||
// Check for required files
|
||||
<% requiredFiles.forEach(file => { %>
|
||||
if (!filesystem.exists('<%= file %>')) {
|
||||
print.error('Missing required file: <%= file %>')
|
||||
return false
|
||||
}
|
||||
<% }) %>
|
||||
|
||||
// Check for required commands
|
||||
<% requiredCommands.forEach(cmd => { %>
|
||||
const has<%= cmd %> = await system.which('<%= cmd %>')
|
||||
if (!has<%= cmd %>) {
|
||||
print.error('Missing required command: <%= cmd %>')
|
||||
return false
|
||||
}
|
||||
<% }) %>
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
import { GluegunCommand } from 'gluegun'
|
||||
|
||||
/**
|
||||
* Examples of filesystem operations with Gluegun
|
||||
*/
|
||||
const command: GluegunCommand = {
|
||||
name: 'filesystem',
|
||||
description: 'Filesystem operation examples',
|
||||
|
||||
run: async (toolbox) => {
|
||||
const { filesystem, print } = toolbox
|
||||
|
||||
print.info('=== Filesystem Examples ===\n')
|
||||
|
||||
// 1. Read file
|
||||
print.info('1. Read file')
|
||||
const packageJson = await filesystem.read('package.json', 'json')
|
||||
if (packageJson) {
|
||||
print.success(`Project: ${packageJson.name}`)
|
||||
}
|
||||
|
||||
// 2. Write file
|
||||
print.info('\n2. Write file')
|
||||
await filesystem.write('temp-output.txt', 'Hello from Gluegun!', {
|
||||
atomic: true // Ensures file is written completely or not at all
|
||||
})
|
||||
print.success('File written: temp-output.txt')
|
||||
|
||||
// 3. Check if file exists
|
||||
print.info('\n3. Check existence')
|
||||
const exists = filesystem.exists('temp-output.txt')
|
||||
print.info(`temp-output.txt exists: ${exists}`)
|
||||
|
||||
// 4. Create directory
|
||||
print.info('\n4. Create directory')
|
||||
await filesystem.dir('temp-dir/nested/deep')
|
||||
print.success('Created nested directories')
|
||||
|
||||
// 5. List files
|
||||
print.info('\n5. List files')
|
||||
const files = filesystem.list('.')
|
||||
print.info(`Files in current directory: ${files?.length || 0}`)
|
||||
|
||||
// 6. Find files with pattern
|
||||
print.info('\n6. Find files')
|
||||
const tsFiles = filesystem.find('.', { matching: '*.ts', recursive: false })
|
||||
print.info(`TypeScript files found: ${tsFiles?.length || 0}`)
|
||||
tsFiles?.slice(0, 5).forEach(file => print.info(` - ${file}`))
|
||||
|
||||
// 7. Copy file/directory
|
||||
print.info('\n7. Copy operations')
|
||||
await filesystem.copy('temp-output.txt', 'temp-dir/copy.txt')
|
||||
print.success('File copied to temp-dir/copy.txt')
|
||||
|
||||
// 8. Move/rename
|
||||
print.info('\n8. Move/rename')
|
||||
await filesystem.move('temp-output.txt', 'temp-dir/moved.txt')
|
||||
print.success('File moved to temp-dir/moved.txt')
|
||||
|
||||
// 9. Read directory tree
|
||||
print.info('\n9. Directory tree')
|
||||
const tree = filesystem.inspectTree('temp-dir')
|
||||
print.info(`Temp directory structure:`)
|
||||
print.info(JSON.stringify(tree, null, 2))
|
||||
|
||||
// 10. File info
|
||||
print.info('\n10. File info')
|
||||
const info = filesystem.inspect('temp-dir/moved.txt')
|
||||
if (info) {
|
||||
print.info(`File type: ${info.type}`)
|
||||
print.info(`File size: ${info.size} bytes`)
|
||||
}
|
||||
|
||||
// 11. Append to file
|
||||
print.info('\n11. Append to file')
|
||||
await filesystem.append('temp-dir/moved.txt', '\nAppended line')
|
||||
print.success('Content appended')
|
||||
|
||||
// 12. Read file with encoding
|
||||
print.info('\n12. Read with encoding')
|
||||
const content = await filesystem.read('temp-dir/moved.txt', 'utf8')
|
||||
print.info(`Content: ${content}`)
|
||||
|
||||
// 13. Path utilities
|
||||
print.info('\n13. Path utilities')
|
||||
const fullPath = filesystem.path('temp-dir', 'moved.txt')
|
||||
print.info(`Full path: ${fullPath}`)
|
||||
print.info(`Current directory: ${filesystem.cwd()}`)
|
||||
print.info(`Path separator: ${filesystem.separator}`)
|
||||
|
||||
// 14. Find by extension
|
||||
print.info('\n14. Find by extension')
|
||||
const jsonFiles = filesystem.find('.', {
|
||||
matching: '*.json',
|
||||
recursive: false
|
||||
})
|
||||
print.info(`JSON files: ${jsonFiles?.join(', ')}`)
|
||||
|
||||
// 15. Remove files (cleanup)
|
||||
print.info('\n15. Cleanup')
|
||||
await filesystem.remove('temp-dir')
|
||||
print.success('Removed temp directory')
|
||||
|
||||
// Summary
|
||||
print.info('\n=== Summary ===')
|
||||
print.success('Filesystem operations completed!')
|
||||
print.info('Common operations:')
|
||||
print.info(' - read/write: Handle file content')
|
||||
print.info(' - exists: Check file/directory existence')
|
||||
print.info(' - dir: Create directories')
|
||||
print.info(' - find: Search for files')
|
||||
print.info(' - copy/move: Manipulate files')
|
||||
print.info(' - remove: Delete files/directories')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = command
|
||||
126
skills/gluegun-patterns/templates/toolbox/prompt-examples.ts.ejs
Normal file
126
skills/gluegun-patterns/templates/toolbox/prompt-examples.ts.ejs
Normal file
@@ -0,0 +1,126 @@
|
||||
import { GluegunCommand } from 'gluegun'
|
||||
|
||||
/**
|
||||
* Examples of different prompt patterns with Gluegun
|
||||
*/
|
||||
const command: GluegunCommand = {
|
||||
name: 'prompts',
|
||||
description: 'Interactive prompt examples',
|
||||
|
||||
run: async (toolbox) => {
|
||||
const { prompt, print } = toolbox
|
||||
|
||||
print.info('=== Prompt Examples ===\n')
|
||||
|
||||
// 1. Simple text input
|
||||
const nameResult = await prompt.ask({
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: 'What is your name?',
|
||||
initial: 'John Doe'
|
||||
})
|
||||
print.info(`Hello, ${nameResult.name}!\n`)
|
||||
|
||||
// 2. Confirmation prompt
|
||||
const shouldContinue = await prompt.confirm('Do you want to continue?')
|
||||
if (!shouldContinue) {
|
||||
print.warning('Operation cancelled')
|
||||
return
|
||||
}
|
||||
|
||||
// 3. Select from list
|
||||
const frameworkResult = await prompt.ask({
|
||||
type: 'select',
|
||||
name: 'framework',
|
||||
message: 'Choose your framework:',
|
||||
choices: ['React', 'Vue', 'Angular', 'Svelte']
|
||||
})
|
||||
print.info(`Selected: ${frameworkResult.framework}\n`)
|
||||
|
||||
// 4. Multi-select
|
||||
const featuresResult = await prompt.ask({
|
||||
type: 'multiselect',
|
||||
name: 'features',
|
||||
message: 'Select features to enable:',
|
||||
choices: [
|
||||
{ name: 'TypeScript', value: 'typescript' },
|
||||
{ name: 'ESLint', value: 'eslint' },
|
||||
{ name: 'Prettier', value: 'prettier' },
|
||||
{ name: 'Testing', value: 'testing' }
|
||||
],
|
||||
initial: ['typescript', 'eslint']
|
||||
})
|
||||
print.info(`Features: ${featuresResult.features.join(', ')}\n`)
|
||||
|
||||
// 5. Password input
|
||||
const passwordResult = await prompt.ask({
|
||||
type: 'password',
|
||||
name: 'password',
|
||||
message: 'Enter password:'
|
||||
})
|
||||
print.info('Password received (hidden)\n')
|
||||
|
||||
// 6. Number input
|
||||
const portResult = await prompt.ask({
|
||||
type: 'numeral',
|
||||
name: 'port',
|
||||
message: 'Enter port number:',
|
||||
initial: 3000
|
||||
})
|
||||
print.info(`Port: ${portResult.port}\n`)
|
||||
|
||||
// 7. Autocomplete
|
||||
const colorResult = await prompt.ask({
|
||||
type: 'autocomplete',
|
||||
name: 'color',
|
||||
message: 'Choose a color:',
|
||||
choices: ['Red', 'Blue', 'Green', 'Yellow', 'Purple', 'Orange']
|
||||
})
|
||||
print.info(`Color: ${colorResult.color}\n`)
|
||||
|
||||
// 8. List input (comma-separated)
|
||||
const tagsResult = await prompt.ask({
|
||||
type: 'list',
|
||||
name: 'tags',
|
||||
message: 'Enter tags (comma-separated):'
|
||||
})
|
||||
print.info(`Tags: ${tagsResult.tags.join(', ')}\n`)
|
||||
|
||||
// 9. Snippet (multiple fields)
|
||||
const userResult = await prompt.ask({
|
||||
type: 'snippet',
|
||||
name: 'user',
|
||||
message: 'Fill out user information:',
|
||||
template: `Name: \${name}
|
||||
Email: \${email}
|
||||
Age: \${age}`
|
||||
})
|
||||
print.info('User info:')
|
||||
print.info(JSON.stringify(userResult.user.values, null, 2))
|
||||
print.info('')
|
||||
|
||||
// 10. Conditional prompts
|
||||
const projectTypeResult = await prompt.ask({
|
||||
type: 'select',
|
||||
name: 'projectType',
|
||||
message: 'Project type:',
|
||||
choices: ['web', 'mobile', 'desktop']
|
||||
})
|
||||
|
||||
if (projectTypeResult.projectType === 'web') {
|
||||
const webFrameworkResult = await prompt.ask({
|
||||
type: 'select',
|
||||
name: 'webFramework',
|
||||
message: 'Choose web framework:',
|
||||
choices: ['Next.js', 'Remix', 'SvelteKit']
|
||||
})
|
||||
print.info(`Web framework: ${webFrameworkResult.webFramework}\n`)
|
||||
}
|
||||
|
||||
// Summary
|
||||
print.success('All prompts completed!')
|
||||
print.info('See the examples above for different prompt patterns')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = command
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* <%= componentName %> Component
|
||||
* Generated by <%= generatorName %>
|
||||
* Created: <%= timestamp %>
|
||||
*/
|
||||
|
||||
<% if (language === 'typescript') { %>
|
||||
import { <%= imports.join(', ') %> } from '<%= importPath %>'
|
||||
|
||||
export interface <%= componentName %>Props {
|
||||
<% props.forEach(prop => { %>
|
||||
<%= prop.name %>: <%= prop.type %><%= prop.optional ? '?' : '' %>
|
||||
<% }) %>
|
||||
}
|
||||
|
||||
export class <%= componentName %> {
|
||||
<% properties.forEach(property => { %>
|
||||
private <%= property.name %>: <%= property.type %>
|
||||
<% }) %>
|
||||
|
||||
constructor(props: <%= componentName %>Props) {
|
||||
<% properties.forEach(property => { %>
|
||||
this.<%= property.name %> = props.<%= property.name %>
|
||||
<% }) %>
|
||||
}
|
||||
|
||||
<% methods.forEach(method => { %>
|
||||
<%= method.name %>(<%= method.params %>): <%= method.returnType %> {
|
||||
// TODO: Implement <%= method.name %>
|
||||
<% if (method.returnType !== 'void') { %>
|
||||
return <%= method.defaultReturn %>
|
||||
<% } %>
|
||||
}
|
||||
<% }) %>
|
||||
}
|
||||
<% } else if (language === 'javascript') { %>
|
||||
/**
|
||||
* <%= componentName %> Component
|
||||
*/
|
||||
class <%= componentName %> {
|
||||
constructor(options = {}) {
|
||||
<% properties.forEach(property => { %>
|
||||
this.<%= property.name %> = options.<%= property.name %> || <%= property.default %>
|
||||
<% }) %>
|
||||
}
|
||||
|
||||
<% methods.forEach(method => { %>
|
||||
<%= method.name %>(<%= method.params %>) {
|
||||
// TODO: Implement <%= method.name %>
|
||||
}
|
||||
<% }) %>
|
||||
}
|
||||
|
||||
module.exports = <%= componentName %>
|
||||
<% } %>
|
||||
|
||||
<% if (includeTests) { %>
|
||||
|
||||
/**
|
||||
* Tests for <%= componentName %>
|
||||
*/
|
||||
describe('<%= componentName %>', () => {
|
||||
<% methods.forEach(method => { %>
|
||||
test('<%= method.name %> should work', () => {
|
||||
// TODO: Write test for <%= method.name %>
|
||||
})
|
||||
<% }) %>
|
||||
})
|
||||
<% } %>
|
||||
|
||||
<% if (includeDocumentation) { %>
|
||||
|
||||
/**
|
||||
* DOCUMENTATION
|
||||
*
|
||||
* Usage Example:
|
||||
* ```<%= language %>
|
||||
* <% if (language === 'typescript') { %>
|
||||
* const instance = new <%= componentName %>({
|
||||
* <% props.forEach(prop => { %>
|
||||
* <%= prop.name %>: <%= prop.exampleValue %>,
|
||||
* <% }) %>
|
||||
* })
|
||||
* <% } else { %>
|
||||
* const instance = new <%= componentName %>({
|
||||
* <% properties.forEach(property => { %>
|
||||
* <%= property.name %>: <%= property.exampleValue %>,
|
||||
* <% }) %>
|
||||
* })
|
||||
* <% } %>
|
||||
*
|
||||
* <% methods.forEach(method => { %>
|
||||
* instance.<%= method.name %>(<%= method.exampleArgs %>)
|
||||
* <% }) %>
|
||||
* ```
|
||||
*/
|
||||
<% } %>
|
||||
Reference in New Issue
Block a user