shoplazza-cli 1.0.6 → 1.0.7

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.
Files changed (61) hide show
  1. package/bin/shoplazza +14 -3
  2. package/lib/app/commands/build.js +53 -74
  3. package/lib/app/commands/deploy.js +210 -39
  4. package/lib/app/commands/generate.js +50 -0
  5. package/lib/app/commands/publish.js +52 -0
  6. package/lib/app/extensions/index.js +13 -0
  7. package/lib/app/extensions/theme-app.js +103 -0
  8. package/lib/app/index.js +29 -17
  9. package/lib/app/inquirers/version.js +131 -0
  10. package/lib/checkout/api.js +34 -11
  11. package/lib/commands/login.js +1 -1
  12. package/lib/commands/logout.js +1 -1
  13. package/lib/openAPI/index.js +10 -21
  14. package/lib/utils.js +0 -52
  15. package/package.json +2 -2
  16. package/lib/app/api/api.js +0 -93
  17. package/lib/app/api/request.js +0 -72
  18. package/lib/app/commands/create.js +0 -100
  19. package/lib/app/commands/list.js +0 -31
  20. package/lib/app/commands/serve.js +0 -118
  21. package/lib/app/commands/versions.js +0 -44
  22. package/lib/app/template/basic-app/.ci/k8s.yaml +0 -4
  23. package/lib/app/template/basic-app/README.md +0 -84
  24. package/lib/app/template/basic-app/package.json +0 -15
  25. package/lib/app/template/basic-app/theme-app/assets/index.css +0 -4
  26. package/lib/app/template/basic-app/theme-app/blocks/index.liquid +0 -14
  27. package/lib/app/template/basic-app/theme-app/snippets/index.liquid +0 -8
  28. package/lib/app/template/basic-app/theme-app.config.json +0 -4
  29. package/lib/app/template/embed-app/.ci/k8s.yaml +0 -4
  30. package/lib/app/template/embed-app/README.md +0 -84
  31. package/lib/app/template/embed-app/package.json +0 -15
  32. package/lib/app/template/embed-app/theme-app/assets/index.css +0 -4
  33. package/lib/app/template/embed-app/theme-app/blocks/index.liquid +0 -15
  34. package/lib/app/template/embed-app/theme-app/locales/ar-SA.json +0 -3
  35. package/lib/app/template/embed-app/theme-app/locales/de-DE.json +0 -3
  36. package/lib/app/template/embed-app/theme-app/locales/en-US.json +0 -3
  37. package/lib/app/template/embed-app/theme-app/locales/es-ES.json +0 -3
  38. package/lib/app/template/embed-app/theme-app/locales/fr-FR.json +0 -3
  39. package/lib/app/template/embed-app/theme-app/locales/id-ID.json +0 -3
  40. package/lib/app/template/embed-app/theme-app/locales/it-IT.json +0 -3
  41. package/lib/app/template/embed-app/theme-app/locales/ja-JP.json +0 -3
  42. package/lib/app/template/embed-app/theme-app/locales/ko-KR.json +0 -3
  43. package/lib/app/template/embed-app/theme-app/locales/nl-NL.json +0 -3
  44. package/lib/app/template/embed-app/theme-app/locales/pl-PL.json +0 -3
  45. package/lib/app/template/embed-app/theme-app/locales/pt-PT.json +0 -3
  46. package/lib/app/template/embed-app/theme-app/locales/ru-RU.json +0 -3
  47. package/lib/app/template/embed-app/theme-app/locales/th-TH.json +0 -3
  48. package/lib/app/template/embed-app/theme-app/locales/zh-CN.json +0 -3
  49. package/lib/app/template/embed-app/theme-app/locales/zh-TW.json +0 -3
  50. package/lib/app/template/embed-app/theme-app/snippets/index.liquid +0 -8
  51. package/lib/app/template/embed-app/theme-app.config.json +0 -4
  52. package/lib/app/utils/config.js +0 -29
  53. package/lib/app/utils/index.js +0 -220
  54. package/lib/oss.js +0 -102
  55. /package/lib/{common → app}/constants.js +0 -0
  56. /package/lib/{common → app}/db/partner.js +0 -0
  57. /package/lib/{common → app}/inquirers/choose-app.js +0 -0
  58. /package/lib/{common → app}/inquirers/choose-partner.js +0 -0
  59. /package/lib/{common → app}/log.js +0 -0
  60. /package/lib/{common → app}/login.js +0 -0
  61. /package/lib/{common → app}/logout.js +0 -0
