@shoper/cli 0.1.0-8 → 0.2.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.
Files changed (170) hide show
  1. package/build/cli/auth/cli_auth_errors_factory.js +1 -1
  2. package/build/cli/auth/tokens/cli_auth_tokens_errors_factory.js +1 -1
  3. package/build/cli/auth/tokens/cli_auth_tokens_initalizer.js +1 -1
  4. package/build/cli/class/errors/file_system_errors_factory.js +1 -1
  5. package/build/cli/class/errors/http/http_errors_constants.js +1 -0
  6. package/build/cli/class/errors/{http_errors_factory.js → http/http_errors_factory.js} +3 -2
  7. package/build/cli/commands/auth/cli_auth_add_token_command.js +22 -19
  8. package/build/cli/commands/auth/cli_auth_commands_constants.js +3 -0
  9. package/build/cli/commands/auth/cli_auth_commands_utils.js +46 -0
  10. package/build/cli/commands/auth/cli_auth_list_tokens_command.js +19 -6
  11. package/build/cli/commands/auth/cli_auth_remove_token_command.js +36 -10
  12. package/build/cli/commands/auth/cli_auth_switch_token_command.js +19 -9
  13. package/build/cli/commands/auth/ui/invalid_token_index_error.js +11 -0
  14. package/build/cli/commands/auth/ui/missing_credentials_error.js +9 -0
  15. package/build/cli/commands/auth/ui/missing_token_index_error.js +19 -0
  16. package/build/cli/commands/cli_ui_dump_command.js +11 -0
  17. package/build/cli/commands/cli_update_command.js +13 -4
  18. package/build/cli/commands/commands_constants.js +2 -1
  19. package/build/cli/core/cli_setup.js +5 -1
  20. package/build/cli/features/controls/controls_constants.js +12 -0
  21. package/build/cli/features/controls/controls_dto_mappers.js +55 -0
  22. package/build/cli/features/controls/ui/controls_mappers.js +62 -0
  23. package/build/cli/features/controls/ui/form.js +4 -0
  24. package/build/cli/features/controls/ui/form_constants.js +7 -0
  25. package/build/cli/features/controls/validators/greater_eq_than_validator.js +5 -0
  26. package/build/cli/features/controls/validators/length_validator.js +6 -0
  27. package/build/cli/features/controls/validators/required_validator.js +5 -0
  28. package/build/cli/features/controls/validators/validator_constants.js +13 -0
  29. package/build/cli/features/execution_context/execution_context_service.js +5 -5
  30. package/build/cli/features/http_requester/http_requester_initializer.js +1 -1
  31. package/build/cli/hooks/authorization/ensure_authorization_hook.js +2 -2
  32. package/build/cli/hooks/authorization/ensure_authorization_hook_constants.js +8 -8
  33. package/build/index.js +37 -19
  34. package/build/theme/class/checksums/theme_checksums.js +174 -0
  35. package/build/theme/{features/theme/utils → class}/checksums/theme_checksums_error_factory.js +1 -1
  36. package/build/theme/class/checksums/theme_checksums_utils.js +17 -0
  37. package/build/theme/class/fetch_resources/fetch_resources.js +5 -3
  38. package/build/theme/class/fetch_resources/fetch_resources_errors_factory.js +1 -1
  39. package/build/theme/class/fetch_resources/fetch_resources_utils.js +4 -1
  40. package/build/theme/commands/delete/theme_delete_command.js +111 -0
  41. package/build/theme/commands/delete/ui/theme_deleted_successfully.js +15 -0
  42. package/build/theme/commands/delete/ui/theme_deletion_warning.js +10 -0
  43. package/build/theme/commands/info/theme_info_command.js +94 -0
  44. package/build/theme/commands/info/theme_info_command_utils.js +39 -0
  45. package/build/theme/commands/init/theme_init_command.js +97 -0
  46. package/build/theme/commands/init/ui/theme_created_success.js +15 -0
  47. package/build/theme/commands/list/theme_list_command.js +25 -0
  48. package/build/theme/commands/list/theme_list_command_utils.js +27 -0
  49. package/build/theme/commands/publish/theme_publish_command.js +92 -0
  50. package/build/theme/commands/pull/theme_pull_command.js +194 -0
  51. package/build/theme/commands/pull/ui/theme_pull_id_mismatch_error.js +7 -0
  52. package/build/theme/commands/pull/ui/theme_pull_unpublished_changes_warning.js +10 -0
  53. package/build/theme/commands/pull/ui/theme_pulled_success.js +5 -0
  54. package/build/theme/commands/push/theme_push_command.js +134 -0
  55. package/build/theme/commands/push/ui/theme_push_skip_into.js +7 -0
  56. package/build/theme/commands/push/ui/theme_pushed_success.js +5 -0
  57. package/build/theme/commands/push/ui/theme_unpermitted_actions_error.js +12 -0
  58. package/build/theme/commands/theme_commands_constants.js +4 -1
  59. package/build/theme/commands/theme_show_changes_command.js +1 -0
  60. package/build/theme/commands/theme_verify_command.js +8 -7
  61. package/build/theme/commands/ui/invalid_theme_id.js +11 -0
  62. package/build/theme/commands/ui/missing_theme_files.js +15 -0
  63. package/build/theme/commands/ui/missing_theme_id_error.js +13 -0
  64. package/build/theme/commands/ui/ouside_of_theme_directory_context_error.js +7 -0
  65. package/build/theme/commands/ui/theme_directory_context_error.js +7 -0
  66. package/build/theme/commands/ui/theme_work_url_mismatch.js +17 -0
  67. package/build/theme/commands/ui/unpermitted_command_error.js +18 -0
  68. package/build/theme/features/theme/actions/api/theme_actions_api.js +3 -0
  69. package/build/theme/features/theme/actions/service/theme_actions_service.js +15 -3
  70. package/build/theme/features/theme/actions/service/theme_actions_service_constants.js +1 -0
  71. package/build/theme/features/theme/actions/theme_actions_constants.js +3 -1
  72. package/build/theme/features/theme/actions/theme_actions_initializer.js +1 -1
  73. package/build/theme/features/theme/actions/theme_actions_utils.js +20 -7
  74. package/build/theme/features/theme/delete/api/theme_delete_api.js +13 -0
  75. package/build/theme/features/theme/delete/http/theme_delete_http_api.js +17 -0
  76. package/build/theme/features/theme/delete/service/theme_delete_service.js +31 -0
  77. package/build/theme/features/theme/delete/theme_delete_constants.js +2 -0
  78. package/build/theme/features/theme/delete/theme_delete_initalizer.js +20 -0
  79. package/build/theme/features/theme/fetch/service/theme_fetch_service.js +30 -10
  80. package/build/theme/features/theme/info/theme_info_utils.js +9 -0
  81. package/build/theme/features/theme/init/service/theme_init_service.js +9 -4
  82. package/build/theme/features/theme/merge/api/theme_merge_api.js +0 -12
  83. package/build/theme/features/theme/merge/service/theme_merge_service.js +20 -28
  84. package/build/theme/features/theme/push/service/theme_push_service.js +102 -73
  85. package/build/theme/features/theme/push/theme_push_constants.js +2 -0
  86. package/build/theme/features/theme/push/theme_push_errors_factory.js +7 -4
  87. package/build/theme/features/theme/push/theme_push_initializer.js +0 -3
  88. package/build/theme/features/theme/push/theme_push_utils.js +25 -0
  89. package/build/theme/features/theme/skinstore/api/theme_skinstore_api.js +19 -0
  90. package/build/theme/features/theme/skinstore/http/theme_skinstore_http_api.js +17 -0
  91. package/build/theme/features/theme/skinstore/service/theme_skinstore_service.js +32 -0
  92. package/build/theme/features/theme/skinstore/theme_publish_constants.js +4 -0
  93. package/build/theme/features/theme/skinstore/theme_skinstore_initialzier.js +20 -0
  94. package/build/theme/features/theme/utils/files_structure/theme_files_structure_utils.js +40 -0
  95. package/build/theme/features/theme/utils/hidden_directory/hidden_directory_utils.js +32 -0
  96. package/build/theme/features/theme/utils/meta_data/theme_meta_data_constants.js +1 -0
  97. package/build/theme/features/theme/utils/meta_data/theme_meta_data_error_factory.js +15 -0
  98. package/build/theme/features/theme/utils/meta_data/theme_meta_data_utils.js +39 -0
  99. package/build/theme/features/theme/utils/{directories → resources}/theme_resources_with_id_directory_utils.js +3 -14
  100. package/build/theme/features/theme/utils/theme_images_utils.js +5 -6
  101. package/build/theme/features/themes/list/api/themes_list_api.js +3 -0
  102. package/build/theme/features/themes/list/services/themes_list_service.js +13 -7
  103. package/build/theme/hooks/{ensure_theme_meta_data_untouched.js → ensure_theme_meta_data_untouched_hook.js} +2 -2
  104. package/build/theme/hooks/theme_checksums/ensure_theme_current_checksums_up_to_date_constants.js +1 -1
  105. package/build/theme/hooks/theme_checksums/{ensure_theme_current_checksums_up_to_date.js → ensure_theme_current_checksums_up_to_date_hook.js} +2 -5
  106. package/build/theme/hooks/themes_actions/ensure_themes_actions_hook.js +1 -0
  107. package/build/theme/hooks/themes_actions/ensure_themes_actions_hook_constants.js +1 -0
  108. package/build/theme/index.js +11 -5
  109. package/build/theme/utils/directory_validator/directory_validator_constants.js +2 -6
  110. package/build/theme/utils/directory_validator/directory_validator_utils.js +18 -38
  111. package/build/ui/box.js +2 -0
  112. package/build/ui/color_constants.js +30 -0
  113. package/build/ui/command.js +6 -0
  114. package/build/ui/file_name.js +6 -0
  115. package/build/ui/flag.js +6 -0
  116. package/build/ui/icons/error_icon.js +7 -0
  117. package/build/ui/icons/info_icon.js +7 -0
  118. package/build/ui/icons/success_icon.js +7 -0
  119. package/build/ui/icons/warning_icon.js +7 -0
  120. package/build/ui/link.js +8 -0
  121. package/build/ui/list/list.js +10 -0
  122. package/build/ui/list/list_constants.js +4 -0
  123. package/build/ui/list/list_item.js +11 -0
  124. package/build/ui/message_box/error.js +4 -0
  125. package/build/ui/message_box/info.js +4 -0
  126. package/build/ui/message_box/message_box.js +11 -0
  127. package/build/ui/message_box/message_box_constants.js +24 -0
  128. package/build/ui/message_box/success.js +4 -0
  129. package/build/ui/message_box/warning.js +4 -0
  130. package/build/ui/prompts/prompt_confirmation.js +11 -0
  131. package/build/ui/prompts/prompt_input.js +10 -0
  132. package/build/ui/table/t_cell.js +7 -0
  133. package/build/ui/table/t_header.js +9 -0
  134. package/build/ui/table/t_row.js +5 -0
  135. package/build/ui/table/table.js +18 -0
  136. package/build/ui/text.js +2 -0
  137. package/build/ui/tip.js +9 -0
  138. package/build/ui/ui_dump/ui_component_box.js +9 -0
  139. package/build/ui/ui_dump/ui_dump.js +53 -0
  140. package/build/ui/ui_dump/ui_dump_constants.js +21 -0
  141. package/build/ui/ui_utils.js +11 -0
  142. package/build/ui/validation_errors/validation_error_content.js +19 -0
  143. package/build/ui/validation_errors/validation_errors.js +21 -0
  144. package/build/ui/validation_errors/validation_errors_utils.js +17 -0
  145. package/build/utils/checksums/checksums_utils.js +9 -26
  146. package/build/utils/download_file/download_file_errors_factory.js +1 -1
  147. package/build/utils/download_file/download_file_utils.js +4 -2
  148. package/build/utils/fs/errors/stream_read_error.js +1 -1
  149. package/build/utils/fs/errors/stream_write_error.js +1 -1
  150. package/build/utils/fs/fs_utils.js +17 -3
  151. package/build/utils/path_utils.js +20 -1
  152. package/build/utils/platform_utils.js +3 -0
  153. package/build/utils/zip/create_zip_utils.js +1 -1
  154. package/build/utils/zip/errors/create_zip_error.js +1 -1
  155. package/build/utils/zip/errors/open_zip_error.js +1 -1
  156. package/oclif.config.js +2 -2
  157. package/package.json +15 -8
  158. package/build/theme/commands/theme_init_command.js +0 -53
  159. package/build/theme/commands/theme_list_command.js +0 -16
  160. package/build/theme/commands/theme_pull_command.js +0 -124
  161. package/build/theme/commands/theme_push_command.js +0 -65
  162. package/build/theme/features/theme/directory/theme_directory_utils.js +0 -76
  163. package/build/theme/features/theme/publish/theme_publish_constants.js +0 -2
  164. package/build/theme/features/theme/utils/checksums/theme_checksums_utils.js +0 -94
  165. /package/build/cli/{features → class}/caches/cache_factory.js +0 -0
  166. /package/build/cli/{features → class}/caches/json_cache/json_cache.js +0 -0
  167. /package/build/cli/{features → class}/caches/memory_cache.js +0 -0
  168. /package/build/cli/class/errors/{app_error → app}/app_error.js +0 -0
  169. /package/build/cli/class/errors/{app_error → app}/app_error_constants.js +0 -0
  170. /package/build/theme/features/theme/{publish → skinstore}/theme_publish_utils.js +0 -0
