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,252 @@
# Gluegun Plugin System Example
Demonstrates how to build an extensible CLI with plugin architecture.
## Structure
```
plugin-system/
├── src/
│ ├── cli.ts # CLI with plugin loading
│ ├── commands/
│ │ └── plugin.ts # Plugin management command
│ └── plugins/
│ ├── custom-plugin.ts # Example plugin
│ └── validator-plugin.ts # Validation plugin
├── package.json
└── README.md
```
## Features
- Plugin discovery and loading
- Custom toolbox extensions via plugins
- Plugin-provided commands
- Plugin configuration management
## Installation
```bash
npm install
npm run build
```
## Usage
### Load Plugins
```bash
# CLI automatically loads plugins from:
# - ./plugins/
# - ./node_modules/mycli-*
```
### Use Plugin Commands
```bash
# Commands added by plugins
./bin/cli validate
./bin/cli custom-action
```
### Use Plugin Extensions
```typescript
// In any command
const { myPlugin } = toolbox
myPlugin.doSomething()
```
## Creating a Plugin
### Basic Plugin Structure
```typescript
module.exports = (toolbox) => {
const { print } = toolbox
// Add to toolbox
toolbox.myPlugin = {
version: '1.0.0',
doSomething: () => {
print.info('Plugin action executed')
}
}
}
```
### Plugin with Commands
```typescript
module.exports = (toolbox) => {
const { runtime } = toolbox
runtime.addPlugin({
name: 'my-plugin',
commands: [
{
name: 'my-command',
run: async (toolbox) => {
// Command implementation
}
}
]
})
}
```
## Plugin Discovery
The CLI looks for plugins in:
1. **Local plugins directory**: `./plugins/*.js`
2. **Node modules**: `./node_modules/mycli-*`
3. **Scoped packages**: `@scope/mycli-*`
## Plugin Naming Convention
- Local plugins: Any `.js` or `.ts` file in `plugins/`
- NPM plugins: Must match pattern `mycli-*`
- Example: `mycli-validator`, `@myorg/mycli-helper`
## Key Patterns
### 1. Load Plugins from Directory
```typescript
cli.plugins('./plugins', { matching: '*.js' })
```
### 2. Load NPM Plugins
```typescript
cli.plugins('./node_modules', {
matching: 'mycli-*',
hidden: true
})
```
### 3. Add Toolbox Extension
```typescript
toolbox.validator = {
validate: (data) => { /* ... */ }
}
```
### 4. Register Commands
```typescript
runtime.addPlugin({
name: 'my-plugin',
commands: [/* commands */]
})
```
## Example Plugins
### custom-plugin.ts
Adds custom utilities to toolbox.
```typescript
toolbox.custom = {
formatDate: (date) => { /* ... */ },
parseConfig: (file) => { /* ... */ }
}
```
### validator-plugin.ts
Adds validation command and utilities.
```typescript
toolbox.validator = {
validateFile: (path) => { /* ... */ },
validateSchema: (data) => { /* ... */ }
}
```
## Publishing Plugins
### 1. Create NPM Package
```json
{
"name": "mycli-myplugin",
"main": "dist/index.js",
"keywords": ["mycli", "plugin"]
}
```
### 2. Export Plugin
```typescript
module.exports = (toolbox) => {
// Plugin implementation
}
```
### 3. Publish
```bash
npm publish
```
### 4. Install and Use
```bash
npm install mycli-myplugin
# Automatically loaded by CLI
```
## Advanced Patterns
### Conditional Plugin Loading
```typescript
if (config.enablePlugin) {
cli.plugins('./plugins/optional')
}
```
### Plugin Configuration
```typescript
toolbox.myPlugin = {
config: await filesystem.read('.mypluginrc', 'json'),
// Plugin methods
}
```
### Plugin Dependencies
```typescript
module.exports = (toolbox) => {
// Check for required plugins
if (!toolbox.otherPlugin) {
throw new Error('Requires other-plugin')
}
}
```
## Best Practices
1. **Namespace Extensions**: Use unique names for toolbox extensions
2. **Document APIs**: Provide clear documentation for plugin methods
3. **Handle Errors**: Validate inputs and handle failures gracefully
4. **Version Plugins**: Use semantic versioning
5. **Test Plugins**: Write tests for plugin functionality
## Testing Plugins
```typescript
import { build } from 'gluegun'
test('plugin loads correctly', async () => {
const cli = build().src(__dirname).plugins('./plugins').create()
const toolbox = await cli.run()
expect(toolbox.myPlugin).toBeDefined()
})
```