package/lib/app/index.js CHANGED
@@ -1,25 +1,37 @@
1
- function initThemeAppCommand(_program) {
2
- const program = _program.command('app').description('Shoplazza app CLI');
1
+ const { checkAndLogin } = require('./login');
2
+ const { build } = require('./commands/build');
3
+ const { deploy } = require('./commands/deploy');
4
+ const { generate } = require('./commands/generate');
5
+ const { publish } = require('./commands/publish');
6
+ const { choosePartner } = require('./inquirers/choose-partner');
7
+ const { chooseApp } = require('./inquirers/choose-app');
3
8
 
4
- program.command('create').description('Create a new theme app').action(require('./commands/create').create);
5
-
6
- program
7
- .command('serve')
8
- .description('Start a local development server for the theme app')
9
- .action(require('./commands/serve').serve);
9
+ const generateExtension = async () => {
10
+ (await checkAndLogin()) && (await generate());
11
+ };
10
12
 
11
- program.command('build').description('Build the theme app for production').action(require('./commands/build').build);
13
+ const deployExtension = async () => {
14
+ (await checkAndLogin()) && (await deploy());
15
+ };
12
16
 
13
- program
14
- .command('versions')
15
- .description('List all versions of the theme app')
16
- .action(require('./commands/versions').versions);
17
+ const publishExtension = async () => {
18
+ (await checkAndLogin()) && (await publish());
19
+ };
17
20
 
18
- program.command('deploy').description('Deploy the theme app').action(require('./commands/deploy').deploy);
21
+ const retry = async (options) => {
22
+ if (options.partner) {
23
+ (await checkAndLogin()) && (await choosePartner()) && (await chooseApp());
24
+ }
19
25
 
20
- program.command('list').description('List all theme apps').action(require('./commands/list').list);
21
- }
26
+ if (options.app) {
27
+ (await checkAndLogin()) && (await chooseApp());
28
+ }
29
+ };
22
30
 
23
31
  module.exports = {
24
- initThemeAppCommand
32
+ generateExtension,
33
+ deployExtension,
34
+ publishExtension,
35
+ buildExtension: build,
36
+ retry
25
37
  };
