shoplazza-cli 0.0.1
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/.editorconfig +28 -0
- package/.prettierrc +9 -0
- package/LICENSE +21 -0
- package/README.md +208 -0
- package/bin/shoplazza +117 -0
- package/fixtures/assets/blog.scss +74 -0
- package/fixtures/assets/cart_modal.scss +450 -0
- package/fixtures/assets/collection_detail.js +234 -0
- package/fixtures/assets/collection_detail.scss +345 -0
- package/fixtures/assets/collection_list.scss +11 -0
- package/fixtures/assets/collection_slider.scss +169 -0
- package/fixtures/assets/feature_columns.scss +26 -0
- package/fixtures/assets/feature_product.scss +109 -0
- package/fixtures/assets/footer.js +58 -0
- package/fixtures/assets/footer.scss +337 -0
- package/fixtures/assets/four_images.scss +29 -0
- package/fixtures/assets/gallery.scss +55 -0
- package/fixtures/assets/header.js +178 -0
- package/fixtures/assets/header.scss +929 -0
- package/fixtures/assets/image_text.scss +72 -0
- package/fixtures/assets/logo_bar.scss +11 -0
- package/fixtures/assets/newsletter.scss +90 -0
- package/fixtures/assets/not_found.scss +39 -0
- package/fixtures/assets/page_detail.scss +16 -0
- package/fixtures/assets/pagination.scss +150 -0
- package/fixtures/assets/postcss.config.js +6 -0
- package/fixtures/assets/product_description.scss +88 -0
- package/fixtures/assets/product_detail.js +634 -0
- package/fixtures/assets/product_detail.scss +1106 -0
- package/fixtures/assets/relative_product.scss +45 -0
- package/fixtures/assets/reviews.scss +70 -0
- package/fixtures/assets/rich_text.scss +71 -0
- package/fixtures/assets/search.js +87 -0
- package/fixtures/assets/search.scss +67 -0
- package/fixtures/assets/slide.scss +51 -0
- package/fixtures/assets/slider.scss +141 -0
- package/fixtures/assets/theme.css +976 -0
- package/fixtures/assets/theme.scss +1100 -0
- package/fixtures/assets/three_images.scss +20 -0
- package/fixtures/assets/tools.scss +23 -0
- package/fixtures/assets/two_images.scss +24 -0
- package/fixtures/assets/video.scss +45 -0
- package/fixtures/assets/video_text.scss +63 -0
- package/fixtures/config/settings_data.json +107 -0
- package/fixtures/config/settings_schema.json +690 -0
- package/fixtures/layout/theme.liquid +76 -0
- package/fixtures/locales/ar-SA.json +212 -0
- package/fixtures/locales/de-DE.json +290 -0
- package/fixtures/locales/en-US.json +290 -0
- package/fixtures/locales/es-ES.json +290 -0
- package/fixtures/locales/fr-FR.json +290 -0
- package/fixtures/locales/id-ID.json +212 -0
- package/fixtures/locales/it-IT.json +212 -0
- package/fixtures/locales/ja-JP.json +289 -0
- package/fixtures/locales/ko-KR.json +290 -0
- package/fixtures/locales/nl-NL.json +290 -0
- package/fixtures/locales/pl-PL.json +290 -0
- package/fixtures/locales/pt-PT.json +212 -0
- package/fixtures/locales/ru-RU.json +212 -0
- package/fixtures/locales/th-TH.json +212 -0
- package/fixtures/locales/zh-CN.json +290 -0
- package/fixtures/locales/zh-TW.json +290 -0
- package/fixtures/sections/apps.liquid +47 -0
- package/fixtures/sections/blog.liquid +137 -0
- package/fixtures/sections/collection_desc.liquid +34 -0
- package/fixtures/sections/collection_detail.liquid +436 -0
- package/fixtures/sections/collection_image.liquid +104 -0
- package/fixtures/sections/collection_list.liquid +161 -0
- package/fixtures/sections/collection_name.liquid +34 -0
- package/fixtures/sections/collection_slider.liquid +330 -0
- package/fixtures/sections/feature_columns.liquid +275 -0
- package/fixtures/sections/feature_product.liquid +227 -0
- package/fixtures/sections/footer.liquid +488 -0
- package/fixtures/sections/four_images.liquid +160 -0
- package/fixtures/sections/gallery.liquid +258 -0
- package/fixtures/sections/header.liquid +1157 -0
- package/fixtures/sections/html.liquid +40 -0
- package/fixtures/sections/image_text.liquid +350 -0
- package/fixtures/sections/instagram_plus.liquid +393 -0
- package/fixtures/sections/logo_bar.liquid +183 -0
- package/fixtures/sections/newsletter.liquid +225 -0
- package/fixtures/sections/not_found.liquid +39 -0
- package/fixtures/sections/overlay_image.liquid +648 -0
- package/fixtures/sections/page_detail.liquid +39 -0
- package/fixtures/sections/photo_collection.liquid +433 -0
- package/fixtures/sections/product_description.liquid +208 -0
- package/fixtures/sections/product_detail.liquid +611 -0
- package/fixtures/sections/products.liquid +216 -0
- package/fixtures/sections/relative_product.liquid +121 -0
- package/fixtures/sections/reviews.liquid +115 -0
- package/fixtures/sections/rich_text.liquid +157 -0
- package/fixtures/sections/search.liquid +163 -0
- package/fixtures/sections/slide.liquid +719 -0
- package/fixtures/sections/three_images.liquid +157 -0
- package/fixtures/sections/two_images.liquid +125 -0
- package/fixtures/sections/video.liquid +95 -0
- package/fixtures/sections/video_text.liquid +128 -0
- package/fixtures/snippets/bgset.liquid +21 -0
- package/fixtures/snippets/card_title.liquid +8 -0
- package/fixtures/snippets/cart_modal.liquid +74 -0
- package/fixtures/snippets/collection.liquid +77 -0
- package/fixtures/snippets/collection_filter_modal.liquid +56 -0
- package/fixtures/snippets/default_image_4.liquid +14 -0
- package/fixtures/snippets/default_image_6.liquid +18 -0
- package/fixtures/snippets/default_image_8.liquid +23 -0
- package/fixtures/snippets/four_images_item.liquid +8 -0
- package/fixtures/snippets/header_ads.liquid +95 -0
- package/fixtures/snippets/hero_image.liquid +94 -0
- package/fixtures/snippets/icon_video_play_large.liquid +1 -0
- package/fixtures/snippets/icon_video_play_medium.liquid +4 -0
- package/fixtures/snippets/icon_video_play_small.liquid +4 -0
- package/fixtures/snippets/lazyimg.liquid +22 -0
- package/fixtures/snippets/lazyimg_art.liquid +36 -0
- package/fixtures/snippets/lazysizes.liquid +41 -0
- package/fixtures/snippets/link.liquid +2 -0
- package/fixtures/snippets/pagination.liquid +48 -0
- package/fixtures/snippets/product.liquid +126 -0
- package/fixtures/snippets/product_art_tpl.liquid +152 -0
- package/fixtures/snippets/product_info_body.liquid +337 -0
- package/fixtures/snippets/product_info_tpl.liquid +423 -0
- package/fixtures/snippets/product_label.liquid +46 -0
- package/fixtures/snippets/settings.liquid +295 -0
- package/fixtures/snippets/social-meta-tags.liquid +106 -0
- package/fixtures/snippets/video_html.liquid +11 -0
- package/fixtures/snippets/video_source.liquid +98 -0
- package/fixtures/snippets/video_thumb_icon.liquid +2 -0
- package/fixtures/templates/404.liquid +1 -0
- package/fixtures/templates/collection.liquid +92 -0
- package/fixtures/templates/index.liquid +206 -0
- package/fixtures/templates/page.liquid +1 -0
- package/fixtures/templates/product.liquid +99 -0
- package/fixtures/templates/search.liquid +1 -0
- package/jest.config.js +192 -0
- package/lib/__tests__/log.test.js +15 -0
- package/lib/__tests__/utils.test.js +69 -0
- package/lib/auth/__mocks__/getCode.js +7 -0
- package/lib/auth/__mocks__/index.js +0 -0
- package/lib/auth/child.js +23 -0
- package/lib/auth/getCode.js +35 -0
- package/lib/auth/index.js +91 -0
- package/lib/commands/__tests__/login.test.js +77 -0
- package/lib/commands/__tests__/logout.test.js +29 -0
- package/lib/commands/__tests__/store.test.js +44 -0
- package/lib/commands/__tests__/switch.test.js +45 -0
- package/lib/commands/login.js +99 -0
- package/lib/commands/logout.js +14 -0
- package/lib/commands/store.js +14 -0
- package/lib/commands/switch.js +52 -0
- package/lib/commands/theme/__tests__/delete.test.js +49 -0
- package/lib/commands/theme/__tests__/init.test.js +21 -0
- package/lib/commands/theme/__tests__/list.test.js +80 -0
- package/lib/commands/theme/__tests__/package.test.js +17 -0
- package/lib/commands/theme/__tests__/publish.test.js +61 -0
- package/lib/commands/theme/__tests__/pull.test.js +69 -0
- package/lib/commands/theme/__tests__/push.test.js +63 -0
- package/lib/commands/theme/__tests__/serve.test.js +107 -0
- package/lib/commands/theme/delete.js +64 -0
- package/lib/commands/theme/init.js +51 -0
- package/lib/commands/theme/list.js +28 -0
- package/lib/commands/theme/package.js +37 -0
- package/lib/commands/theme/publish.js +56 -0
- package/lib/commands/theme/pull.js +62 -0
- package/lib/commands/theme/push.js +106 -0
- package/lib/commands/theme/serve.js +153 -0
- package/lib/commands/theme/share.js +20 -0
- package/lib/commands/version.js +6 -0
- package/lib/config.js +5 -0
- package/lib/db/__mocks__/index.js +9 -0
- package/lib/db/__tests__/analytics.test.js +19 -0
- package/lib/db/__tests__/user.test.js +20 -0
- package/lib/db/analytics.js +48 -0
- package/lib/db/index.js +9 -0
- package/lib/db/user.js +68 -0
- package/lib/log.js +13 -0
- package/lib/openAPI/__mocks__/index.js +20 -0
- package/lib/openAPI/api.js +76 -0
- package/lib/openAPI/index.js +46 -0
- package/lib/report.js +37 -0
- package/lib/tracing.js +50 -0
- package/lib/utils.js +48 -0
- package/package.json +54 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const MockAdapter = require('axios-mock-adapter');
|
|
4
|
+
const publishCommand = require('../publish');
|
|
5
|
+
const openAPI = require('../../../openAPI');
|
|
6
|
+
const { set, empty } = require('../../../db/user');
|
|
7
|
+
|
|
8
|
+
jest.mock('inquirer', () => ({
|
|
9
|
+
prompt: () => Promise.resolve({ confirm: 'Yes' })
|
|
10
|
+
}));
|
|
11
|
+
jest.mock('../../../db');
|
|
12
|
+
jest.mock('../../../openAPI/index');
|
|
13
|
+
|
|
14
|
+
describe('theme publish', () => {
|
|
15
|
+
let mock;
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
set({
|
|
19
|
+
store_domain: 'developer.myshoplaza.com'
|
|
20
|
+
});
|
|
21
|
+
mock = new MockAdapter(openAPI);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
mock.reset();
|
|
26
|
+
empty();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('publish success', async () => {
|
|
30
|
+
mock.onGet(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id`).replyOnce(200, {
|
|
31
|
+
data: { name: 'TestLifeStyle', merchant_theme_id: 'merchant_theme_id' }
|
|
32
|
+
});
|
|
33
|
+
mock.onPatch(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id/publish`).replyOnce(200);
|
|
34
|
+
|
|
35
|
+
process.chdir(path.join(process.cwd(), '/fixtures'));
|
|
36
|
+
|
|
37
|
+
console.log = jest.fn();
|
|
38
|
+
await publishCommand({
|
|
39
|
+
theme: 'theme_id'
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
expect(console.log.mock.calls[0][0]).toBe(
|
|
43
|
+
chalk.green(`✓ Your theme is now live at https://developer.myshoplaza.com`)
|
|
44
|
+
);
|
|
45
|
+
process.chdir(path.join(process.cwd(), '../'));
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('publish failed', async () => {
|
|
49
|
+
mock.onGet(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id`).replyOnce(200, {
|
|
50
|
+
data: { name: 'TestLifeStyle', merchant_theme_id: 'merchant_theme_id' }
|
|
51
|
+
});
|
|
52
|
+
mock.onPatch(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id/publish`).replyOnce(500);
|
|
53
|
+
|
|
54
|
+
console.log = jest.fn();
|
|
55
|
+
await publishCommand({
|
|
56
|
+
theme: 'theme_id'
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(console.log.mock.calls[0][0]).toBe(chalk.red(`✗ Failed to publish theme`));
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const MockAdapter = require('axios-mock-adapter');
|
|
5
|
+
const AdmZip = require('adm-zip');
|
|
6
|
+
const pullCommand = require('../pull');
|
|
7
|
+
const openAPI = require('../../../openAPI');
|
|
8
|
+
const { set, empty } = require('../../../db/user');
|
|
9
|
+
|
|
10
|
+
jest.mock('ora', () => () => ({
|
|
11
|
+
start: () => ({
|
|
12
|
+
stop: () => {}
|
|
13
|
+
})
|
|
14
|
+
}));
|
|
15
|
+
jest.mock('../../../db');
|
|
16
|
+
jest.mock('../../../openAPI/index');
|
|
17
|
+
|
|
18
|
+
describe('theme pull', () => {
|
|
19
|
+
let mock;
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
set({
|
|
23
|
+
store_domain: 'developer.myshoplaza.com'
|
|
24
|
+
});
|
|
25
|
+
mock = new MockAdapter(openAPI);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
mock.reset();
|
|
30
|
+
empty();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('pull success', async () => {
|
|
34
|
+
const zip = new AdmZip();
|
|
35
|
+
zip.addLocalFolder(path.join(process.cwd(), '/fixtures'), 'test');
|
|
36
|
+
zip.writeZip(path.join(process.cwd(), 'test.zip'));
|
|
37
|
+
fs.ensureDirSync(path.join(process.cwd(), '/fixtures/theme'));
|
|
38
|
+
|
|
39
|
+
mock
|
|
40
|
+
.onGet(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id/download`)
|
|
41
|
+
.replyOnce(200, fs.createReadStream(path.join(process.cwd(), 'test.zip')));
|
|
42
|
+
|
|
43
|
+
fs.rmSync(path.join(process.cwd(), 'test.zip'));
|
|
44
|
+
|
|
45
|
+
process.chdir(path.join(process.cwd(), '/fixtures/theme'));
|
|
46
|
+
|
|
47
|
+
console.log = jest.fn();
|
|
48
|
+
await pullCommand({
|
|
49
|
+
theme: 'theme_id'
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
expect(console.log.mock.calls[0][0]).toBe(chalk.green(`✓ Theme pulled successfully`));
|
|
53
|
+
expect(fs.existsSync(path.join(process.cwd(), '/config/settings_schema.json'))).toBe(true);
|
|
54
|
+
fs.rmSync(process.cwd(), { recursive: true });
|
|
55
|
+
|
|
56
|
+
process.chdir(path.join(process.cwd(), '../../'));
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('pull failed', async () => {
|
|
60
|
+
mock.onGet(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id/download`).replyOnce(500);
|
|
61
|
+
|
|
62
|
+
console.log = jest.fn();
|
|
63
|
+
await pullCommand({
|
|
64
|
+
theme: 'theme_id'
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
expect(console.log.mock.calls[0][0]).toBe(chalk.red(`✗ Failed to pull theme`));
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const MockAdapter = require('axios-mock-adapter');
|
|
4
|
+
const { pushCommand } = require('../push');
|
|
5
|
+
const openAPI = require('../../../openAPI');
|
|
6
|
+
const { set, empty } = require('../../../db/user');
|
|
7
|
+
|
|
8
|
+
jest.mock('ora', () => () => ({
|
|
9
|
+
start: () => ({
|
|
10
|
+
stop: () => {}
|
|
11
|
+
})
|
|
12
|
+
}));
|
|
13
|
+
jest.mock('../../../db');
|
|
14
|
+
jest.mock('../../../openAPI/index');
|
|
15
|
+
|
|
16
|
+
describe('theme push', () => {
|
|
17
|
+
let mock;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
set({
|
|
21
|
+
store_domain: 'developer.myshoplaza.com'
|
|
22
|
+
});
|
|
23
|
+
mock = new MockAdapter(openAPI);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
mock.reset();
|
|
28
|
+
empty();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('push success', async () => {
|
|
32
|
+
mock.onGet(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id`).replyOnce(200, {
|
|
33
|
+
data: { merchant_theme_id: 'merchant_theme_id' }
|
|
34
|
+
});
|
|
35
|
+
mock.onPost(`https://developer.myshoplaza.com/openapi/2020-07/themes/upload`).replyOnce(200, {
|
|
36
|
+
task: { task: { id: 1 } }
|
|
37
|
+
});
|
|
38
|
+
mock.onGet(`https://developer.myshoplaza.com/openapi/2020-07/themes/task/1`).replyOnce(200, {
|
|
39
|
+
task: { status: 1, info: JSON.stringify({ name: 'TestLifeStyle', theme_id: 'theme_id' }) }
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
process.chdir(path.join(process.cwd(), '/fixtures'));
|
|
43
|
+
|
|
44
|
+
console.log = jest.fn();
|
|
45
|
+
await pushCommand({
|
|
46
|
+
theme: 'theme_id'
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
expect(console.log.mock.calls[0][0]).toBe(chalk.green(`✓ The TestLifeStyle theme pushed successfully`));
|
|
50
|
+
process.chdir(path.join(process.cwd(), '../'));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('push failed', async () => {
|
|
54
|
+
mock.onGet(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id`).replyOnce(500);
|
|
55
|
+
|
|
56
|
+
console.log = jest.fn();
|
|
57
|
+
await pushCommand({
|
|
58
|
+
theme: 'theme_id'
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
expect(console.log.mock.calls[0][0]).toBe(chalk.red(`✗ Failed to push theme`));
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const MockAdapter = require('axios-mock-adapter');
|
|
5
|
+
const serve = require('../serve');
|
|
6
|
+
const openAPI = require('../../../openAPI');
|
|
7
|
+
const { set, empty } = require('../../../db/user');
|
|
8
|
+
|
|
9
|
+
jest.mock('ora', () => () => ({
|
|
10
|
+
start: () => ({
|
|
11
|
+
stop: () => {}
|
|
12
|
+
})
|
|
13
|
+
}));
|
|
14
|
+
jest.mock('../../../db');
|
|
15
|
+
jest.mock('../../../openAPI/index');
|
|
16
|
+
|
|
17
|
+
describe('theme serve', () => {
|
|
18
|
+
let mock;
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
set({
|
|
22
|
+
store_domain: 'developer.myshoplaza.com'
|
|
23
|
+
});
|
|
24
|
+
mock = new MockAdapter(openAPI);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
mock.reset();
|
|
29
|
+
empty();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('start dev server', async () => {
|
|
33
|
+
mock.onGet(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id`).replyOnce(200, {
|
|
34
|
+
data: { merchant_theme_id: 'merchant_theme_id' }
|
|
35
|
+
});
|
|
36
|
+
mock.onGet(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id/doctree`).replyOnce(200, {
|
|
37
|
+
assets: [
|
|
38
|
+
{
|
|
39
|
+
id: '7848a198-9809-4163-91c7-556e6960a0c6',
|
|
40
|
+
location: 'blog.css'
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: '651a9948-d4e5-4fe0-bcd7-e88349f6eeaf',
|
|
44
|
+
location: 'blog.scss'
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
config: [
|
|
48
|
+
{
|
|
49
|
+
id: '9e7a0930-6f6e-42f3-88ee-31e40bc28fdf',
|
|
50
|
+
location: 'settings_data.json'
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: '1799d8b6-82dd-4a42-bad4-32d11a98a924',
|
|
54
|
+
location: 'settings_schema.json'
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
});
|
|
58
|
+
mock.onPost(`https://developer.myshoplaza.com/openapi/2020-07/themes/upload`).replyOnce(200, {
|
|
59
|
+
task: { task: { id: 1 } }
|
|
60
|
+
});
|
|
61
|
+
mock.onGet(`https://developer.myshoplaza.com/openapi/2020-07/themes/task/1`).replyOnce(200, {
|
|
62
|
+
task: { status: 1, info: JSON.stringify({ name: 'TestLifeStyle', theme_id: 'theme_id' }) }
|
|
63
|
+
});
|
|
64
|
+
mock.onPost(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id/doc`).replyOnce(200);
|
|
65
|
+
mock.onPatch(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id/doc`).replyOnce(200);
|
|
66
|
+
mock.onDelete(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id/doc`).replyOnce(200);
|
|
67
|
+
|
|
68
|
+
process.chdir(path.join(process.cwd(), '/fixtures'));
|
|
69
|
+
console.log = jest.fn();
|
|
70
|
+
const watcher = await serve({ theme: 'theme_id' });
|
|
71
|
+
|
|
72
|
+
expect(console.log.mock.calls[0][0]).toBe(
|
|
73
|
+
`Please open this URL in your browser:
|
|
74
|
+
${chalk.green('https://developer.myshoplaza.com/?preview_theme_id=theme_id')}
|
|
75
|
+
|
|
76
|
+
Customize this theme in the Theme Editor, and use 'theme pull' to get the changes:
|
|
77
|
+
${chalk.green(`https://developer.myshoplaza.com/admin/smart_apps/editor?theme_id=theme_id`)}`.replace(
|
|
78
|
+
/^[^\S\n]+/gm,
|
|
79
|
+
''
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
expect(console.log.mock.calls[1][0]).toBe(`\nListening for file changes ...`);
|
|
83
|
+
|
|
84
|
+
fs.writeFileSync(path.join(process.cwd(), 'assets/test.scss'), 'body { color: red; }', 'utf8');
|
|
85
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
86
|
+
expect(console.log.mock.calls[2][0]).toBe(chalk.green(`[update]: ${path.join(process.cwd(), 'assets/test.scss')}`));
|
|
87
|
+
expect(console.log.mock.calls[3][0]).toBe(
|
|
88
|
+
chalk.cyan(`Updated, please refresh your browser, will continue listening for file changes ...`)
|
|
89
|
+
);
|
|
90
|
+
fs.rmSync(path.join(process.cwd(), 'assets/test.scss'));
|
|
91
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
92
|
+
expect(console.log.mock.calls[4][0]).toBe(chalk.green(`[remove]: ${path.join(process.cwd(), 'assets/test.scss')}`));
|
|
93
|
+
|
|
94
|
+
process.chdir(path.join(process.cwd(), '../'));
|
|
95
|
+
watcher.close();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('not a theme directory', async () => {
|
|
99
|
+
mock.onGet(`https://developer.myshoplaza.com/openapi/2020-07/themes/theme_id`).replyOnce(200, {
|
|
100
|
+
data: { merchant_theme_id: 'merchant_theme_id' }
|
|
101
|
+
});
|
|
102
|
+
await serve({ theme: 'theme_id' });
|
|
103
|
+
expect(console.log.mock.calls[0][0]).toBe(
|
|
104
|
+
chalk.red('✗ Provide a config/settings_schema.json to package your theme')
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const ora = require('ora');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const Sentry = require('@sentry/node');
|
|
4
|
+
const inquirer = require('inquirer');
|
|
5
|
+
const { getThemeDetail, getThemes, deleteTheme } = require('../../openAPI/api');
|
|
6
|
+
const { get } = require('../../db/user');
|
|
7
|
+
const log = require('../../log');
|
|
8
|
+
const { formatThemeList } = require('../../utils');
|
|
9
|
+
|
|
10
|
+
const confirmAndDeleteTheme = async (themeName, themeId) => {
|
|
11
|
+
const answers = await inquirer.prompt([
|
|
12
|
+
{
|
|
13
|
+
name: 'confirm',
|
|
14
|
+
type: 'list',
|
|
15
|
+
message: `Are you sure you want to delete ${themeName} on ${get('store_domain')}? ${chalk.yellow(
|
|
16
|
+
'(Choose with ↑ ↓ ⏎)'
|
|
17
|
+
)}`,
|
|
18
|
+
choices: ['Yes', 'No']
|
|
19
|
+
}
|
|
20
|
+
]);
|
|
21
|
+
if (answers.confirm === 'Yes') {
|
|
22
|
+
try {
|
|
23
|
+
await deleteTheme(themeId);
|
|
24
|
+
log.info(chalk.green(`✓ ${themeName} (${themeId}) theme deleted`));
|
|
25
|
+
} catch (error) {
|
|
26
|
+
log.error(chalk.red(`✗ Failed to delete theme`));
|
|
27
|
+
Sentry.captureException(error);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
module.exports = async (options) => {
|
|
33
|
+
try {
|
|
34
|
+
if (options.theme) {
|
|
35
|
+
const { data } = await getThemeDetail(options.theme);
|
|
36
|
+
if (!data) {
|
|
37
|
+
log.error(chalk.red(`✗ Theme ${options.theme} does not exist`));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
return confirmAndDeleteTheme(data.data.name, options.theme);
|
|
41
|
+
} else {
|
|
42
|
+
const storeDomain = get('store_domain');
|
|
43
|
+
const spinner = ora(chalk.cyan(`Fetching theme lists from ${storeDomain}`)).start();
|
|
44
|
+
const { data } = await getThemes();
|
|
45
|
+
spinner.stop();
|
|
46
|
+
inquirer
|
|
47
|
+
.prompt([
|
|
48
|
+
{
|
|
49
|
+
name: 'theme',
|
|
50
|
+
type: 'rawlist',
|
|
51
|
+
message: `Select a theme to delete ${chalk.cyan('(Choose with ↑ ↓ ⏎)')}`,
|
|
52
|
+
choices: formatThemeList(data.data.themes)
|
|
53
|
+
}
|
|
54
|
+
])
|
|
55
|
+
.then((answers) => {
|
|
56
|
+
const themeObj = data.data.themes.find((theme) => theme.id === answers.theme);
|
|
57
|
+
return confirmAndDeleteTheme(themeObj.name, answers.theme);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
log.error(chalk.red(`✗ Failed to delete theme`));
|
|
62
|
+
Sentry.captureException(error);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const process = require('process');
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const inquirer = require('inquirer');
|
|
6
|
+
const Sentry = require('@sentry/node');
|
|
7
|
+
const execa = require('execa');
|
|
8
|
+
const ora = require('ora');
|
|
9
|
+
const log = require('../../log');
|
|
10
|
+
|
|
11
|
+
const createDirAndCloneTheme = async (directory) => {
|
|
12
|
+
const themeDir = path.join(process.cwd(), directory);
|
|
13
|
+
if (fs.existsSync(themeDir)) {
|
|
14
|
+
log.error(chalk.red(`✗ Destination path ${directory} already exists and is not an empty directory.`));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
fs.mkdirSync(themeDir);
|
|
18
|
+
const spinner = ora(chalk.cyan(`Cloning https://github.com/Shoplazza/bing into ${directory}…`)).start();
|
|
19
|
+
await execa('git', ['clone', 'https://github.com/Shoplazza/bing', directory]);
|
|
20
|
+
fs.rmSync(path.join(process.cwd(), `${directory}/.git`), { recursive: true });
|
|
21
|
+
spinner.stop();
|
|
22
|
+
log.info(chalk.green(`✓ Cloned into ${directory}`));
|
|
23
|
+
log.info(`Please run ${chalk.green(`cd ${directory}`)}`);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
module.exports = async (options) => {
|
|
27
|
+
try {
|
|
28
|
+
if (options.name) {
|
|
29
|
+
await createDirAndCloneTheme(options.name);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
inquirer
|
|
33
|
+
.prompt([
|
|
34
|
+
{
|
|
35
|
+
name: 'name',
|
|
36
|
+
type: 'input',
|
|
37
|
+
message: 'Theme directory name'
|
|
38
|
+
}
|
|
39
|
+
])
|
|
40
|
+
.then((answers) => {
|
|
41
|
+
if (answers.name) {
|
|
42
|
+
createDirAndCloneTheme(answers.name);
|
|
43
|
+
} else {
|
|
44
|
+
log.error(chalk.red(`✗ Please input theme directory name.`));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
} catch (error) {
|
|
48
|
+
log.error(chalk.red(`✗ Failed to init theme`));
|
|
49
|
+
Sentry.captureException(error);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const ora = require('ora');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const Sentry = require('@sentry/node');
|
|
4
|
+
const { get } = require('../../db/user');
|
|
5
|
+
const { getDefaultThemeDetail, getThemes } = require('../../openAPI/api');
|
|
6
|
+
const log = require('../../log');
|
|
7
|
+
|
|
8
|
+
module.exports = async () => {
|
|
9
|
+
try {
|
|
10
|
+
const storeDomain = get('store_domain');
|
|
11
|
+
const spinner = ora(chalk.cyan(`Fetching theme lists from ${storeDomain}`)).start();
|
|
12
|
+
const [themesRes, defaultThemeRes] = await Promise.all([getThemes(), getDefaultThemeDetail()]);
|
|
13
|
+
spinner.stop();
|
|
14
|
+
log.info(`${chalk.yellow('⭑')} List of ${chalk.green(storeDomain)} themes:`);
|
|
15
|
+
log.info(
|
|
16
|
+
[defaultThemeRes.data.data, ...themesRes.data.data.themes].reduce(
|
|
17
|
+
(acc, theme) =>
|
|
18
|
+
(acc += `${theme.name} (${chalk.green(theme.id)}) ${
|
|
19
|
+
theme.id === defaultThemeRes.data.data.id ? chalk.green('[live]') : chalk.yellow('[unpublished]')
|
|
20
|
+
}\n`),
|
|
21
|
+
''
|
|
22
|
+
)
|
|
23
|
+
);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
log.error(chalk.red(`✗ Failed to get theme list`));
|
|
26
|
+
Sentry.captureException(error);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const Sentry = require('@sentry/node');
|
|
5
|
+
const log = require('../../log');
|
|
6
|
+
const { zipTheme } = require('../../utils');
|
|
7
|
+
|
|
8
|
+
const checkAndZipThemes = () => {
|
|
9
|
+
const configPath = path.join(process.cwd(), 'config/settings_schema.json');
|
|
10
|
+
if (!fs.pathExistsSync(configPath)) {
|
|
11
|
+
log.error(chalk.red('✗ Provide a config/settings_schema.json to package your theme'));
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const config = fs.readJSONSync(configPath);
|
|
15
|
+
const themeInfo = config.find((section) => section.name === 'theme_info');
|
|
16
|
+
const { theme_name, theme_version = '' } = themeInfo;
|
|
17
|
+
if (!theme_name) {
|
|
18
|
+
log.error(chalk.red('✗ Provide a theme_info.theme_name configuration in config/settings_schema.json'));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const zipName = `${theme_name}${theme_version ? `-${theme_version}` : ''}`;
|
|
22
|
+
const zipPath = path.join(process.cwd(), `${zipName}.zip`);
|
|
23
|
+
fs.removeSync(zipPath);
|
|
24
|
+
zipTheme(process.cwd(), zipName);
|
|
25
|
+
return { theme_name, theme_version, zipName, zipPath };
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
exports.checkAndZipThemes = checkAndZipThemes;
|
|
29
|
+
exports.packageCommand = () => {
|
|
30
|
+
try {
|
|
31
|
+
const { zipName } = checkAndZipThemes();
|
|
32
|
+
log.info(`${chalk.green('✓')} Theme packaged in ${zipName}.zip`);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
log.error(chalk.red(`✗ Failed to package theme`));
|
|
35
|
+
Sentry.captureException(error);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const ora = require('ora');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const inquirer = require('inquirer');
|
|
4
|
+
const Sentry = require('@sentry/node');
|
|
5
|
+
const { getThemeDetail, getThemes, publishTheme } = require('../../openAPI/api');
|
|
6
|
+
const { get } = require('../../db/user');
|
|
7
|
+
const log = require('../../log');
|
|
8
|
+
const { formatThemeList } = require('../../utils');
|
|
9
|
+
|
|
10
|
+
const confirmAndExecPublish = async (themeName, themeId) => {
|
|
11
|
+
const answers = await inquirer.prompt([
|
|
12
|
+
{
|
|
13
|
+
name: 'confirm',
|
|
14
|
+
type: 'list',
|
|
15
|
+
message: `Are you sure you want to make ${themeName} the new live theme on ${get('store_domain')}? ${chalk.yellow(
|
|
16
|
+
'(Choose with ↑ ↓ ⏎)'
|
|
17
|
+
)}`,
|
|
18
|
+
choices: ['Yes', 'No']
|
|
19
|
+
}
|
|
20
|
+
]);
|
|
21
|
+
if (answers.confirm === 'Yes') {
|
|
22
|
+
await publishTheme(themeId);
|
|
23
|
+
log.info(chalk.green(`✓ Your theme is now live at https://${get('store_domain')}`));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
module.exports = async (options) => {
|
|
28
|
+
try {
|
|
29
|
+
if (options.theme) {
|
|
30
|
+
const { data } = await getThemeDetail(options.theme);
|
|
31
|
+
if (!data) {
|
|
32
|
+
log.error(chalk.red(`✗ Theme ${options.theme} does not exist`));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
await confirmAndExecPublish(data.data.name, options.theme);
|
|
36
|
+
} else {
|
|
37
|
+
const storeDomain = get('store_domain');
|
|
38
|
+
const spinner = ora(chalk.cyan(`Fetching theme lists from ${storeDomain}`)).start();
|
|
39
|
+
const { data } = await getThemes();
|
|
40
|
+
spinner.stop();
|
|
41
|
+
const answers = await inquirer.prompt([
|
|
42
|
+
{
|
|
43
|
+
name: 'theme',
|
|
44
|
+
type: 'rawlist',
|
|
45
|
+
message: `Select a theme to publish ${chalk.cyan('(Choose with ↑ ↓ ⏎)')}`,
|
|
46
|
+
choices: formatThemeList(data.data.themes)
|
|
47
|
+
}
|
|
48
|
+
]);
|
|
49
|
+
const themeObj = data.data.themes.find((theme) => theme.id === answers.theme);
|
|
50
|
+
await confirmAndExecPublish(themeObj.name, answers.theme);
|
|
51
|
+
}
|
|
52
|
+
} catch (error) {
|
|
53
|
+
log.error(chalk.red(`✗ Failed to publish theme`));
|
|
54
|
+
Sentry.captureException(error);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const ora = require('ora');
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const inquirer = require('inquirer');
|
|
7
|
+
const Sentry = require('@sentry/node');
|
|
8
|
+
const { get } = require('../../db/user');
|
|
9
|
+
const { pullTheme, getThemes, getDefaultThemeDetail } = require('../../openAPI/api');
|
|
10
|
+
const { unzipTheme, formatThemeList } = require('../../utils');
|
|
11
|
+
const log = require('../../log');
|
|
12
|
+
|
|
13
|
+
const pullThemeFiles = async (theme) => {
|
|
14
|
+
const storeDomain = get('store_domain');
|
|
15
|
+
const spinner = ora(chalk.cyan(`Pulling theme files from ${theme} on ${storeDomain}`)).start();
|
|
16
|
+
const { data } = await pullTheme(theme);
|
|
17
|
+
const zipPath = path.join(path.join(os.homedir(), '/.cache/shoplazza_theme.zip'));
|
|
18
|
+
const write = fs.createWriteStream(zipPath);
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
data
|
|
21
|
+
.pipe(write)
|
|
22
|
+
.on('finish', async () => {
|
|
23
|
+
unzipTheme(zipPath, path.resolve(process.cwd()));
|
|
24
|
+
spinner.stop();
|
|
25
|
+
log.info(chalk.green(`✓ Theme pulled successfully`));
|
|
26
|
+
resolve();
|
|
27
|
+
})
|
|
28
|
+
.on('error', (err) => {
|
|
29
|
+
reject(err);
|
|
30
|
+
log.error(chalk.red('✗ Error pulling theme ', err));
|
|
31
|
+
Sentry.captureException(err);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
module.exports = async (options) => {
|
|
37
|
+
try {
|
|
38
|
+
if (options.theme) {
|
|
39
|
+
await pullThemeFiles(options.theme);
|
|
40
|
+
} else {
|
|
41
|
+
const storeDomain = get('store_domain');
|
|
42
|
+
const spinner = ora(chalk.cyan(`Fetching theme lists from ${storeDomain}`)).start();
|
|
43
|
+
const [themesRes, defaultThemeRes] = await Promise.all([getThemes(), getDefaultThemeDetail()]);
|
|
44
|
+
spinner.stop();
|
|
45
|
+
const answers = await inquirer.prompt([
|
|
46
|
+
{
|
|
47
|
+
name: 'theme',
|
|
48
|
+
type: 'rawlist',
|
|
49
|
+
message: `Select a theme to pull from ${chalk.cyan('(Choose with ↑ ↓ ⏎)')}`,
|
|
50
|
+
choices: formatThemeList(
|
|
51
|
+
[defaultThemeRes.data.data, ...themesRes.data.data.themes],
|
|
52
|
+
defaultThemeRes.data.data.id
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
]);
|
|
56
|
+
await pullThemeFiles(answers.theme);
|
|
57
|
+
}
|
|
58
|
+
} catch (error) {
|
|
59
|
+
log.error(chalk.red(`✗ Failed to pull theme`));
|
|
60
|
+
Sentry.captureException(error);
|
|
61
|
+
}
|
|
62
|
+
};
|