@@ -0,0 +1,21 @@
1
+ export const TABLE_COMPONENT_DATA = {
2
+ headers: [
3
+ {
4
+ content: 'Component',
5
+ width: 20
6
+ },
7
+ {
8
+ content: 'Description',
9
+ width: 20
10
+ },
11
+ {
12
+ content: 'Props',
13
+ width: 20
14
+ }
15
+ ],
16
+ rows: [
17
+ ['Box', 'A flexible', 'borderStyle'],
18
+ ['Box', 'A flexible', 'borderStyle'],
19
+ ['Box', 'A flexible', 'borderStyle']
20
+ ]
21
+ };
@@ -0,0 +1,11 @@
1
+ import { render as inkRender } from 'ink';
2
+ export const render = async (element, options) => {
3
+ const { waitUntilExit } = inkRender(element, options);
4
+ await waitUntilExit();
5
+ // We need to wait for other pending tasks -- unmounting of the ink component -- to complete
6
+ return new Promise((resolve) => setImmediate(resolve));
7
+ };
8
+ export const renderOnce = (element, options) => {
9
+ const instance = inkRender(element, options);
10
+ instance.unmount();
11
+ };
@@ -0,0 +1,19 @@
1
+ import { Text } from '../text.js';
2
+ import { List } from '../list/list.js';
3
+ import { ValidationErrorsUtils } from './validation_errors_utils.js';
4
+ import React from 'react';
5
+ export const ValidationErrorContent = ({ errors }) => {
6
+ if (typeof errors === 'string') {
7
+ return React.createElement(Text, null, errors);
8
+ }
9
+ if (Array.isArray(errors)) {
10
+ return (React.createElement(List, { items: errors.map((error) => ({
11
+ content: error
12
+ })) }));
13
+ }
14
+ return (React.createElement(List, { items: Object.entries(errors).map(([title, errorMessages]) => {
15
+ return {
16
+ content: `${title} - ${ValidationErrorsUtils.getErrorContent(errorMessages)}`
17
+ };
18
+ }) }));
19
+ };
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { Error } from '../message_box/error.js';
3
+ import { Text } from '../text.js';
4
+ import { List } from '../list/list.js';
5
+ import { ValidationErrorContent } from './validation_error_content.js';
6
+ export const ValidationErrors = ({ errors }) => {
7
+ if (typeof errors === 'string') {
8
+ return (React.createElement(Error, null,
9
+ React.createElement(Text, null, errors)));
10
+ }
11
+ if (Array.isArray(errors)) {
12
+ return (React.createElement(Error, null,
13
+ React.createElement(List, { items: errors.map((error) => ({
14
+ content: error
15
+ })) })));
16
+ }
17
+ return (React.createElement(React.Fragment, null, Object.entries(errors).map(([title, errorMessages], index) => {
18
+ return (React.createElement(Error, { key: index, header: title },
19
+ React.createElement(ValidationErrorContent, { errors: errorMessages })));
20
+ })));
21
+ };
@@ -0,0 +1,17 @@
1
+ export class ValidationErrorsUtils {
2
+ static getErrorContent(errors) {
3
+ if (typeof errors === 'string') {
4
+ return errors;
5
+ }
6
+ if (Array.isArray(errors)) {
7
+ return errors.join(', ');
8
+ }
9
+ if (errors?.errors && Array.isArray(errors?.errors)) {
10
+ return errors.errors.join(', ');
11
+ }
12
+ if (typeof errors === 'object') {
13
+ return Object.values(errors).join(', ');
14
+ }
15
+ throw new Error('Not supported validation errors', errors);
16
+ }
17
+ }
@@ -1,7 +1,6 @@
1
1
  import crypto, { createHash } from 'node:crypto';