@@ -0,0 +1,131 @@
1
+ const axios = require('axios');
2
+ const chalk = require('chalk');
3
+ const inquirer = require('inquirer');
4
+
5
+ const { PARNTER_URL } = require('../constants');
6
+ const { getApp, getValue, PARTNER_KEYS } = require('../db/partner');
7
+ const { line } = require('../log');
8
+
9
+ const requestLastVersion = async () => {
10
+ try {
11
+ const app = getApp();
12
+ if (!app) {
13
+ return;
14
+ }
15
+ const extensionId = getValue(PARTNER_KEYS.EXTENSION_ID);
16
+ const partnerId = getValue(PARTNER_KEYS.PARTNER_ID);
17
+
18
+ const url = `${PARNTER_URL}/api/partner/apps/${app.uid}/theme_extensions/${extensionId}/last_version`;
19
+ const res = await axios.get(url, {
20
+ headers: {
21
+ cookie: `awesomev2=${getValue(PARTNER_KEYS.SESSION_ID)};`,
22
+ 'x-shoplazza-partner-id': partnerId
23
+ },
24
+ validateStatus(status) {
25
+ if (status === 404) {
26
+ return true;
27
+ }
28
+ return status >= 200 && status < 299;
29
+ }
30
+ });
31
+
32
+ if (res.data.errors) {
33
+ return;
34
+ }
35
+
36
+ return res.data.version;
37
+ } catch (e) {
38
+ console.log(chalk.red(e.message || e));
39
+ console.log(chalk.red(JSON.stringify(e.response?.data)));
40
+ }
41
+ };
42
+
43
+ const requestVersionsData = async (params = {}) => {
44
+ try {
45
+ const app = getApp();
46
+ if (!app) {
47
+ return;
48
+ }
49
+ const extensionId = getValue(PARTNER_KEYS.EXTENSION_ID);
50
+ const partnerId = getValue(PARTNER_KEYS.PARTNER_ID);
51
+
52
+ const url = `${PARNTER_URL}/api/partner/apps/${app.uid}/theme_extensions/${extensionId}/versions`;
53
+ const res = await axios.get(url, {
54
+ params,
55
+ headers: {
56
+ cookie: `awesomev2=${getValue(PARTNER_KEYS.SESSION_ID)};`,
57
+ 'x-shoplazza-partner-id': partnerId
58
+ },
59
+ validateStatus(status) {
60
+ if (status === 404) {
61
+ return true;
62
+ }
63
+ return status >= 200 && status < 299;
64
+ }
65
+ });
66
+
67
+ if (res.data.errors) {
68
+ throw new Error(JSON.stringify(res.data.errors));
69
+ }
70
+
71
+ return res.data.data;
72
+ } catch (e) {
73
+ console.log(chalk.red(e.message || e));
74
+ console.log(chalk.red(JSON.stringify(e.response?.data)));
75
+ }
76
+ };
77
+
78
+ const inputVersion = async () => {
79
+ line();
80
+ const lastVersionData = await requestLastVersion({ limit: 1 });
81
+ const hint = lastVersionData ? chalk.gray(`(last version: ${lastVersionData.version})`) : '';
82
+
83
+ const answer = await inquirer.prompt([
84
+ {
85
+ type: 'input',
86
+ name: 'extensionVersion',
87
+ message: `${chalk.blue('Input your extension version')} ${hint}:`,
88
+ prefix: `${chalk.green('⭐️')}`
89
+ }
90
+ ]);
91
+
92
+ return answer['extensionVersion'];
93
+ };
94
+
95
+ const selectVersion = async () => {
96
+ line();
97
+
98
+ const versionDataList = await requestVersionsData();
99
+ if (!versionDataList) {
100
+ console.log(chalk.red('Please deploy a version first!'));
101
+ line();
102
+ }
103
+
104
+ const answer = await inquirer.prompt([
105
+ {
106
+ type: 'list',
107
+ name: 'versionData',
108
+ message: `${chalk.blue('Choose a version to publish:')}`,
109
+ default: versionDataList[0].version,
110
+ prefix: `${chalk.blue('🐱')}`,
111
+ choices: versionDataList.map((v) => {
112
+ return {
113
+ name: `${v.version} ${v.published ? chalk.green('published') : ''}`,
114
+ value: {
115
+ version: v.version,
116
+ appId: v.app_id,
117
+ versionId: v.version_id,
118
+ extensionId: v.extension_id
119
+ }
120
+ };
121
+ })
122
+ }
123
+ ]);
124
+
125
+ return answer['versionData'];
126
+ };
127
+
128
+ module.exports = {
129
+ inputVersion,
130
+ selectVersion
131
+ };
@@ -8,7 +8,6 @@ const { isDebug } = require('./console');
8
8
  const { getProjectConfig } = require('./util');
9
9
  const chalk = require('chalk');
10
10
  const { consoleWarn } = require('./console');
11
- const { useOss } = require('../oss');
12
11
 
13
12
  const FILE_SIGN_URL = '/checkout_extensions/file/sign';
14
13
  const CREATE_URL = '/checkout_extensions/create';
@@ -20,7 +19,6 @@ const UNDEPLOY_URL = '/checkout_extensions/undeploy';
20
19
  const PREVIEW_URL = '/checkout_extensions/preview';
21
20
 
22
21
  let configJson = undefined;
23
- let uploadOss = null;
24
22
 
25
23
  const request = new Axios.create();
26
24
 
@@ -66,6 +64,9 @@ request.interceptors.response.use(
66
64
  if (isDebug()) {
67
65
  console.log(`\n<== error ${error.response.status}: ${error.response.config.url}`);
68
66
  }
67
+ if (!error.response) {
68
+ throw chalk.red('Network error, please check your connection.');
69
+ }
69
70
  if (error.response?.status == 403) {
70
71
  return Promise.reject(new Error('Token permission failure'));
71
72
  }
@@ -73,20 +74,42 @@ request.interceptors.response.use(
73
74
  }
74
75
  );
75
76
 
