ecomcoder-cli 1.2.15 → 1.3.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/dist/__tests__/test-utils.d.ts +123 -0
- package/dist/__tests__/test-utils.d.ts.map +1 -0
- package/dist/__tests__/test-utils.js +133 -0
- package/dist/__tests__/test-utils.js.map +1 -0
- package/dist/cli.d.ts +8 -7
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +70 -65
- package/dist/cli.js.map +1 -1
- package/dist/commands/docs/index.d.ts +10 -0
- package/dist/commands/docs/index.d.ts.map +1 -0
- package/dist/commands/docs/index.js +43 -0
- package/dist/commands/docs/index.js.map +1 -0
- package/dist/commands/metafield/index.d.ts +10 -0
- package/dist/commands/metafield/index.d.ts.map +1 -0
- package/dist/commands/metafield/index.js +55 -0
- package/dist/commands/metafield/index.js.map +1 -0
- package/dist/commands/product/__tests__/service.test.d.ts +7 -0
- package/dist/commands/product/__tests__/service.test.d.ts.map +1 -0
- package/dist/commands/product/__tests__/service.test.js +299 -0
- package/dist/commands/product/__tests__/service.test.js.map +1 -0
- package/dist/commands/product/__tests__/update-description.test.d.ts +5 -0
- package/dist/commands/product/__tests__/update-description.test.d.ts.map +1 -0
- package/dist/commands/product/__tests__/update-description.test.js +110 -0
- package/dist/commands/product/__tests__/update-description.test.js.map +1 -0
- package/dist/commands/product/get.d.ts +2 -0
- package/dist/commands/product/get.d.ts.map +1 -0
- package/dist/commands/product/get.js +305 -0
- package/dist/commands/product/get.js.map +1 -0
- package/dist/commands/product/index.d.ts +10 -0
- package/dist/commands/product/index.d.ts.map +1 -0
- package/dist/commands/product/index.js +73 -0
- package/dist/commands/product/index.js.map +1 -0
- package/dist/commands/product/queries.d.ts +32 -0
- package/dist/commands/product/queries.d.ts.map +1 -0
- package/dist/commands/product/queries.js +195 -0
- package/dist/commands/product/queries.js.map +1 -0
- package/dist/commands/product/service.d.ts +51 -0
- package/dist/commands/product/service.d.ts.map +1 -0
- package/dist/commands/product/service.js +237 -0
- package/dist/commands/product/service.js.map +1 -0
- package/dist/commands/product/types.d.ts +165 -0
- package/dist/commands/product/types.d.ts.map +1 -0
- package/dist/commands/product/types.js +6 -0
- package/dist/commands/product/types.js.map +1 -0
- package/dist/commands/product/update-description.d.ts +8 -0
- package/dist/commands/product/update-description.d.ts.map +1 -0
- package/dist/commands/product/update-description.js +86 -0
- package/dist/commands/product/update-description.js.map +1 -0
- package/dist/commands/product/update-price.d.ts +8 -0
- package/dist/commands/product/update-price.d.ts.map +1 -0
- package/dist/commands/product/update-price.js +101 -0
- package/dist/commands/product/update-price.js.map +1 -0
- package/dist/commands/product/update-template.d.ts +8 -0
- package/dist/commands/product/update-template.d.ts.map +1 -0
- package/dist/commands/product/update-template.js +114 -0
- package/dist/commands/product/update-template.js.map +1 -0
- package/dist/commands/product/utils.d.ts +69 -0
- package/dist/commands/product/utils.d.ts.map +1 -0
- package/dist/commands/product/utils.js +180 -0
- package/dist/commands/product/utils.js.map +1 -0
- package/dist/commands/products/index.d.ts +10 -0
- package/dist/commands/products/index.d.ts.map +1 -0
- package/dist/commands/products/index.js +62 -0
- package/dist/commands/products/index.js.map +1 -0
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +11 -0
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/args-parser.d.ts.map +1 -1
- package/dist/lib/args-parser.js +2 -1
- package/dist/lib/args-parser.js.map +1 -1
- package/dist/lib/command-registry.d.ts +64 -0
- package/dist/lib/command-registry.d.ts.map +1 -0
- package/dist/lib/command-registry.js +76 -0
- package/dist/lib/command-registry.js.map +1 -0
- package/package.json +10 -2
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared helpers for testing CLI commands
|
|
5
|
+
*/
|
|
6
|
+
import type { ShopifyCredentials } from '../lib/types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Mock Shopify credentials for testing
|
|
9
|
+
*/
|
|
10
|
+
export declare const mockCredentials: ShopifyCredentials;
|
|
11
|
+
/**
|
|
12
|
+
* Mock GraphQL response helper
|
|
13
|
+
*/
|
|
14
|
+
export declare function mockGraphQLResponse<T>(data: T, errors?: any[]): {
|
|
15
|
+
data: T;
|
|
16
|
+
errors: any[] | undefined;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Mock product data
|
|
20
|
+
*/
|
|
21
|
+
export declare const mockProduct: {
|
|
22
|
+
id: string;
|
|
23
|
+
title: string;
|
|
24
|
+
description: string;
|
|
25
|
+
descriptionHtml: string;
|
|
26
|
+
handle: string;
|
|
27
|
+
productType: string;
|
|
28
|
+
vendor: string;
|
|
29
|
+
tags: string[];
|
|
30
|
+
status: "ACTIVE";
|
|
31
|
+
templateSuffix: null;
|
|
32
|
+
variants: {
|
|
33
|
+
edges: {
|
|
34
|
+
node: {
|
|
35
|
+
id: string;
|
|
36
|
+
title: string;
|
|
37
|
+
sku: string;
|
|
38
|
+
price: string;
|
|
39
|
+
compareAtPrice: null;
|
|
40
|
+
inventoryQuantity: number;
|
|
41
|
+
availableForSale: boolean;
|
|
42
|
+
};
|
|
43
|
+
}[];
|
|
44
|
+
};
|
|
45
|
+
images: {
|
|
46
|
+
edges: never[];
|
|
47
|
+
};
|
|
48
|
+
priceRangeV2: {
|
|
49
|
+
minVariantPrice: {
|
|
50
|
+
amount: string;
|
|
51
|
+
currencyCode: string;
|
|
52
|
+
};
|
|
53
|
+
maxVariantPrice: {
|
|
54
|
+
amount: string;
|
|
55
|
+
currencyCode: string;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Mock product with multiple variants
|
|
61
|
+
*/
|
|
62
|
+
export declare const mockProductMultipleVariants: {
|
|
63
|
+
variants: {
|
|
64
|
+
edges: {
|
|
65
|
+
node: {
|
|
66
|
+
id: string;
|
|
67
|
+
title: string;
|
|
68
|
+
sku: string;
|
|
69
|
+
price: string;
|
|
70
|
+
compareAtPrice: null;
|
|
71
|
+
inventoryQuantity: number;
|
|
72
|
+
availableForSale: boolean;
|
|
73
|
+
};
|
|
74
|
+
}[];
|
|
75
|
+
};
|
|
76
|
+
id: string;
|
|
77
|
+
title: string;
|
|
78
|
+
description: string;
|
|
79
|
+
descriptionHtml: string;
|
|
80
|
+
handle: string;
|
|
81
|
+
productType: string;
|
|
82
|
+
vendor: string;
|
|
83
|
+
tags: string[];
|
|
84
|
+
status: "ACTIVE";
|
|
85
|
+
templateSuffix: null;
|
|
86
|
+
images: {
|
|
87
|
+
edges: never[];
|
|
88
|
+
};
|
|
89
|
+
priceRangeV2: {
|
|
90
|
+
minVariantPrice: {
|
|
91
|
+
amount: string;
|
|
92
|
+
currencyCode: string;
|
|
93
|
+
};
|
|
94
|
+
maxVariantPrice: {
|
|
95
|
+
amount: string;
|
|
96
|
+
currencyCode: string;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Mock variant data
|
|
102
|
+
*/
|
|
103
|
+
export declare const mockVariant: {
|
|
104
|
+
id: string;
|
|
105
|
+
price: string;
|
|
106
|
+
compareAtPrice: null;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Mock user errors
|
|
110
|
+
*/
|
|
111
|
+
export declare const mockUserErrors: {
|
|
112
|
+
field: string[];
|
|
113
|
+
message: string;
|
|
114
|
+
}[];
|
|
115
|
+
/**
|
|
116
|
+
* Parse JSON output from CLI commands
|
|
117
|
+
*/
|
|
118
|
+
export declare function parseCommandOutput(output: string): any;
|
|
119
|
+
/**
|
|
120
|
+
* Create mock shopifyGraphQL function
|
|
121
|
+
*/
|
|
122
|
+
export declare function createMockShopifyGraphQL(mockResponse: any): (credentials: ShopifyCredentials, query: string, variables?: any) => Promise<any>;
|
|
123
|
+
//# sourceMappingURL=test-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../../src/__tests__/test-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,kBAG7B,CAAC;AAEF;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE;;;EAK7D;AAED;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuCvB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BvC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW;;;;CAIvB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc;;;GAK1B,CAAC;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAMtD;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,GAAG,IAC1C,aAAa,kBAAkB,EAAE,OAAO,MAAM,EAAE,YAAY,GAAG,kBAG9E"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared helpers for testing CLI commands
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Mock Shopify credentials for testing
|
|
8
|
+
*/
|
|
9
|
+
export const mockCredentials = {
|
|
10
|
+
shopifyUrl: 'https://test-shop.myshopify.com',
|
|
11
|
+
shopifyAdminPassword: 'shpat_test_token_12345'
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Mock GraphQL response helper
|
|
15
|
+
*/
|
|
16
|
+
export function mockGraphQLResponse(data, errors) {
|
|
17
|
+
return {
|
|
18
|
+
data,
|
|
19
|
+
errors: errors || undefined
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Mock product data
|
|
24
|
+
*/
|
|
25
|
+
export const mockProduct = {
|
|
26
|
+
id: 'gid://shopify/Product/123456789',
|
|
27
|
+
title: 'Test Product',
|
|
28
|
+
description: 'Test description',
|
|
29
|
+
descriptionHtml: '<p>Test description</p>',
|
|
30
|
+
handle: 'test-product',
|
|
31
|
+
productType: 'Test Type',
|
|
32
|
+
vendor: 'Test Vendor',
|
|
33
|
+
tags: ['test', 'sample'],
|
|
34
|
+
status: 'ACTIVE',
|
|
35
|
+
templateSuffix: null,
|
|
36
|
+
variants: {
|
|
37
|
+
edges: [
|
|
38
|
+
{
|
|
39
|
+
node: {
|
|
40
|
+
id: 'gid://shopify/ProductVariant/987654321',
|
|
41
|
+
title: 'Default Title',
|
|
42
|
+
sku: 'TEST-SKU',
|
|
43
|
+
price: '29.99',
|
|
44
|
+
compareAtPrice: null,
|
|
45
|
+
inventoryQuantity: 100,
|
|
46
|
+
availableForSale: true
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
images: {
|
|
52
|
+
edges: []
|
|
53
|
+
},
|
|
54
|
+
priceRangeV2: {
|
|
55
|
+
minVariantPrice: {
|
|
56
|
+
amount: '29.99',
|
|
57
|
+
currencyCode: 'USD'
|
|
58
|
+
},
|
|
59
|
+
maxVariantPrice: {
|
|
60
|
+
amount: '29.99',
|
|
61
|
+
currencyCode: 'USD'
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Mock product with multiple variants
|
|
67
|
+
*/
|
|
68
|
+
export const mockProductMultipleVariants = {
|
|
69
|
+
...mockProduct,
|
|
70
|
+
variants: {
|
|
71
|
+
edges: [
|
|
72
|
+
{
|
|
73
|
+
node: {
|
|
74
|
+
id: 'gid://shopify/ProductVariant/111',
|
|
75
|
+
title: 'Small',
|
|
76
|
+
sku: 'TEST-SKU-S',
|
|
77
|
+
price: '29.99',
|
|
78
|
+
compareAtPrice: null,
|
|
79
|
+
inventoryQuantity: 50,
|
|
80
|
+
availableForSale: true,
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
node: {
|
|
85
|
+
id: 'gid://shopify/ProductVariant/222',
|
|
86
|
+
title: 'Medium',
|
|
87
|
+
sku: 'TEST-SKU-M',
|
|
88
|
+
price: '29.99',
|
|
89
|
+
compareAtPrice: null,
|
|
90
|
+
inventoryQuantity: 50,
|
|
91
|
+
availableForSale: true,
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Mock variant data
|
|
99
|
+
*/
|
|
100
|
+
export const mockVariant = {
|
|
101
|
+
id: 'gid://shopify/ProductVariant/987654321',
|
|
102
|
+
price: '29.99',
|
|
103
|
+
compareAtPrice: null
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Mock user errors
|
|
107
|
+
*/
|
|
108
|
+
export const mockUserErrors = [
|
|
109
|
+
{
|
|
110
|
+
field: ['input', 'price'],
|
|
111
|
+
message: 'Price must be positive'
|
|
112
|
+
}
|
|
113
|
+
];
|
|
114
|
+
/**
|
|
115
|
+
* Parse JSON output from CLI commands
|
|
116
|
+
*/
|
|
117
|
+
export function parseCommandOutput(output) {
|
|
118
|
+
try {
|
|
119
|
+
return JSON.parse(output);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
throw new Error(`Failed to parse command output: ${output}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Create mock shopifyGraphQL function
|
|
127
|
+
*/
|
|
128
|
+
export function createMockShopifyGraphQL(mockResponse) {
|
|
129
|
+
return async (credentials, query, variables) => {
|
|
130
|
+
return mockResponse;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=test-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../src/__tests__/test-utils.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* EcomCoder CLI - Main Entry Point
|
|
3
|
+
* EcomCoder CLI - Main Entry Point (Refactored)
|
|
4
4
|
*
|
|
5
|
-
* Command
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* Architecture: Command Registry Pattern
|
|
6
|
+
*
|
|
7
|
+
* Benefits:
|
|
8
|
+
* ✅ Open/Closed Principle - Add commands without modifying this file
|
|
9
|
+
* ✅ Single Responsibility - This file only routes, doesn't know command details
|
|
10
|
+
* ✅ Scalability - Supports unlimited commands
|
|
11
|
+
* ✅ Testability - Easy to test routing logic
|
|
11
12
|
*/
|
|
12
13
|
export {};
|
|
13
14
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG"}
|
package/dist/cli.js
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* EcomCoder CLI - Main Entry Point
|
|
3
|
+
* EcomCoder CLI - Main Entry Point (Refactored)
|
|
4
4
|
*
|
|
5
|
-
* Command
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* Architecture: Command Registry Pattern
|
|
6
|
+
*
|
|
7
|
+
* Benefits:
|
|
8
|
+
* ✅ Open/Closed Principle - Add commands without modifying this file
|
|
9
|
+
* ✅ Single Responsibility - This file only routes, doesn't know command details
|
|
10
|
+
* ✅ Scalability - Supports unlimited commands
|
|
11
|
+
* ✅ Testability - Easy to test routing logic
|
|
11
12
|
*/
|
|
12
13
|
import { getPositionalArgs } from './lib/args-parser.js';
|
|
13
|
-
|
|
14
|
+
import { registry } from './lib/command-registry.js';
|
|
15
|
+
// Register all command groups
|
|
16
|
+
import { registerProductCommands } from './commands/product/index.js';
|
|
17
|
+
import { registerMetafieldCommands } from './commands/metafield/index.js';
|
|
18
|
+
import { registerProductsCommands } from './commands/products/index.js';
|
|
19
|
+
import { registerDocsCommands } from './commands/docs/index.js';
|
|
20
|
+
// Initialize registry
|
|
21
|
+
registerProductCommands();
|
|
22
|
+
registerMetafieldCommands();
|
|
23
|
+
registerProductsCommands();
|
|
24
|
+
registerDocsCommands();
|
|
25
|
+
function showMainHelp() {
|
|
14
26
|
console.log(`
|
|
15
27
|
EcomCoder CLI - Shopify Development Utilities
|
|
16
28
|
|
|
@@ -18,12 +30,16 @@ USAGE:
|
|
|
18
30
|
ecomcoder <command> <subcommand> [options]
|
|
19
31
|
|
|
20
32
|
COMMANDS:
|
|
21
|
-
products create
|
|
22
|
-
products list
|
|
23
|
-
products set-rating
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
products create Create dummy Shopify products for testing
|
|
34
|
+
products list List products in your Shopify store
|
|
35
|
+
products set-rating Set rating metafields on a product
|
|
36
|
+
product get Get detailed product data
|
|
37
|
+
product update-description Update product description
|
|
38
|
+
product update-price Update product price and compare-at price
|
|
39
|
+
product update-template Change product template assignment
|
|
40
|
+
metafield create Create metafield definition
|
|
41
|
+
metafield get Get metafield definition(s)
|
|
42
|
+
docs search Search Shopify theme documentation
|
|
27
43
|
|
|
28
44
|
GLOBAL OPTIONS:
|
|
29
45
|
--session-id Session ID for authentication (auto-provided when used with Claude)
|
|
@@ -46,6 +62,19 @@ EXAMPLES:
|
|
|
46
62
|
# Set product rating
|
|
47
63
|
ecomcoder products set-rating --product-id="gid://shopify/Product/123" --rating=4.5 --count=127
|
|
48
64
|
|
|
65
|
+
# Get product details
|
|
66
|
+
ecomcoder product get --id=123456789
|
|
67
|
+
ecomcoder product get --title="Blue T-Shirt"
|
|
68
|
+
|
|
69
|
+
# Update product description
|
|
70
|
+
ecomcoder product update-description --id=123 --description="Premium cotton t-shirt"
|
|
71
|
+
|
|
72
|
+
# Update product price
|
|
73
|
+
ecomcoder product update-price --id=123 --price=34.99 --compare-at-price=49.99
|
|
74
|
+
|
|
75
|
+
# Change product template
|
|
76
|
+
ecomcoder product update-template --id=123 --template=premium
|
|
77
|
+
|
|
49
78
|
# Create product-level metafield
|
|
50
79
|
ecomcoder metafield create --name="Rating" --key=rating --type=number_decimal --owner-type=PRODUCT
|
|
51
80
|
|
|
@@ -64,71 +93,47 @@ For more help on specific commands, run:
|
|
|
64
93
|
}
|
|
65
94
|
async function main() {
|
|
66
95
|
const args = process.argv.slice(2);
|
|
67
|
-
// Show help
|
|
96
|
+
// Show help if no arguments
|
|
68
97
|
if (args.length === 0) {
|
|
69
|
-
|
|
98
|
+
showMainHelp();
|
|
70
99
|
process.exit(0);
|
|
71
100
|
}
|
|
72
101
|
const positional = getPositionalArgs(args);
|
|
73
102
|
const [command, subcommand] = positional;
|
|
74
103
|
// Show main help if help flag with no command
|
|
75
104
|
if ((args.includes('--help') || args.includes('-h')) && !command) {
|
|
76
|
-
|
|
105
|
+
showMainHelp();
|
|
77
106
|
process.exit(0);
|
|
78
107
|
}
|
|
79
|
-
// Route to appropriate command handler
|
|
80
108
|
try {
|
|
81
|
-
if
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
else if (subcommand === 'list') {
|
|
87
|
-
const { run } = await import('./commands/list-products.js');
|
|
88
|
-
await run(args.slice(2));
|
|
89
|
-
}
|
|
90
|
-
else if (subcommand === 'set-rating') {
|
|
91
|
-
const { run } = await import('./commands/set-product-rating.js');
|
|
92
|
-
await run(args.slice(2));
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
console.error(`Unknown products subcommand: ${subcommand}`);
|
|
96
|
-
console.error(`Valid subcommands: create, list, set-rating`);
|
|
97
|
-
process.exit(1);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
else if (command === 'metafield') {
|
|
101
|
-
if (subcommand === 'create') {
|
|
102
|
-
const { run } = await import('./commands/create-metafield.js');
|
|
103
|
-
await run(args.slice(2));
|
|
104
|
-
}
|
|
105
|
-
else if (subcommand === 'get') {
|
|
106
|
-
const { run } = await import('./commands/get-metafield.js');
|
|
107
|
-
await run(args.slice(2));
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
console.error(`Unknown metafield subcommand: ${subcommand}`);
|
|
111
|
-
console.error(`Valid subcommands: create, get`);
|
|
112
|
-
process.exit(1);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
else if (command === 'docs') {
|
|
116
|
-
if (subcommand === 'search') {
|
|
117
|
-
const { run } = await import('./commands/docs-search.js');
|
|
118
|
-
await run(args.slice(2));
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
console.error(`Unknown docs subcommand: ${subcommand}`);
|
|
122
|
-
console.error(`Valid subcommands: search`);
|
|
123
|
-
process.exit(1);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
109
|
+
// Check if command group exists
|
|
110
|
+
const group = registry.getGroup(command);
|
|
111
|
+
if (!group) {
|
|
112
|
+
// Command not found
|
|
113
|
+
const availableCommands = registry.getAllCommands();
|
|
127
114
|
console.error(`Unknown command: ${command}`);
|
|
128
|
-
console.error(`Valid commands:
|
|
115
|
+
console.error(`Valid commands: ${availableCommands.join(', ')}`);
|
|
129
116
|
console.error(`Run 'ecomcoder --help' for more information`);
|
|
130
117
|
process.exit(1);
|
|
131
118
|
}
|
|
119
|
+
// Show group help ONLY if no subcommand
|
|
120
|
+
if (!subcommand) {
|
|
121
|
+
group.showHelp();
|
|
122
|
+
process.exit(0);
|
|
123
|
+
}
|
|
124
|
+
// Try to get command handler
|
|
125
|
+
const handler = await registry.get(command, subcommand);
|
|
126
|
+
if (!handler) {
|
|
127
|
+
// Subcommand not found
|
|
128
|
+
const availableCommands = registry.getCommandsInGroup(command)
|
|
129
|
+
.map(cmd => cmd.subcommand)
|
|
130
|
+
.filter(Boolean);
|
|
131
|
+
console.error(`Unknown ${command} subcommand: ${subcommand}`);
|
|
132
|
+
console.error(`Valid subcommands: ${availableCommands.join(', ')}`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
// Execute command (command itself handles --help)
|
|
136
|
+
await handler.run(args.slice(2)); // Pass remaining args
|
|
132
137
|
}
|
|
133
138
|
catch (error) {
|
|
134
139
|
console.error(`Error executing command: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAErD,8BAA8B;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,sBAAsB;AACtB,uBAAuB,EAAE,CAAC;AAC1B,yBAAyB,EAAE,CAAC;AAC5B,wBAAwB,EAAE,CAAC;AAC3B,oBAAoB,EAAE,CAAC;AAEvB,SAAS,YAAY;IACnB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkEb,CAAC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,4BAA4B;IAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,YAAY,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,UAAU,CAAC;IAEzC,8CAA8C;IAC9C,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACjE,YAAY,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,gCAAgC;QAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAEzC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,oBAAoB;YACpB,MAAM,iBAAiB,GAAG,QAAQ,CAAC,cAAc,EAAE,CAAC;YACpD,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;YAC7C,OAAO,CAAC,KAAK,CAAC,mBAAmB,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACjE,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;YAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,wCAAwC;QACxC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,KAAK,CAAC,QAAQ,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,6BAA6B;QAC7B,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QAExD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,uBAAuB;YACvB,MAAM,iBAAiB,GAAG,QAAQ,CAAC,kBAAkB,CAAC,OAAO,CAAC;iBAC3D,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC;iBAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;YAEnB,OAAO,CAAC,KAAK,CAAC,WAAW,OAAO,gBAAgB,UAAU,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,KAAK,CAAC,sBAAsB,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,kDAAkD;QAClD,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB;IAE1D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,4BAA4B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;QACtG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/docs/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAiC3C"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docs Commands Registration
|
|
3
|
+
*
|
|
4
|
+
* Following Open/Closed Principle - commands register themselves
|
|
5
|
+
*/
|
|
6
|
+
import { registry } from '../../lib/command-registry.js';
|
|
7
|
+
/**
|
|
8
|
+
* Register all docs commands
|
|
9
|
+
*/
|
|
10
|
+
export function registerDocsCommands() {
|
|
11
|
+
// Register command group
|
|
12
|
+
registry.registerGroup({
|
|
13
|
+
command: 'docs',
|
|
14
|
+
description: 'Search Shopify theme documentation',
|
|
15
|
+
showHelp: () => {
|
|
16
|
+
console.log(`
|
|
17
|
+
Docs Commands - Search Shopify theme documentation
|
|
18
|
+
|
|
19
|
+
USAGE:
|
|
20
|
+
ecomcoder docs <subcommand> [options]
|
|
21
|
+
|
|
22
|
+
SUBCOMMANDS:
|
|
23
|
+
search Search Shopify theme docs using RAG
|
|
24
|
+
|
|
25
|
+
EXAMPLES:
|
|
26
|
+
# Search Shopify theme docs
|
|
27
|
+
ecomcoder docs search --query="How do sections work?"
|
|
28
|
+
ecomcoder docs search --query="Liquid filters for dates"
|
|
29
|
+
|
|
30
|
+
For detailed help on a specific subcommand:
|
|
31
|
+
ecomcoder docs <subcommand> --help
|
|
32
|
+
`);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
// Register individual subcommands
|
|
36
|
+
registry.register({
|
|
37
|
+
command: 'docs',
|
|
38
|
+
subcommand: 'search',
|
|
39
|
+
description: 'Search Shopify theme documentation',
|
|
40
|
+
handler: async () => await import('../docs-search.js')
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/docs/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAEzD;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,yBAAyB;IACzB,QAAQ,CAAC,aAAa,CAAC;QACrB,OAAO,EAAE,MAAM;QACf,WAAW,EAAE,oCAAoC;QACjD,QAAQ,EAAE,GAAG,EAAE;YACb,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;CAgBjB,CAAC,CAAC;QACC,CAAC;KACF,CAAC,CAAC;IAEH,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,MAAM;QACf,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,oCAAoC;QACjD,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,mBAAmB,CAAC;KACvD,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metafield Commands Registration
|
|
3
|
+
*
|
|
4
|
+
* Following Open/Closed Principle - commands register themselves
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Register all metafield commands
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerMetafieldCommands(): void;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/metafield/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CA8ChD"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metafield Commands Registration
|
|
3
|
+
*
|
|
4
|
+
* Following Open/Closed Principle - commands register themselves
|
|
5
|
+
*/
|
|
6
|
+
import { registry } from '../../lib/command-registry.js';
|
|
7
|
+
/**
|
|
8
|
+
* Register all metafield commands
|
|
9
|
+
*/
|
|
10
|
+
export function registerMetafieldCommands() {
|
|
11
|
+
// Register command group
|
|
12
|
+
registry.registerGroup({
|
|
13
|
+
command: 'metafield',
|
|
14
|
+
description: 'Manage Shopify metafield definitions',
|
|
15
|
+
showHelp: () => {
|
|
16
|
+
console.log(`
|
|
17
|
+
Metafield Commands - Manage Shopify metafield definitions
|
|
18
|
+
|
|
19
|
+
USAGE:
|
|
20
|
+
ecomcoder metafield <subcommand> [options]
|
|
21
|
+
|
|
22
|
+
SUBCOMMANDS:
|
|
23
|
+
create Create metafield definition
|
|
24
|
+
get Get metafield definition(s)
|
|
25
|
+
|
|
26
|
+
EXAMPLES:
|
|
27
|
+
# Create product-level metafield
|
|
28
|
+
ecomcoder metafield create --name="Rating" --key=rating --type=number_decimal --owner-type=PRODUCT
|
|
29
|
+
|
|
30
|
+
# Create shop-level metafield (global)
|
|
31
|
+
ecomcoder metafield create --name="Cart Upsell" --key=cart_upsell --type=product_reference --owner-type=SHOP
|
|
32
|
+
|
|
33
|
+
# Get metafield definition
|
|
34
|
+
ecomcoder metafield get --namespace=ecomcoder --key=upsell --owner-type=PRODUCT
|
|
35
|
+
|
|
36
|
+
For detailed help on a specific subcommand:
|
|
37
|
+
ecomcoder metafield <subcommand> --help
|
|
38
|
+
`);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
// Register individual subcommands
|
|
42
|
+
registry.register({
|
|
43
|
+
command: 'metafield',
|
|
44
|
+
subcommand: 'create',
|
|
45
|
+
description: 'Create metafield definition',
|
|
46
|
+
handler: async () => await import('../create-metafield.js')
|
|
47
|
+
});
|
|
48
|
+
registry.register({
|
|
49
|
+
command: 'metafield',
|
|
50
|
+
subcommand: 'get',
|
|
51
|
+
description: 'Get metafield definition(s)',
|
|
52
|
+
handler: async () => await import('../get-metafield.js')
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/metafield/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAEzD;;GAEG;AACH,MAAM,UAAU,yBAAyB;IACvC,yBAAyB;IACzB,QAAQ,CAAC,aAAa,CAAC;QACrB,OAAO,EAAE,WAAW;QACpB,WAAW,EAAE,sCAAsC;QACnD,QAAQ,EAAE,GAAG,EAAE;YACb,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;CAsBjB,CAAC,CAAC;QACC,CAAC;KACF,CAAC,CAAC;IAEH,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,WAAW;QACpB,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,6BAA6B;QAC1C,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,wBAAwB,CAAC;KAC5D,CAAC,CAAC;IAEH,QAAQ,CAAC,QAAQ,CAAC;QAChB,OAAO,EAAE,WAAW;QACpB,UAAU,EAAE,KAAK;QACjB,WAAW,EAAE,6BAA6B;QAC1C,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,MAAM,CAAC,qBAAqB,CAAC;KACzD,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.test.d.ts","sourceRoot":"","sources":["../../../../src/commands/product/__tests__/service.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|