@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.
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;