77
+ async function upload(path, name) {
78
+ const form = new FormData();
79
+ const url = await request(`${FILE_SIGN_URL}?key=${name}`)
80
+ .then((data) => {
81
+ return data.data;
82
+ })
83
+ .then(async (data) => {
84
+ const url = data.write_host;
85
+ form.append('policy', data.policy);
86
+ form.append('OSSAccessKeyId', data.access_id);
87
+ form.append('success_action_status', 200);
88
+ form.append('signature', data.sign);
89
+ form.append('x-oss-forbid-overwrite', 'true');
90
+ form.append('key', name);
91
+ form.append('file', fs.createReadStream(path));
92
+ await request.post(`https:${url}`, form, { headers: form.getHeaders() }).catch((error) => {
93
+ if (error.response?.data.includes('<Code>FileAlreadyExists</Code>')) {
94
+ consoleWarn('The current file already exists, not need to upload.');
95
+ return;
96
+ } else {
97
+ return Promise.reject(error);
98
+ }
99
+ });
100
+ return `${data.read_host}${data.read_host.endsWith('/') ? '' : '/'}${name}`;
101
+ });
102
+ loading('succeed upload').succeed();
103
+ return url;
104
+ }
105
+
76
106
  async function uploadFile(dirPath, file) {
77
- if (!uploadOss) {
78
- uploadOss = useOss(
79
- configJson.token,
80
- new URL(configJson.store).hostname,
81
- `✗ No store found. Please check your "extension.config.js" file.`
82
- ).uploadOss;
83
- }
84
- return uploadOss(`${dirPath}/${file}`);
107
+ return upload(`${dirPath}/${file}`, `chick-extension/${file}`);
85
108
  }
86
109
  async function uploadDir(dirPath, files) {
87
110
  return Promise.all(
88
111
  files.map((file) => {
89
- return uploadOss(`${dirPath}/${file}`);
112
+ return upload(`${dirPath}/${file}`, `chick-extension/${file}`);
90
113
  })
91
114
  );
92
115
  }
@@ -8,7 +8,7 @@ const log = require('../log');
8
8
  const { getShopDetail } = require('../openAPI/api');
9
9
  const getCode = require('../auth/getCode');
10
10
  const { postAccessToken, getUserInfo, postExchangeToken, postStoreToken } = require('../auth');
11
- const { loginIntoPartner } = require('../common/login');
11
+ const { loginIntoPartner } = require('../app/login');
12
12
 
13
13
  let spinner;
14
14
 
@@ -1,7 +1,7 @@
1
1
  const Sentry = require('@sentry/node');
2
2
  const chalk = require('chalk');
3
3
  const { empty: emptyUser } = require('../db/user');
4
- const { logoutPartner } = require('../common/logout');
4
+ const { logoutPartner } = require('../app/logout');
5
5
  const log = require('../log');
6
6
 
7
7
  const logoutStore = () => {
@@ -12,23 +12,17 @@ const openAPI = axios.create({
12
12
  headers: { 'Access-Token': get('exchange_token') }
13
13
  });
14
14
 
15
- openAPI.interceptors.request.use(
16
- (config) => {
17
- if (!get('store_domain')) {
18
- log.error(
19
- chalk.red(
20
- `\n✗ No store found. Please run ${chalk.cyan('shoplazza login --store STORE')} to login to a specific store`
21
- )
22
- );
23
- process.exit(-1);
24
- }
25
- return config;
26
- },
27
- (error) => {
28
- console.error(chalk.red(`[REQUEST ERROR] ${error.message}`));
29
- return Promise.reject(error);
15
+ openAPI.interceptors.request.use((config) => {
16
+ if (!get('store_domain')) {
17
+ log.error(
18
+ chalk.red(
19
+ `\n✗ No store found. Please run ${chalk.cyan('shoplazza login --store STORE')} to login to a specific store`
20
+ )
21
+ );
22
+ process.exit(-1);
30
23
  }
31
- );
24
+ return config;
25
+ });
32
26
 
33
27
  openAPI.interceptors.response.use(
34
28
  function (response) {
@@ -45,11 +39,6 @@ openAPI.interceptors.response.use(
45
39
  return openAPI(error.config);
46
40
  });
47
41
  }
48
- error.response && console.error(
49
- chalk.red(
50
- `[RESPONSE ERROR] ${error.response.status} ${error.response.config.baseURL}${error.response.config.url}`
51
- )
52
- );
53
42
  return Promise.reject(error);
54
43
  }
55
44
  );