2
2
  import { createReadStream } from 'node:fs';
3
- import { dirname, join, platformSeparator, relative } from '../path_utils.js';
4
- import klaw from 'klaw';
3
+ import { dirname, join, platformSeparator, relative, toUnixPath } from '../path_utils.js';
5
4
  import { CHECKSUM_KEY } from './checksums_utils_constants.js';
6
5
  export const computeChecksum = (data, algorithm = 'md5') => {
7
6
  const hash = crypto.createHash(algorithm);
@@ -23,28 +22,13 @@ export const computeFileChecksum = async (filePath, algorithm = 'md5') => {
23
22
  });
24
23
  });
25
24
  };
26
- export const computeChecksumsFromSource = (source) => {
27
- return new Promise((resolve, reject) => {
28
- const files = [];
29
- klaw(source)
30
- .on('data', (item) => {
31
- if (!item.stats.isDirectory())
32
- files.push(item.path);
33
- })
34
- .on('end', () => {
35
- computeChecksumsFromFilesStructure(files, source).then(({ filesChecksumsInDirectories, filesChecksums }) => {
36
- resolve({ ...filesChecksums, ...computeDirectoriesChecksums(filesChecksumsInDirectories) });
37
- });
38
- });
39
- });
40
- };
41
25
  export const computeChecksumsFromFilesStructure = async (files, rootDir) => {
42
26
  const filesChecksums = {};
43
27
  const filesChecksumsInDirectories = {};
44
28
  for (const filePath of files) {
45
29
  const checksum = await computeFileChecksum(filePath);
46
30
  const relativePath = relative(rootDir, filePath);
47
- filesChecksums[relativePath] = checksum;
31
+ filesChecksums[toUnixPath(relativePath)] = checksum;
48
32
  const zipDir = join(dirname(relativePath), platformSeparator);
49
33
  const zipParts = zipDir.split(platformSeparator);
50
34
  zipParts.pop();
@@ -52,9 +36,10 @@ export const computeChecksumsFromFilesStructure = async (files, rootDir) => {
52
36
  zipParts.forEach((part) => {
53
37
  currentParts.push(part);
54
38
  const partsDir = join(...currentParts, platformSeparator);
55
- if (!filesChecksumsInDirectories[partsDir])
56
- filesChecksumsInDirectories[partsDir] = [];
57
- filesChecksumsInDirectories[partsDir].push(checksum);
39
+ const unixParts = toUnixPath(partsDir);
40
+ if (!filesChecksumsInDirectories[unixParts])
41
+ filesChecksumsInDirectories[unixParts] = [];
42
+ filesChecksumsInDirectories[unixParts].push(checksum);
58
43
  });
59
44
  }
60
45
  return {
@@ -65,7 +50,7 @@ export const computeChecksumsFromFilesStructure = async (files, rootDir) => {
65
50
  export const computeDirectoriesChecksums = (filesChecksumsInDirectories) => {
66
51
  const checksums = {};
67
52
  Object.entries(filesChecksumsInDirectories).forEach(([directoryPath, filesChecksums]) => {
68
- checksums[directoryPath] = computeChecksum(filesChecksums.sort().join(''));
53
+ checksums[toUnixPath(directoryPath)] = computeChecksum(filesChecksums.sort().join(''));
69
54
  });
70
55
  return checksums;
71
56
  };
@@ -76,15 +61,13 @@ export const mapChecksumToTree = (checksums) => {
76
61
  let currentLevel = tree;
77
62
  parts.filter(Boolean).forEach((part, index) => {
78
63
  if (index === parts.length - 1) {
79
- // TODO cross platform
80
- const finalPart = path.endsWith('/') ? `${part}/` : part;
64
+ const finalPart = path.endsWith(platformSeparator) ? join(part, platformSeparator) : part;
81
65
  if (!currentLevel[finalPart])
82
66
  currentLevel[finalPart] = {};
83
67
  currentLevel[finalPart][CHECKSUM_KEY] = checksum;
84
68
  }
85
69
  if (index !== parts.length - 1) {
86
- // TODO cross platform
87
- const finalPart = `${part}/`;
70
+ const finalPart = join(part, platformSeparator);
88
71
  if (!currentLevel[finalPart])
89
72
  currentLevel[finalPart] = {};
90
73
  currentLevel = currentLevel[finalPart];
@@ -1,4 +1,4 @@
1
- import { AppError } from '../../cli/class/errors/app_error/app_error.js';
1
+ import { AppError } from '../../cli/class/errors/app/app_error.js';
2
2
  export class DownloadFileErrorsFactory {
3
3
  static downloadError(status) {
4
4
  return new AppError({
@@ -3,11 +3,13 @@ import { createWriteStream } from 'fs';
3
3
  import { URL } from 'url';
4
4
  import { basename, extname, join, parse } from '../path_utils.js';
5
5
  import { FileSystemErrorsFactory } from '../../cli/class/errors/file_system_errors_factory.js';
6
- import { HttpErrorsFactory } from '../../cli/class/errors/http_errors_factory.js';
6
+ import { HttpErrorsFactory } from '../../cli/class/errors/http/http_errors_factory.js';
7
7
  import { DownloadFileErrorsFactory } from './download_file_errors_factory.js';
8
8
  export const downloadFile = async ({ dist, request }) => {
9
9
  try {
10
10
  const resp = (await request);
11
+ if (!resp)
12
+ throw resp;
11
13
  const headers = resp.headers;
12
14
  const url = new URL(resp.config.url);
13
15
  const filename = getFileNameFromHeaders(headers) ?? basename(url.pathname);
@@ -41,6 +43,6 @@ export const downloadFile = async ({ dist, request }) => {
41
43
  throw DownloadFileErrorsFactory.downloadError(err.response.status);
42
44
  }
43
45
  }
46
+ throw DownloadFileErrorsFactory.downloadError('Unknown error');
44
47
  }
45
- throw DownloadFileErrorsFactory.downloadError('Unknown error');
46
48
  };
@@ -1,4 +1,4 @@
1
- import { AppError } from '../../../cli/class/errors/app_error/app_error.js';
1
+ import { AppError } from '../../../cli/class/errors/app/app_error.js';
2
2
  export class StreamReadError extends AppError {
3
3
  constructor({ filePath, details, stack }) {
4
4
  super({
@@ -1,4 +1,4 @@
1
- import { AppError } from '../../../cli/class/errors/app_error/app_error.js';
1
+ import { AppError } from '../../../cli/class/errors/app/app_error.js';
2
2
  export class StreamWriteError extends AppError {
3
3
  constructor({ filePath, details, stack }) {
4
4
  super({
@@ -1,5 +1,5 @@
1
1
  import fsPromises from 'node:fs/promises';
2
- import fs, { createReadStream } from 'node:fs';
2
+ import fs, { createReadStream, readFileSync } from 'node:fs';
3
3
  import { isHiddenFile } from 'is-hidden-file';
4
4
  import process from 'node:process';
5
5
  import { basename, join, resolve } from '../path_utils.js';
@@ -9,6 +9,7 @@ import { JSON_FILE_INDENT } from '../../cli/cli_constants.js';
9
9
  import tmp from 'tmp-promise';
10
10
  import { pipeline } from 'node:stream/promises';
11
11
  import { jsonIndentTransform } from '../stream_transforms/json_indent_transform.js';
12
+ import { move } from 'fs-extra';
12
13
  export const fileExists = async (path) => {
13
14
  try {
14
15
  await fsPromises.access(path);
@@ -38,6 +39,17 @@ export const readJSONFile = async (path, options = { encoding: 'utf-8', flag: 'r
38
39
  throw new Error(`Failed to parse JSON from file ${path}: ${error}`);
39
40
  }
40
41
  };
42
+ export const readJSONFileSync = (path, options = { encoding: 'utf-8', flag: 'r' }) => {
43
+ const fileContent = readFileSync(path, options);
44
+ if (typeof fileContent !== 'string')
45
+ throw new Error('File content is not a string');
46
+ try {
47
+ return JSON.parse(fileContent);
48
+ }
49
+ catch (error) {
50
+ throw new Error(`Failed to parse JSON from file ${path}: ${error}`);
51
+ }
52
+ };
41
53
  export const writeJSONFile = async (path, data) => {
42
54
  try {
43
55
  await writeFile(path, JSON.stringify(data, null, JSON_FILE_INDENT), {
@@ -50,13 +62,15 @@ export const writeJSONFile = async (path, data) => {
50
62
  }
51
63
  };
52
64
  export const formatJSONFile = async (path, indent = JSON_FILE_INDENT) => {
53
- const { path: tmpDir } = await tmp.dir({ unsafeCleanup: true });
65
+ const { path: tmpDir, cleanup } = await tmp.dir({ unsafeCleanup: true });
54
66
  const fileName = basename(path);
55
67
  const formattedTmpFilePath = join(tmpDir, fileName);
56
68
  const readStream = createReadStream(path);
57
69
  const writeStream = fs.createWriteStream(formattedTmpFilePath);
58
70
  await pipeline(readStream, jsonIndentTransform(indent), writeStream);
59
- await copyFile(formattedTmpFilePath, path, { force: true });
71
+ // await copyFile(formattedTmpFilePath, path, { force: true });
72
+ await move(formattedTmpFilePath, path, { overwrite: true });
73
+ await cleanup();
60
74
  };
61
75
  export const openFile = async (path, flags, mode) => {
62
76
  return fsPromises.open(path, flags, mode);
@@ -1,5 +1,6 @@
1
- import { basename as pathBaseName, dirname as pathDirname, extname as pathExtname, join as pathJoin, normalize, parse as parsePath, relative as pathRelative, resolve as resolvePath, sep } from 'node:path';
1
+ import path, { basename as pathBaseName, dirname as pathDirname, extname as pathExtname, join as pathJoin, normalize, parse as parsePath, relative as pathRelative, resolve as resolvePath, sep } from 'node:path';
2
2
  import fs from 'node:fs';
3
+ import { isWindowsOs } from './platform_utils.js';
3
4
  export const resolve = (...paths) => {
4
5
  return resolvePath(...paths);
5
6
  };
@@ -31,4 +32,22 @@ export const looksLikeDirectory = (path) => {
31
32
  }
32
33
  return isHidden || !hasExtension;
33
34
  };
35
+ export const toUnixPath = (filePath) => {
36
+ return normalize(filePath).split(sep).join(path.posix.sep);
37
+ };
38
+ export const toWinowsPath = (filePath) => {
39
+ return normalize(filePath).split(sep).join(path.win32.sep);
40
+ };
41
+ export const isUnixPath = (path) => {
42
+ return !path.includes('\\') && (path.startsWith('/') || path.includes('/'));
43
+ };
34
44
  export const platformSeparator = sep;
45
+ export const mapKeysPathsToWindowPlatform = (paths) => {
46
+ return Object.entries(paths).reduce((acc, [path, value]) => {
47
+ return {
48
+ ...acc,
49
+ [toWinowsPath(path)]: value
50
+ };
51
+ }, {});
52
+ };
53
+ export const toCurrentPlatformPath = (path) => (isWindowsOs() ? toWinowsPath(path) : toUnixPath(path));
@@ -0,0 +1,3 @@
1
+ export const isWindowsOs = () => {
2
+ return process.platform === 'win32';
3
+ };
@@ -6,7 +6,7 @@ import { StreamReadError } from '../fs/errors/stream_read_error.js';
6
6
  import { CreateZipError } from './errors/create_zip_error.js';
7
7
  import { StreamWriteError } from '../fs/errors/stream_write_error.js';
8
8
  import { join } from '../path_utils.js';
9
- import { AppError } from '../../cli/class/errors/app_error/app_error.js';
9
+ import { AppError } from '../../cli/class/errors/app/app_error.js';
10
10
  export const createZip = async ({ files, dist, baseDir = process.cwd() }) => {
11
11
  const zipfile = new yazl.ZipFile();
12
12
  let hasError = false;
@@ -1,4 +1,4 @@
1
- import { AppError } from '../../../cli/class/errors/app_error/app_error.js';
1
+ import { AppError } from '../../../cli/class/errors/app/app_error.js';
2
2
  export class CreateZipError extends AppError {
3
3
  constructor({ details, stack, file }) {
4
4
  super({
@@ -1,4 +1,4 @@
1
- import { AppError } from '../../../cli/class/errors/app_error/app_error.js';
1
+ import { AppError } from '../../../cli/class/errors/app/app_error.js';
2
2
  export class OpenZipError extends AppError {
3
3
  constructor({ details, stack, file }) {
4
4
  super({
package/oclif.config.js CHANGED
@@ -18,8 +18,8 @@ export default {
18
18
  prerun: [
19
19
  './build/cli/hooks/authorization/ensure_authorization_hook.js',
20
20
  './build/cli/hooks/ensure_cli_initialized_hook.js',
21
- './build/theme/hooks/ensure_theme_meta_data_untouched.js',
22
- './build/theme/hooks/ensure_theme_current_checksums_up_to_date.js',
21
+ './build/theme/hooks/ensure_theme_meta_data_untouched_hook.js',
22
+ './build/theme/hooks/theme_checksums/ensure_theme_current_checksums_up_to_date_hook.js',
23
23
  './build/theme/hooks/themes_actions/ensure_themes_actions_hook.js'
24
24
  ]
25
25
  },
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@shoper/cli",
3
3
  "packageManager": "yarn@3.2.0",
4
4
  "sideEffects": false,
5
- "version": "0.1.0-8",
5
+ "version": "0.2.0",
6
6
  "description": "CLI tool for Shoper",
7
7
  "author": "Joanna Firek",
8
8
  "license": "MIT",
@@ -27,10 +27,10 @@
27
27
  "test": "jest --config config/jest/jest.config.mjs",
28
28
  "test:watch": "jest --config config/jest/jest.config.mjs --no-cache --watch",
29
29
  "deploy:latest": "npm run build && npm publish --tag latest --access public",
30
- "deploy:beta": "npm run build && npm publish --tag beta --access public"
30
+ "deploy:beta": "npm run build && npm version prerelease --no-git-tag-version && npm publish --tag beta --access public"
31
31
  },
32
32
  "dependencies": {
33
- "@dreamcommerce/star_core": "1.8.1",
33
+ "@dreamcommerce/star_core": "1.8.5",
34
34
  "@oclif/core": "4.2.10",
35
35
  "@oclif/plugin-autocomplete": "3.2.27",
36
36
  "@oclif/plugin-help": "6.2.27",
@@ -40,13 +40,13 @@
40
40
  "axios": "1.8.4",
41
41
  "chalk": "5.4.1",
42
42
  "conf": "13.1.0",
43
- "ink": "5.2.1",
43
+ "ink": "6.0.1",
44
44
  "inquirer": "12.5.2",
45
45
  "is-hidden-file": "1.1.2",
46
46
  "jsonwebtoken": "9.0.2",
47
47
  "memfs": "4.17.0",
48
48
  "ora": "8.2.0",
49
- "react": "18.3.1",
49
+ "react": "19.1.0",
50
50
  "reflect-metadata": "0.2.2",
51
51
  "rxjs": "7.8.2",
52
52
  "semver": "7.7.1",
@@ -58,18 +58,25 @@
58
58
  "klaw": "4.1.0",
59
59
  "walk-sync": "3.0.0",
60
60
  "lodash": "4.17.21",
61
- "uuid": "11.1.0"
61
+ "uuid": "11.1.0",
62
+ "fs-extra": "11.3.0",
63
+ "ink-link": "4.1.0",
64
+ "log-symbols": "7.0.1",
65
+ "figures": "6.1.0",
66
+ "strip-ansi": "7.1.0",
67
+ "inquirer-select-line": "1.1.3"
62
68
  },
63
69
  "devDependencies": {
64
70
  "@babel/core": "7.27.1",
65
71
  "@babel/preset-env": "7.27.2",
66
72
  "@babel/preset-typescript": "7.27.1",
67
73
  "@oclif/test": "4.1.12",
68
- "@tsconfig/node18": "18.2.4",
74
+ "@tsconfig/node20": "20.1.6",
69
75
  "@types/jest": "29.5.14",
76
+ "@types/fs-extra": "11.0.4",
70
77
  "@types/jsonwebtoken": "9.0.9",
71
78
  "@types/node": "18.19.84",
72
- "@types/react": "19.1.3",
79
+ "@types/react": "19.1.8",
73
80
  "@types/semver": "7.7.0",
74
81
  "@types/tmp": "0.2.6",
75
82
  "@types/yauzl": "2.10.3",
@@ -1,53 +0,0 @@
1
- import { BaseThemeCommand } from '../class/base_theme_command.js';
2
- import { Args } from '@oclif/core';
3
- import { THEME_INIT_API_NAME } from '../features/theme/init/theme_init_constants.js';
4
- import { CLI_AUTH_API_NAME } from '../../cli/auth/cli_auth_constants.js';
5
- import ora from 'ora';
6
- import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../cli/features/execution_context/execution_context_constants.js';
7
- import { THEME_ACTIONS_API_NAME, THEME_ACTIONS_TYPES } from '../features/theme/actions/theme_actions_constants.js';
8
- export class ThemeInitCommand extends BaseThemeCommand {
9
- static description = 'Clone a theme with provided ID from the shop';
10
- static args = {
11
- id: Args.string({
12
- description: 'Theme id',
13
- name: 'id',
14
- required: true,
15
- type: 'string'
16
- })
17
- };
18
- async run() {
19
- const data = await this.parse(ThemeInitCommand);
20
- const { args } = data;
21
- const themeId = args.id;
22
- const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
23
- const themeInitApi = this.getApi(THEME_INIT_API_NAME);
24
- const themeActionsApi = this.getApi(THEME_ACTIONS_API_NAME);
25
- const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
26
- const credentials = cliAuthApi.getCredentials();
27
- if (!credentials)
28
- this.error('Credentials not found. Please authorize first.');
29
- const copyAction = themeActionsApi.getThemeAction({
30
- actionType: THEME_ACTIONS_TYPES.copy,
31
- themeId,
32
- credentials
33
- });
34
- if (!copyAction)
35
- this.error(`You cannot init theme with id ${themeId}`);
36
- const executionContext = await executionContextApi.getExecutionContext();
37
- if (executionContext.type === EXECUTION_CONTEXTS.theme)
38
- this.error('You cannot run this command in the theme execution context');
39
- const spinner = ora('Creating theme...').start();
40
- try {
41
- await themeInitApi.initTheme({ action: copyAction, credentials });
42
- spinner.stopAndPersist({
43
- symbol: '\u2713',
44
- text: 'Theme successfully created!'
45
- });
46
- }
47
- catch (err) {
48
- // TODO handle error
49
- spinner.clear();
50
- this.error(String(err));
51
- }
52
- }
53
- }
@@ -1,16 +0,0 @@
1
- import { BaseThemeCommand } from '../class/base_theme_command.js';
2
- import { THEMES_LIST_API_NAME } from '../features/themes/list/themes_list_constants.js';
3
- import { CLI_AUTH_API_NAME } from '../../cli/auth/cli_auth_constants.js';
4
- export class ThemeListCommand extends BaseThemeCommand {
5
- static description = 'List all shop themes';
6
- async run() {
7
- const ThemesListApi = this.getApi(THEMES_LIST_API_NAME);
8
- const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
9
- const credentials = cliAuthApi.getCredentials();
10
- if (!credentials)
11
- this.error('Credentials not found. Please authorize first.');
12
- const themes = await ThemesListApi.getThemes(credentials);
13
- //TODO UI
14
- this.log('themes', themes);
15
- }
16
- }
@@ -1,124 +0,0 @@
1
- import { Args, Flags } from '@oclif/core';
2
- import { BaseThemeCommand } from '../class/base_theme_command.js';
3
- import { THEME_FETCH_API_NAME, THEME_FETCH_TYPES } from '../features/theme/fetch/theme_fetch_constants.js';
4
- import { CLI_AUTH_API_NAME } from '../../cli/auth/cli_auth_constants.js';
5
- import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../cli/features/execution_context/execution_context_constants.js';
6
- import inquirer from 'inquirer';
7
- import ora from 'ora';
8
- import { THEME_MERGE_API_NAME } from '../features/theme/merge/theme_merge_constants.js';
9
- import tmp from 'tmp-promise';
10
- import { join } from '../../utils/path_utils.js';
11
- import { THEME_ACTIONS_API_NAME, THEME_ACTIONS_TYPES } from '../features/theme/actions/theme_actions_constants.js';
12
- import process from 'node:process';
13
- import { ThemeResourcesWithIdDirectoryUtils } from '../features/theme/utils/directories/theme_resources_with_id_directory_utils.js';
14
- export class ThemePullCommand extends BaseThemeCommand {
15
- static description = 'Pull theme from shop';
16
- static args = {
17
- id: Args.string({
18
- description: 'Theme id',
19
- name: 'id',
20
- type: 'string'
21
- })
22
- };
23
- static flags = {
24
- type: Flags.string({
25
- default: THEME_FETCH_TYPES.full,
26
- description: 'Type of theme to pull',
27
- options: Object.values(THEME_FETCH_TYPES)
28
- })
29
- };
30
- async run() {
31
- const data = await this.parse(ThemePullCommand);
32
- const { args, flags } = data;
33
- const themeId = args.id;
34
- const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
35
- const themeFetchApi = this.getApi(THEME_FETCH_API_NAME);
36
- const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
37
- const themeActionsApi = this.getApi(THEME_ACTIONS_API_NAME);
38
- const credentials = cliAuthApi.getCredentials();
39
- if (!credentials)
40
- this.error('Credentials not found. Please authorize first.');
41
- const executionContext = await executionContextApi.getExecutionContext();
42
- const spinner = ora('Pulling theme...').start();
43
- try {
44
- if (executionContext.type !== EXECUTION_CONTEXTS.theme) {
45
- if (themeId === undefined)
46
- this.error('To run this command outside theme context you must provide theme id.');
47
- const pullAction = themeActionsApi.getThemeAction({
48
- actionType: THEME_ACTIONS_TYPES.pull,
49
- themeId: themeId,
50
- credentials
51
- });
52
- await themeFetchApi.fetchTheme({
53
- credentials,
54
- action: pullAction,
55
- config: {
56
- dist: process.cwd(),
57
- fetchType: flags.type
58
- }
59
- });
60
- spinner.stopAndPersist({
61
- symbol: '\u2713',
62
- text: 'Theme successfully pulled!'
63
- });
64
- return;
65
- }
66
- const _themeId = themeId ? themeId : executionContext.themeId;
67
- const pullAction = themeActionsApi.getThemeAction({
68
- actionType: THEME_ACTIONS_TYPES.pull,
69
- themeId: _themeId,
70
- credentials
71
- });
72
- if (executionContext.themeId !== _themeId) {
73
- this.error('You cannot pull a theme in the theme execution context that is not the current theme.');
74
- }
75
- const themeMergeApi = this.getApi(THEME_MERGE_API_NAME);
76
- const { path: tmpDir } = await tmp.dir({ unsafeCleanup: true });
77
- const { name } = await themeFetchApi.fetchTheme({
78
- credentials,
79
- action: pullAction,
80
- config: {
81
- fetchType: flags.type,
82
- dist: tmpDir
83
- }
84
- });
85
- await ThemeResourcesWithIdDirectoryUtils.updateDirectoryNamesOfResourcesWithIdAccordingToLocalThemeNames(join(executionContext.themeRootDir, 'modules'), executionContext.themeRootDir, join(tmpDir, name, 'modules'), join(tmpDir, name));
86
- spinner.stopAndPersist({
87
- symbol: '\u2713',
88
- text: 'Theme successfully pulled!'
89
- });
90
- this.log('\n');
91
- const changes = await themeMergeApi.getChangesBetweenThemes(join(tmpDir, name), executionContext.themeRootDir);
92
- if (await themeMergeApi.hasThemeBeenModified(executionContext.themeRootDir)) {
93
- console.log('changes', changes);
94
- this.log('You have unpublished changes in your theme...\n');
95
- this.log('The following files will be changed:\n');
96
- changes.forEach(([action, name]) => {
97
- console.log(name, ' - ', action);
98
- });
99
- console.log('\n');
100
- const { proceed } = await inquirer.prompt([
101
- {
102
- type: 'confirm',
103
- name: 'proceed',
104
- message: 'Do you want to continue and overwrite local changes?',
105
- default: true
106
- }
107
- ]);
108
- if (!proceed)
109
- this.log('Pull operation cancelled. Your local changes are safe.');
110
- }
111
- try {
112
- await themeMergeApi.applyChanges(join(tmpDir, name), executionContext.themeRootDir, changes);
113
- }
114
- catch (err) {
115
- console.log('err', err);
116
- }
117
- }
118
- catch (err) {
119
- // TODO handle error
120
- spinner.clear();
121
- this.error(String(err));
122
- }
123
- }
124
- }