@o2vend/theme-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @o2vend/theme-cli might be problematic. Click here for more details.
- package/README.md +211 -0
- package/bin/o2vend +34 -0
- package/config/widget-map.json +45 -0
- package/package.json +64 -0
- package/src/commands/check.js +201 -0
- package/src/commands/generate.js +33 -0
- package/src/commands/init.js +302 -0
- package/src/commands/optimize.js +216 -0
- package/src/commands/package.js +208 -0
- package/src/commands/serve.js +105 -0
- package/src/commands/validate.js +191 -0
- package/src/lib/api-client.js +339 -0
- package/src/lib/dev-server.js +482 -0
- package/src/lib/file-watcher.js +80 -0
- package/src/lib/hot-reload.js +106 -0
- package/src/lib/liquid-engine.js +169 -0
- package/src/lib/liquid-filters.js +589 -0
- package/src/lib/mock-api-server.js +225 -0
- package/src/lib/mock-data.js +290 -0
- package/src/lib/widget-service.js +293 -0
package/README.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# O2VEND Theme CLI
|
|
2
|
+
|
|
3
|
+
Command-line interface for O2VEND theme development. This is a standalone tool that works independently of the main webstore solution.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @o2vend/theme-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
### `serve`
|
|
14
|
+
|
|
15
|
+
Start development server with hot reload:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
o2vend serve [options]
|
|
19
|
+
|
|
20
|
+
Options:
|
|
21
|
+
-m, --mode <mode> API mode (mock|real) [default: mock]
|
|
22
|
+
-p, --port <port> Server port [default: 3000]
|
|
23
|
+
--host <host> Server host [default: localhost]
|
|
24
|
+
--cwd <path> Working directory [default: current]
|
|
25
|
+
--open Open browser automatically [default: true]
|
|
26
|
+
--no-open Don't open browser
|
|
27
|
+
--mock-api-port <port> Mock API port [default: 3001]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Examples:**
|
|
31
|
+
```bash
|
|
32
|
+
# Start in mock mode (default)
|
|
33
|
+
o2vend serve
|
|
34
|
+
|
|
35
|
+
# Start in real API mode
|
|
36
|
+
o2vend serve --mode real
|
|
37
|
+
|
|
38
|
+
# Custom port
|
|
39
|
+
o2vend serve --port 8080
|
|
40
|
+
|
|
41
|
+
# Don't open browser
|
|
42
|
+
o2vend serve --no-open
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `init <name>`
|
|
46
|
+
|
|
47
|
+
Initialize a new theme project:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
o2vend init my-theme
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Creates a new theme directory with:
|
|
54
|
+
- Basic theme structure
|
|
55
|
+
- Configuration files
|
|
56
|
+
- Example templates and widgets
|
|
57
|
+
- VS Code configuration
|
|
58
|
+
|
|
59
|
+
### `validate`
|
|
60
|
+
|
|
61
|
+
Validate theme structure:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
o2vend validate
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Checks for:
|
|
68
|
+
- Required theme files
|
|
69
|
+
- Valid Liquid syntax
|
|
70
|
+
- Proper theme structure
|
|
71
|
+
- Configuration file validity
|
|
72
|
+
|
|
73
|
+
### `package`
|
|
74
|
+
|
|
75
|
+
Package theme for marketplace:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
o2vend package
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Creates a zip file in `dist/` directory ready for marketplace upload.
|
|
82
|
+
|
|
83
|
+
### `check`
|
|
84
|
+
|
|
85
|
+
Check theme for issues:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
o2vend check
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Performs various checks:
|
|
92
|
+
- Syntax errors
|
|
93
|
+
- Missing files
|
|
94
|
+
- Performance issues
|
|
95
|
+
- Best practices
|
|
96
|
+
|
|
97
|
+
### `optimize`
|
|
98
|
+
|
|
99
|
+
Optimize theme assets:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
o2vend optimize
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Optimizes:
|
|
106
|
+
- CSS files (minification)
|
|
107
|
+
- JavaScript files (minification)
|
|
108
|
+
- Images (compression)
|
|
109
|
+
- Asset bundling
|
|
110
|
+
|
|
111
|
+
## Environment Variables
|
|
112
|
+
|
|
113
|
+
| Variable | Description | Default |
|
|
114
|
+
|----------|-------------|---------|
|
|
115
|
+
| `API_MODE` | API mode (`mock` or `real`) | `mock` |
|
|
116
|
+
| `PORT` | Development server port | `3000` |
|
|
117
|
+
| `HOST` | Development server host | `localhost` |
|
|
118
|
+
| `MOCK_API_PORT` | Mock API server port | `3001` |
|
|
119
|
+
| `O2VEND_TENANT_ID` | Tenant ID (real mode) | - |
|
|
120
|
+
| `O2VEND_API_KEY` | API Key (real mode) | - |
|
|
121
|
+
| `O2VEND_API_BASE_URL` | API Base URL (real mode) | - |
|
|
122
|
+
| `OPEN_BROWSER` | Auto-open browser | `true` |
|
|
123
|
+
| `DEBUG_API_ERRORS` | Debug API errors | `false` |
|
|
124
|
+
|
|
125
|
+
## Features
|
|
126
|
+
|
|
127
|
+
### Hot Reload
|
|
128
|
+
|
|
129
|
+
- **CSS changes** - Injected without page reload
|
|
130
|
+
- **Liquid/JS changes** - Full page reload
|
|
131
|
+
- **File watching** - Automatic change detection
|
|
132
|
+
|
|
133
|
+
### Mock API
|
|
134
|
+
|
|
135
|
+
Built-in mock API provides realistic test data:
|
|
136
|
+
- Products (20+ items)
|
|
137
|
+
- Categories (10+ items)
|
|
138
|
+
- Brands (8+ items)
|
|
139
|
+
- Widgets (multiple sections)
|
|
140
|
+
- Store information
|
|
141
|
+
- Shopping cart
|
|
142
|
+
|
|
143
|
+
### Real API Mode
|
|
144
|
+
|
|
145
|
+
Connect to actual O2VEND Storefront API:
|
|
146
|
+
- Full API compatibility
|
|
147
|
+
- Authentication support
|
|
148
|
+
- Widget loading
|
|
149
|
+
- Real-time data
|
|
150
|
+
|
|
151
|
+
## Architecture
|
|
152
|
+
|
|
153
|
+
### Standalone Design
|
|
154
|
+
|
|
155
|
+
The CLI is completely standalone:
|
|
156
|
+
- No dependencies on webstore solution
|
|
157
|
+
- Self-contained mock API
|
|
158
|
+
- All services included
|
|
159
|
+
- Manual updates from webstore
|
|
160
|
+
|
|
161
|
+
### Update Process
|
|
162
|
+
|
|
163
|
+
When webstore solution changes:
|
|
164
|
+
1. Copy services from webstore to CLI
|
|
165
|
+
2. Update manually (see UPDATE.md)
|
|
166
|
+
3. Test thoroughly
|
|
167
|
+
4. Publish new version
|
|
168
|
+
|
|
169
|
+
## Development
|
|
170
|
+
|
|
171
|
+
### Local Development
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Clone repository
|
|
175
|
+
git clone https://github.com/Jeyan-Technologies/o2vend-theme-dev-tools.git
|
|
176
|
+
cd o2vend-theme-dev-tools/packages/cli
|
|
177
|
+
|
|
178
|
+
# Install dependencies
|
|
179
|
+
npm install
|
|
180
|
+
|
|
181
|
+
# Link for local testing
|
|
182
|
+
npm link
|
|
183
|
+
|
|
184
|
+
# Run commands
|
|
185
|
+
o2vend serve
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Building
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
npm run build
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Testing
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
npm test
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Support & Resources
|
|
201
|
+
|
|
202
|
+
- **[O2VEND Developer Documentation](https://o2vend.com/developer/)** - Complete API documentation and guides
|
|
203
|
+
- **Support Email:** support@o2vend.com or developer@jeyantechnologies.com
|
|
204
|
+
- **Support Desk:** [O2VEND Support Portal](https://o2vend.atlassian.net/servicedesk/customer/portals)
|
|
205
|
+
- **Community:** [O2VEND Community Program](https://o2vend.com/community)
|
|
206
|
+
- **Partnership:** [O2VEND Partnership Program](https://o2vend.com/partnership)
|
|
207
|
+
- **Developer Portal:** [www.o2vend.com](https://www.o2vend.com)
|
|
208
|
+
|
|
209
|
+
## License
|
|
210
|
+
|
|
211
|
+
MIT License - See LICENSE file
|
package/bin/o2vend
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* O2VEND Theme CLI Entry Point
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { program } = require('commander');
|
|
8
|
+
const initCommand = require('../src/commands/init');
|
|
9
|
+
const serveCommand = require('../src/commands/serve');
|
|
10
|
+
const validateCommand = require('../src/commands/validate');
|
|
11
|
+
const checkCommand = require('../src/commands/check');
|
|
12
|
+
const generateCommand = require('../src/commands/generate');
|
|
13
|
+
const optimizeCommand = require('../src/commands/optimize');
|
|
14
|
+
const packageCommand = require('../src/commands/package');
|
|
15
|
+
|
|
16
|
+
const packageJson = require('../package.json');
|
|
17
|
+
|
|
18
|
+
program
|
|
19
|
+
.name('o2vend')
|
|
20
|
+
.description('O2VEND Theme Development CLI')
|
|
21
|
+
.version(packageJson.version);
|
|
22
|
+
|
|
23
|
+
// Add commands directly (no nested 'theme' command)
|
|
24
|
+
program
|
|
25
|
+
.addCommand(initCommand)
|
|
26
|
+
.addCommand(serveCommand)
|
|
27
|
+
.addCommand(validateCommand)
|
|
28
|
+
.addCommand(checkCommand)
|
|
29
|
+
.addCommand(generateCommand)
|
|
30
|
+
.addCommand(optimizeCommand)
|
|
31
|
+
.addCommand(packageCommand);
|
|
32
|
+
|
|
33
|
+
program.parse();
|
|
34
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"BrandWidget": "brand",
|
|
3
|
+
"Brand": "brand",
|
|
4
|
+
"BrandWidgetCarousel": "brand-carousel",
|
|
5
|
+
"BrandCarousel": "brand-carousel",
|
|
6
|
+
"CarouselWidget": "carousel",
|
|
7
|
+
"Carousel": "carousel",
|
|
8
|
+
"CategoryListCarouselWidget": "category-list-carousel",
|
|
9
|
+
"CategoryListCarousel": "category-list-carousel",
|
|
10
|
+
"CategoryListWidget": "category-list",
|
|
11
|
+
"CategoryList": "category-list",
|
|
12
|
+
"CategoryWidget": "category",
|
|
13
|
+
"Category": "category",
|
|
14
|
+
"DiscountTimeWidget": "discount-time",
|
|
15
|
+
"DiscountTime": "discount-time",
|
|
16
|
+
"FooterWidget": "footer",
|
|
17
|
+
"FooterMenu": "footer-menu",
|
|
18
|
+
"GalleryWidget": "gallery",
|
|
19
|
+
"Gallery": "gallery",
|
|
20
|
+
"HeaderWidget": "header",
|
|
21
|
+
"HeaderMenu": "header-menu",
|
|
22
|
+
"HtmlWidget": "html",
|
|
23
|
+
"Html": "html",
|
|
24
|
+
"NewsWidget": "news",
|
|
25
|
+
"News": "news",
|
|
26
|
+
"ProductCanvasWidget": "product-canvas",
|
|
27
|
+
"ProductCanvas": "product-canvas",
|
|
28
|
+
"ProductCarouselWidget": "product-carousel",
|
|
29
|
+
"ProductWidget": "product",
|
|
30
|
+
"Product": "product",
|
|
31
|
+
"RecentlyViewedWidget": "recently-viewed",
|
|
32
|
+
"RecentlyViewed": "recently-viewed",
|
|
33
|
+
"SimpleProductWidget": "simple-product",
|
|
34
|
+
"SimpleProduct": "simple-product",
|
|
35
|
+
"SingleProductWidget": "single-product",
|
|
36
|
+
"SingleProduct": "single-product",
|
|
37
|
+
"SpaceBarWidget": "spacebar",
|
|
38
|
+
"SpaceBar": "spacebar",
|
|
39
|
+
"SpaceBarWidgetCarousel": "spacebar-carousel",
|
|
40
|
+
"SpaceBarCarousel": "spacebar-carousel",
|
|
41
|
+
"SplashWidget": "splash",
|
|
42
|
+
"Splash": "splash",
|
|
43
|
+
"TestimonialCarousel": "testimonial-carousel"
|
|
44
|
+
}
|
|
45
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@o2vend/theme-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "O2VEND Theme Development CLI - Standalone tool for local theme development",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"o2vend": "./bin/o2vend"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"o2vend",
|
|
11
|
+
"theme",
|
|
12
|
+
"cli",
|
|
13
|
+
"ecommerce",
|
|
14
|
+
"liquid"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
18
|
+
"build": "echo \"Build complete\""
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"commander": "^11.0.0",
|
|
22
|
+
"express": "^4.18.2",
|
|
23
|
+
"liquidjs": "^10.7.0",
|
|
24
|
+
"axios": "^1.6.0",
|
|
25
|
+
"lodash": "^4.17.21",
|
|
26
|
+
"moment": "^2.29.4",
|
|
27
|
+
"slugify": "^1.6.6",
|
|
28
|
+
"chokidar": "^3.5.3",
|
|
29
|
+
"socket.io": "^4.7.0",
|
|
30
|
+
"chalk": "^4.1.2",
|
|
31
|
+
"inquirer": "^9.2.0",
|
|
32
|
+
"ora": "^5.4.1",
|
|
33
|
+
"boxen": "^7.1.1",
|
|
34
|
+
"table": "^6.8.3",
|
|
35
|
+
"listr": "^0.14.3",
|
|
36
|
+
"dotenv": "^16.3.1",
|
|
37
|
+
"archiver": "^6.0.1",
|
|
38
|
+
"glob": "^10.3.10",
|
|
39
|
+
"fs-extra": "^11.1.1",
|
|
40
|
+
"node-cache": "^5.1.2",
|
|
41
|
+
"http-proxy-middleware": "^2.0.6",
|
|
42
|
+
"open": "^8.4.2"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18.0.0"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"bin/**/*",
|
|
49
|
+
"src/**/*",
|
|
50
|
+
"config/**/*",
|
|
51
|
+
"README.md"
|
|
52
|
+
],
|
|
53
|
+
"repository": {
|
|
54
|
+
"type": "git",
|
|
55
|
+
"url": "https://github.com/Jeyan-Technologies/o2vend-theme-dev-tools.git",
|
|
56
|
+
"directory": "packages/cli"
|
|
57
|
+
},
|
|
58
|
+
"publishConfig": {
|
|
59
|
+
"access": "public",
|
|
60
|
+
"registry": "https://registry.npmjs.org"
|
|
61
|
+
},
|
|
62
|
+
"author": "Jeyan Technologies Private Limited",
|
|
63
|
+
"license": "MIT"
|
|
64
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O2VEND Theme CLI - Check Command
|
|
3
|
+
* Lint and check best practices
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { Command } = require('commander');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const fs = require('fs-extra');
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
|
|
11
|
+
const checkCommand = new Command('check');
|
|
12
|
+
|
|
13
|
+
checkCommand
|
|
14
|
+
.description('Check theme for issues and best practices')
|
|
15
|
+
.option('--strict', 'Enable strict mode')
|
|
16
|
+
.option('--format <format>', 'Output format (table|json|compact)', 'table')
|
|
17
|
+
.option('--cwd <path>', 'Working directory (theme path)', process.cwd())
|
|
18
|
+
.action(async (options) => {
|
|
19
|
+
try {
|
|
20
|
+
console.log(chalk.cyan('🔍 Checking theme...\n'));
|
|
21
|
+
|
|
22
|
+
const themePath = path.resolve(options.cwd);
|
|
23
|
+
const issues = [];
|
|
24
|
+
|
|
25
|
+
if (!fs.existsSync(themePath)) {
|
|
26
|
+
console.error(chalk.red(`Theme directory does not exist: ${themePath}`));
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Performance checks
|
|
31
|
+
const assetFiles = findFiles(themePath, ['css', 'js']);
|
|
32
|
+
assetFiles.forEach(file => {
|
|
33
|
+
const size = fs.statSync(file).size;
|
|
34
|
+
const sizeKB = (size / 1024).toFixed(2);
|
|
35
|
+
|
|
36
|
+
if (size > 500 * 1024) { // > 500KB
|
|
37
|
+
issues.push({
|
|
38
|
+
type: 'performance',
|
|
39
|
+
severity: 'warning',
|
|
40
|
+
file: path.relative(themePath, file),
|
|
41
|
+
message: `Large file: ${sizeKB}KB (consider optimization)`
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Accessibility checks (basic)
|
|
47
|
+
const liquidFiles = findFiles(themePath, 'liquid');
|
|
48
|
+
liquidFiles.forEach(file => {
|
|
49
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
50
|
+
|
|
51
|
+
// Check for images without alt text
|
|
52
|
+
const imgTags = content.match(/<img[^>]*>/g) || [];
|
|
53
|
+
imgTags.forEach(img => {
|
|
54
|
+
if (!img.includes('alt=')) {
|
|
55
|
+
issues.push({
|
|
56
|
+
type: 'accessibility',
|
|
57
|
+
severity: 'warning',
|
|
58
|
+
file: path.relative(themePath, file),
|
|
59
|
+
message: 'Image missing alt attribute'
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Check for form inputs without labels
|
|
65
|
+
const inputTags = content.match(/<input[^>]*>/g) || [];
|
|
66
|
+
inputTags.forEach(input => {
|
|
67
|
+
const id = input.match(/id=["']([^"']+)["']/);
|
|
68
|
+
if (id && !content.includes(`for="${id[1]}"`)) {
|
|
69
|
+
issues.push({
|
|
70
|
+
type: 'accessibility',
|
|
71
|
+
severity: 'warning',
|
|
72
|
+
file: path.relative(themePath, file),
|
|
73
|
+
message: 'Input field should have associated label'
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// SEO checks
|
|
80
|
+
const layoutPath = path.join(themePath, 'layout', 'theme.liquid');
|
|
81
|
+
if (fs.existsSync(layoutPath)) {
|
|
82
|
+
const layoutContent = fs.readFileSync(layoutPath, 'utf8');
|
|
83
|
+
|
|
84
|
+
if (!layoutContent.includes('<title>')) {
|
|
85
|
+
issues.push({
|
|
86
|
+
type: 'seo',
|
|
87
|
+
severity: 'error',
|
|
88
|
+
file: 'layout/theme.liquid',
|
|
89
|
+
message: 'Layout should include <title> tag'
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!layoutContent.includes('meta name="description"')) {
|
|
94
|
+
issues.push({
|
|
95
|
+
type: 'seo',
|
|
96
|
+
severity: 'warning',
|
|
97
|
+
file: 'layout/theme.liquid',
|
|
98
|
+
message: 'Layout should include meta description'
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Best practices
|
|
104
|
+
const settingsSchemaPath = path.join(themePath, 'config', 'settings_schema.json');
|
|
105
|
+
if (!fs.existsSync(settingsSchemaPath)) {
|
|
106
|
+
issues.push({
|
|
107
|
+
type: 'best-practice',
|
|
108
|
+
severity: 'info',
|
|
109
|
+
file: 'config/settings_schema.json',
|
|
110
|
+
message: 'Consider adding settings_schema.json for theme customization'
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Output results
|
|
115
|
+
outputResults(issues, options);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error(chalk.red('❌ Check failed:'), error.message);
|
|
118
|
+
if (error.stack && process.env.DEBUG) {
|
|
119
|
+
console.error(error.stack);
|
|
120
|
+
}
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Find files by extension(s)
|
|
127
|
+
*/
|
|
128
|
+
function findFiles(dir, ext) {
|
|
129
|
+
const extensions = Array.isArray(ext) ? ext : [ext];
|
|
130
|
+
const files = [];
|
|
131
|
+
|
|
132
|
+
if (!fs.existsSync(dir)) return files;
|
|
133
|
+
|
|
134
|
+
const items = fs.readdirSync(dir);
|
|
135
|
+
items.forEach(item => {
|
|
136
|
+
const itemPath = path.join(dir, item);
|
|
137
|
+
const stat = fs.statSync(itemPath);
|
|
138
|
+
if (stat.isDirectory() && !item.startsWith('.') && item !== 'node_modules') {
|
|
139
|
+
files.push(...findFiles(itemPath, ext));
|
|
140
|
+
} else {
|
|
141
|
+
const fileExt = item.split('.').pop();
|
|
142
|
+
if (extensions.includes(fileExt)) {
|
|
143
|
+
files.push(itemPath);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
return files;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Output check results
|
|
153
|
+
*/
|
|
154
|
+
function outputResults(issues, options) {
|
|
155
|
+
if (options.format === 'json') {
|
|
156
|
+
console.log(JSON.stringify(issues, null, 2));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (issues.length === 0) {
|
|
161
|
+
console.log(chalk.green('✅ All checks passed!'));
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Group by type
|
|
166
|
+
const byType = {};
|
|
167
|
+
issues.forEach(issue => {
|
|
168
|
+
if (!byType[issue.type]) {
|
|
169
|
+
byType[issue.type] = [];
|
|
170
|
+
}
|
|
171
|
+
byType[issue.type].push(issue);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Output by type
|
|
175
|
+
Object.keys(byType).forEach(type => {
|
|
176
|
+
const typeIssues = byType[type];
|
|
177
|
+
const typeLabel = type.charAt(0).toUpperCase() + type.slice(1);
|
|
178
|
+
|
|
179
|
+
console.log(chalk.cyan(`\n${typeLabel} (${typeIssues.length}):`));
|
|
180
|
+
|
|
181
|
+
typeIssues.forEach(issue => {
|
|
182
|
+
const icon = issue.severity === 'error' ? '❌' : issue.severity === 'warning' ? '⚠️' : 'ℹ️';
|
|
183
|
+
const color = issue.severity === 'error' ? chalk.red : issue.severity === 'warning' ? chalk.yellow : chalk.blue;
|
|
184
|
+
|
|
185
|
+
if (options.format === 'compact') {
|
|
186
|
+
console.log(color(` ${icon} ${issue.file}: ${issue.message}`));
|
|
187
|
+
} else {
|
|
188
|
+
console.log(color(` ${icon} ${issue.file}`));
|
|
189
|
+
console.log(chalk.gray(` ${issue.message}`));
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const errors = issues.filter(i => i.severity === 'error').length;
|
|
195
|
+
const warnings = issues.filter(i => i.severity === 'warning').length;
|
|
196
|
+
const info = issues.filter(i => i.severity === 'info').length;
|
|
197
|
+
|
|
198
|
+
console.log(chalk.cyan(`\n📊 Summary: ${errors} errors, ${warnings} warnings, ${info} info`));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
module.exports = checkCommand;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O2VEND Theme CLI - Generate Command
|
|
3
|
+
* AI-powered theme generation from natural language
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { Command } = require('commander');
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
|
|
9
|
+
const generateCommand = new Command('generate');
|
|
10
|
+
|
|
11
|
+
generateCommand
|
|
12
|
+
.description('Generate theme from natural language description')
|
|
13
|
+
.argument('<description>', 'Theme description')
|
|
14
|
+
.option('--cwd <path>', 'Output directory', process.cwd())
|
|
15
|
+
.action(async (description, options) => {
|
|
16
|
+
try {
|
|
17
|
+
console.log(chalk.cyan('🤖 Generating theme with AI...\n'));
|
|
18
|
+
|
|
19
|
+
// TODO: Implement AI-powered theme generation
|
|
20
|
+
// 1. Parse description
|
|
21
|
+
// 2. Generate theme structure
|
|
22
|
+
// 3. Generate templates
|
|
23
|
+
// 4. Generate settings schema
|
|
24
|
+
// 5. Generate mock data
|
|
25
|
+
|
|
26
|
+
console.log(chalk.green('✅ Theme generated successfully!'));
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error(chalk.red('❌ Error generating theme:'), error.message);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
module.exports = generateCommand;
|