package/lib/utils.js CHANGED
@@ -2,8 +2,6 @@ const path = require('path');
2
2
  const fs = require('fs-extra');
3
3
  const AdmZip = require('adm-zip');
4
4
  const chalk = require('chalk');
5
- const chokidar = require('chokidar');
6
- const fsExtra = require('fs-extra');
7
5
 
8
6
  const {
9
7
  SSO_AUTH_URL,
@@ -113,53 +111,3 @@ const SSO_AUTH_URL_MAP = {
113
111
  exports.getSSOAuthUrl = (store) => {
114
112
  return SSO_AUTH_URL_MAP[getEnv(store)];
115
113
  };
116
-
117
- /**
118
- * 监听文件夹变化
119
- * @param {string} workspace - 需要监听的文件夹路径
120
- * @param {Object} options - 配置项
121
- * @param {Function} [options.onAdd] - 文件添加时的回调函数,接收文件路径作为参数
122
- * @param {Function} [options.onChange] - 文件更改时的回调函数,接收文件路径作为参数
123
- * @param {Function} [options.onDelete] - 文件删除时的回调函数,接收文件路径作为参数
124
- * @param {any} [options.xxx] - 其他chokidar.watch配置项
125
- * @returns {Function} - 取消监听的函数
126
- */
127
- exports.initWatcher = (workspace, options = {}) => {
128
- if (!fsExtra.pathExistsSync(workspace)) {
129
- console.error(chalk.red(`[ERROR] "${workspace}" does not exist.`));
130
- return;
131
- }
132
- const defaultOptions = {
133
- persistent: true,
134
- ignoreInitial: true
135
- };
136
- const { onAdd = () => {}, onChange = () => {}, onDelete = () => {}, ...restOptions } = options;
137
- const watcherOptions = { ...defaultOptions, ...restOptions };
138
- const watcher = chokidar.watch(workspace, watcherOptions);
139
-
140
- watcher.on('add', (filePath) => {
141
- console.log(chalk.cyan(`[ADD] ${filePath}`));
142
- onAdd(filePath);
143
- });
144
-
145
- watcher.on('change', (filePath) => {
146
- console.log(chalk.yellow(`[CHANGE] ${filePath}`));
147
- onChange(filePath);
148
- });
149
-
150
- watcher.on('unlink', (filePath) => {
151
- console.log(chalk.red(`[DELETE] ${filePath}`));
152
- onDelete(filePath);
153
- });
154
-
155
- watcher.on('error', (error) => {
156
- console.error(chalk.red(`[ERROR] ${error}`));
157
- });
158
-
159
- const stopWatcher = () => {
160
- console.log(chalk.green('[INFO] Stopping watcher...'));
161
- watcher.close();
162
- };
163
-
164
- return stopWatcher;
165
- };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shoplazza-cli",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "",
5
5
  "main": "bin/shoplazza",
6
6
  "engines": {
@@ -26,6 +26,7 @@
26
26
  "@sentry/tracing": "^6.19.7",
27
27
  "adm-zip": "^0.5.9",
28
28
  "ali-oss": "^6.17.1",
29
+ "archiver": "^5.3.1",
29
30
  "axios": "^1.6.8",
30
31
  "better-sqlite3": "^11.5.0",
31
32
  "chalk": "^4.1.2",
@@ -63,7 +64,6 @@
63
64
  "semver": "~7.3.5",
64
65
  "serve-static": "^1.15.0",
65
66
  "spark-md5": "^3.0.2",
66
- "table": "^6.9.0",
67
67
  "uglify-js": "^3.17.4",
68
68
  "update-notifier": "^5.1.0",
69
69
  "vite": "~4.3.1",
@@ -1,93 +0,0 @@
1
- const { get, post, put, del, patch } = require('./request');
2
-
3
- /**
4
- * 获取主题列表
5
- */
6
- async function getThemeList() {
7
- return get('/themes');
8
- }
9
-
10
- /**
11
- * 获取店铺私有主题插件列表
12
- * @returns
13
- */
14
- async function getThemeAppList() {
15
- return [
16
- {
17
- name: '主题插件1',
18
- version: '1.0.0',
19
- description: '主题插件1的描述'
20
- },
21
- {
22
- name: '主题插件2',
23
- version: '2.0.0',
24
- description: '主题插件2的描述'
25
- },
26
- {
27
- name: '主题插件3',
28
- version: '3.0.0',
29
- description: '主题插件3的描述'
30
- }
31
- ];
32
- // return get('/theme-extensions');
33
- }
34
-
35
- /**
36
- * 创建主题插件
37
- */
38
- async function toCreateThemeApp(data) {
39
- return put('/theme-extensions', data);
40
- }
41
-
42
- /**
43
- * 上传主题插件
44
- */
45
- async function toUploadThemeApp(data) {
46
- return patch(`theme-extensions/${data.appId}/dev-doctree`, data);
47
- }
48
-
49
- /**
50
- * 获取任务状态
51
- */
52
- async function getTaskStatus(data) {
53
- return get(`/theme-extensions/version-tasks/${data.taskId}`);
54
- }
55
-
56
- /**
57
- * 获取主题插件版本列表
58
- */
59
- async function getThemeAppVersionList(data) {
60
- return [
61
- { version: '1.0.0', date: '2023-01-01', description: 'Initial release' },
62
- { version: '1.1.0', date: '2023-02-01', description: 'Added new features and bug fixes' },
63
- { version: '1.2.0', date: '2023-03-01', description: 'Fixed bugs and improved performance' },
64
- { version: '1.3.0', date: '2023-04-01', description: 'Optimized performance and added new features' },
65
- { version: '1.4.0', date: '2023-05-01', description: 'Fixed bugs and improved user experience' }
66
- ];
67
- // return get(`/theme-extensions/:${data.appId}/versions`);
68
- }
69
-
70
- /**
71
- * 创建主题插件版本
72
- */
73
- async function toCreateThemeAppVersion(data) {
74
- return post(`/theme-extensions/version-tasks`, data);
75
- }
76
-
77
- /**
78
- * 部署主题插件
79
- */
80
- async function toDeployThemeApp(data) {
81
- return post(`theme-extensions/publications`, data);
82
- }
83
-
84
- module.exports = {
85
- getThemeList,
86
- getThemeAppList,
87
- toCreateThemeApp,
88
- toUploadThemeApp,
89
- getThemeAppVersionList,
90
- toCreateThemeAppVersion,
91
- toDeployThemeApp,
92
- getTaskStatus
93
- };
@@ -1,72 +0,0 @@
1
- const instance = require('../../openAPI/index');
2
-
3
- /**
4
- * 基础的 API 请求方法
5
- * @param {string} method 请求方法 (GET, POST, PUT, DELETE)
6
- * @param {string} url 请求的路径
7
- * @param {Object} data 请求的数据(适用于 POST、PUT)
8
- * @param {Object} params 请求的 URL 参数(适用于 GET)
9
- */
10
- async function request({ method, url, data, params }) {
11
- const response = await instance({
12
- method,
13
- url,
14
- data,
15
- params
16
- });
17
- return response; // 返回请求结果
18
- }
19
-
20
- /**
21
- * GET 请求封装
22
- * @param {string} url 请求的路径
23
- * @param {Object} params 请求的 URL 参数
24
- */
25
- async function get(url, params) {
26
- return request({ method: 'get', url, params });
27
- }
28
-
29
- /**
30
- * POST 请求封装
31
- * @param {string} url 请求的路径
32
- * @param {Object} data 请求的数据
33
- */
34
- async function post(url, data) {
35
- return request({ method: 'post', url, data });
36
- }
37
-
38
- /**
39
- * PUT 请求封装
40
- * @param {string} url 请求的路径
41
- * @param {Object} data 请求的数据
42
- */
43
- async function put(url, data) {
44
- return request({ method: 'put', url, data });
45
- }
46
-
47
- /**
48
- * DELETE 请求封装
49
- * @param {string} url 请求的路径
50
- * @param {Object} params 请求的 URL 参数
51
- */
52
- async function del(url, params) {
53
- return request({ method: 'delete', url, params });
54
- }
55
-
56
- /**
57
- * PATCH 请求封装
58
- * @param {string} url 请求的路径
59
- * @param {Object} data 请求的数据
60
- */
61
- async function patch(url, data) {
62
- return request({ method: 'patch', url, data });
63
- }
64
-
65
-
66
- module.exports = {
67
- get,
68
- post,
69
- put,
70
- del,
71
- patch
72
- };
@@ -1,100 +0,0 @@
1
- const inquirer = require('inquirer');
2
- const path = require('path');
3
- const fsExtra = require('fs-extra');
4
- const chalk = require('chalk');
5
- const { WORKSPACE_PATH, THEME_APP_TYPE } = require('../utils/config');
6
- const { replacePlaceholders, renameFile } = require('../utils');
7
-
8
- /**
9
- * 交互式命令行
10
- */
11
- async function usePrompt() {
12
- return await inquirer.prompt([
13
- {
14
- type: 'list',
15
- name: 'themeAppType',
16
- message: 'Select theme app type:',
17
- choices: [THEME_APP_TYPE.BASIC_APP.description, THEME_APP_TYPE.EMBEDS_APP.description],
18
- prefix: '*'
19
- },
20
- {
21
- type: 'input',
22
- name: 'projectName',
23
- message: 'Please enter the theme app project name:',
24
- prefix: '*',
25
- validate: (projectName) => {
26
- if (!projectName.trim()) {
27
- return 'Project name cannot be empty';
28
- }
29
- return true;
30
- }
31
- }
32
- ]);
33
- }
34
-
35
- /**
36
- * 初始化项目
37
- */
38
- async function initProj(projectPath, projectName) {
39
- // 替换占位符 key文件相对路径 value替换的内容
40
- const replacementConfig = {
41
- 'package.json': { projectName },
42
- 'theme-app/blocks/index.liquid': { projectName },
43
- 'theme-app.config.json': { projectName }
44
- };
45
- for (const [filePath, replacements] of Object.entries(replacementConfig)) {
46
- const fullPath = path.resolve(projectPath, filePath);
47
- await replacePlaceholders(fullPath, replacements);
48
- }
49
-
50
- // 重命名文件
51
- const filesToRename = ['assets/index.css', 'blocks/index.liquid', 'snippets/index.liquid'];
52
- for (const file of filesToRename) {
53
- const filePath = path.resolve(projectPath, 'theme-app', file);
54
- await renameFile(filePath, `${projectName}${file.includes('snippets') ? '_snippet' : ''}`);
55
- }
56
- }
57
-
58
- /**
59
- * 控制台提示信息
60
- */
61
- function consoleTips(projectName) {
62
- console.log(chalk.green(`Theme app project "${projectName}" has been successfully created.`));
63
- console.log(chalk.bold(`To get started:\n`));
64
- console.log(` ${chalk.cyan(`cd ${projectName}`)}`);
65
- console.log(` ${chalk.cyan(`npm start`)}\n`);
66
- console.log(chalk.greenBright(`Happy coding! 🎉🎉🎉`));
67
- }
68
-
69
- /**
70
- * 创建项目
71
- */
72
- async function _create(themeAppDescription, projectName) {
73
- const projectPath = path.resolve(WORKSPACE_PATH, projectName);
74
- const projectExists = await fsExtra.pathExists(projectPath);
75
-
76
- if (projectExists) {
77
- throw new Error(`Project directory "${projectName}" already exists.`);
78
- }
79
- await fsExtra.ensureDir(projectPath);
80
- const templatePath =
81
- THEME_APP_TYPE.BASIC_APP.description === themeAppDescription
82
- ? THEME_APP_TYPE.BASIC_APP.templatePath
83
- : THEME_APP_TYPE.EMBEDS_APP.templatePath;
84
- await fsExtra.copy(templatePath, projectPath);
85
- await initProj(projectPath, projectName);
86
- consoleTips(projectName);
87
- }
88
-
89
- async function create() {
90
- try {
91
- const { themeAppType, projectName } = await usePrompt();
92
- await _create(themeAppType, projectName);
93
- } catch (error) {
94
- console.error(chalk.red(`[ERROR IN CREATE] ${error.message}`));
95
- }
96
- }
97
-
98
- module.exports = {
99
- create
100
- };