@shoper/cli 0.1.0-9 → 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.
- package/build/cli/auth/cli_auth_errors_factory.js +1 -1
- package/build/cli/auth/tokens/cli_auth_tokens_errors_factory.js +1 -1
- package/build/cli/auth/tokens/cli_auth_tokens_initalizer.js +1 -1
- package/build/cli/class/errors/file_system_errors_factory.js +1 -1
- package/build/cli/class/errors/http/http_errors_constants.js +1 -0
- package/build/cli/class/errors/{http_errors_factory.js → http/http_errors_factory.js} +3 -2
- package/build/cli/commands/auth/cli_auth_add_token_command.js +22 -19
- package/build/cli/commands/auth/cli_auth_commands_constants.js +3 -0
- package/build/cli/commands/auth/cli_auth_commands_utils.js +46 -0
- package/build/cli/commands/auth/cli_auth_list_tokens_command.js +19 -6
- package/build/cli/commands/auth/cli_auth_remove_token_command.js +36 -10
- package/build/cli/commands/auth/cli_auth_switch_token_command.js +19 -9
- package/build/cli/commands/auth/ui/invalid_token_index_error.js +11 -0
- package/build/cli/commands/auth/ui/missing_credentials_error.js +9 -0
- package/build/cli/commands/auth/ui/missing_token_index_error.js +19 -0
- package/build/cli/commands/cli_ui_dump_command.js +11 -0
- package/build/cli/commands/cli_update_command.js +13 -4
- package/build/cli/commands/commands_constants.js +2 -1
- package/build/cli/core/cli_setup.js +5 -1
- package/build/cli/features/controls/controls_constants.js +12 -0
- package/build/cli/features/controls/controls_dto_mappers.js +55 -0
- package/build/cli/features/controls/ui/controls_mappers.js +62 -0
- package/build/cli/features/controls/ui/form.js +4 -0
- package/build/cli/features/controls/ui/form_constants.js +7 -0
- package/build/cli/features/controls/validators/greater_eq_than_validator.js +5 -0
- package/build/cli/features/controls/validators/length_validator.js +6 -0
- package/build/cli/features/controls/validators/required_validator.js +5 -0
- package/build/cli/features/controls/validators/validator_constants.js +13 -0
- package/build/cli/features/execution_context/execution_context_service.js +5 -5
- package/build/cli/features/http_requester/http_requester_initializer.js +1 -1
- package/build/cli/hooks/authorization/ensure_authorization_hook.js +2 -2
- package/build/cli/hooks/authorization/ensure_authorization_hook_constants.js +8 -8
- package/build/index.js +37 -19
- package/build/theme/class/checksums/theme_checksums.js +174 -0
- package/build/theme/{features/theme/utils → class}/checksums/theme_checksums_error_factory.js +1 -1
- package/build/theme/class/checksums/theme_checksums_utils.js +17 -0
- package/build/theme/class/fetch_resources/fetch_resources.js +1 -0
- package/build/theme/class/fetch_resources/fetch_resources_errors_factory.js +1 -1
- package/build/theme/class/fetch_resources/fetch_resources_utils.js +4 -1
- package/build/theme/commands/delete/theme_delete_command.js +111 -0
- package/build/theme/commands/delete/ui/theme_deleted_successfully.js +15 -0
- package/build/theme/commands/delete/ui/theme_deletion_warning.js +10 -0
- package/build/theme/commands/info/theme_info_command.js +94 -0
- package/build/theme/commands/info/theme_info_command_utils.js +39 -0
- package/build/theme/commands/init/theme_init_command.js +97 -0
- package/build/theme/commands/init/ui/theme_created_success.js +15 -0
- package/build/theme/commands/list/theme_list_command.js +25 -0
- package/build/theme/commands/list/theme_list_command_utils.js +27 -0
- package/build/theme/commands/publish/theme_publish_command.js +92 -0
- package/build/theme/commands/pull/theme_pull_command.js +194 -0
- package/build/theme/commands/pull/ui/theme_pull_id_mismatch_error.js +7 -0
- package/build/theme/commands/pull/ui/theme_pull_unpublished_changes_warning.js +10 -0
- package/build/theme/commands/pull/ui/theme_pulled_success.js +5 -0
- package/build/theme/commands/push/theme_push_command.js +134 -0
- package/build/theme/commands/push/ui/theme_push_skip_into.js +7 -0
- package/build/theme/commands/push/ui/theme_pushed_success.js +5 -0
- package/build/theme/commands/push/ui/theme_unpermitted_actions_error.js +12 -0
- package/build/theme/commands/theme_commands_constants.js +4 -1
- package/build/theme/commands/theme_show_changes_command.js +1 -0
- package/build/theme/commands/theme_verify_command.js +8 -7
- package/build/theme/commands/ui/invalid_theme_id.js +11 -0
- package/build/theme/commands/ui/missing_theme_files.js +15 -0
- package/build/theme/commands/ui/missing_theme_id_error.js +13 -0
- package/build/theme/commands/ui/ouside_of_theme_directory_context_error.js +7 -0
- package/build/theme/commands/ui/theme_directory_context_error.js +7 -0
- package/build/theme/commands/ui/theme_work_url_mismatch.js +17 -0
- package/build/theme/commands/ui/unpermitted_command_error.js +18 -0
- package/build/theme/features/theme/actions/api/theme_actions_api.js +3 -0
- package/build/theme/features/theme/actions/service/theme_actions_service.js +15 -3
- package/build/theme/features/theme/actions/service/theme_actions_service_constants.js +1 -0
- package/build/theme/features/theme/actions/theme_actions_constants.js +3 -1
- package/build/theme/features/theme/actions/theme_actions_initializer.js +1 -1
- package/build/theme/features/theme/actions/theme_actions_utils.js +20 -7
- package/build/theme/features/theme/delete/api/theme_delete_api.js +13 -0
- package/build/theme/features/theme/delete/http/theme_delete_http_api.js +17 -0
- package/build/theme/features/theme/delete/service/theme_delete_service.js +31 -0
- package/build/theme/features/theme/delete/theme_delete_constants.js +2 -0
- package/build/theme/features/theme/delete/theme_delete_initalizer.js +20 -0
- package/build/theme/features/theme/fetch/service/theme_fetch_service.js +30 -10
- package/build/theme/features/theme/info/theme_info_utils.js +9 -0
- package/build/theme/features/theme/init/service/theme_init_service.js +9 -4
- package/build/theme/features/theme/merge/api/theme_merge_api.js +0 -12
- package/build/theme/features/theme/merge/service/theme_merge_service.js +20 -28
- package/build/theme/features/theme/push/service/theme_push_service.js +92 -69
- package/build/theme/features/theme/push/theme_push_constants.js +2 -0
- package/build/theme/features/theme/push/theme_push_errors_factory.js +7 -4
- package/build/theme/features/theme/push/theme_push_initializer.js +0 -3
- package/build/theme/features/theme/push/theme_push_utils.js +25 -0
- package/build/theme/features/theme/skinstore/api/theme_skinstore_api.js +19 -0
- package/build/theme/features/theme/skinstore/http/theme_skinstore_http_api.js +17 -0
- package/build/theme/features/theme/skinstore/service/theme_skinstore_service.js +32 -0
- package/build/theme/features/theme/skinstore/theme_publish_constants.js +4 -0
- package/build/theme/features/theme/skinstore/theme_skinstore_initialzier.js +20 -0
- package/build/theme/features/theme/utils/files_structure/theme_files_structure_utils.js +40 -0
- package/build/theme/features/theme/utils/hidden_directory/hidden_directory_utils.js +32 -0
- package/build/theme/features/theme/utils/meta_data/theme_meta_data_constants.js +1 -0
- package/build/theme/features/theme/utils/meta_data/theme_meta_data_error_factory.js +15 -0
- package/build/theme/features/theme/utils/meta_data/theme_meta_data_utils.js +39 -0
- package/build/theme/features/theme/utils/{directories → resources}/theme_resources_with_id_directory_utils.js +3 -14
- package/build/theme/features/theme/utils/theme_images_utils.js +1 -1
- package/build/theme/features/themes/list/api/themes_list_api.js +3 -0
- package/build/theme/features/themes/list/services/themes_list_service.js +13 -7
- package/build/theme/hooks/{ensure_theme_meta_data_untouched.js → ensure_theme_meta_data_untouched_hook.js} +2 -2
- package/build/theme/hooks/theme_checksums/ensure_theme_current_checksums_up_to_date_constants.js +1 -1
- 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
- package/build/theme/hooks/themes_actions/ensure_themes_actions_hook.js +1 -0
- package/build/theme/hooks/themes_actions/ensure_themes_actions_hook_constants.js +1 -0
- package/build/theme/index.js +11 -5
- package/build/theme/utils/directory_validator/directory_validator_constants.js +2 -6
- package/build/theme/utils/directory_validator/directory_validator_utils.js +7 -25
- package/build/ui/box.js +2 -0
- package/build/ui/color_constants.js +30 -0
- package/build/ui/command.js +6 -0
- package/build/ui/file_name.js +6 -0
- package/build/ui/flag.js +6 -0
- package/build/ui/icons/error_icon.js +7 -0
- package/build/ui/icons/info_icon.js +7 -0
- package/build/ui/icons/success_icon.js +7 -0
- package/build/ui/icons/warning_icon.js +7 -0
- package/build/ui/link.js +8 -0
- package/build/ui/list/list.js +10 -0
- package/build/ui/list/list_constants.js +4 -0
- package/build/ui/list/list_item.js +11 -0
- package/build/ui/message_box/error.js +4 -0
- package/build/ui/message_box/info.js +4 -0
- package/build/ui/message_box/message_box.js +11 -0
- package/build/ui/message_box/message_box_constants.js +24 -0
- package/build/ui/message_box/success.js +4 -0
- package/build/ui/message_box/warning.js +4 -0
- package/build/ui/prompts/prompt_confirmation.js +11 -0
- package/build/ui/prompts/prompt_input.js +10 -0
- package/build/ui/table/t_cell.js +7 -0
- package/build/ui/table/t_header.js +9 -0
- package/build/ui/table/t_row.js +5 -0
- package/build/ui/table/table.js +18 -0
- package/build/ui/text.js +2 -0
- package/build/ui/tip.js +9 -0
- package/build/ui/ui_dump/ui_component_box.js +9 -0
- package/build/ui/ui_dump/ui_dump.js +53 -0
- package/build/ui/ui_dump/ui_dump_constants.js +21 -0
- package/build/ui/ui_utils.js +11 -0
- package/build/ui/validation_errors/validation_error_content.js +19 -0
- package/build/ui/validation_errors/validation_errors.js +21 -0
- package/build/ui/validation_errors/validation_errors_utils.js +17 -0
- package/build/utils/checksums/checksums_utils.js +9 -26
- package/build/utils/download_file/download_file_errors_factory.js +1 -1
- package/build/utils/download_file/download_file_utils.js +4 -2
- package/build/utils/fs/errors/stream_read_error.js +1 -1
- package/build/utils/fs/errors/stream_write_error.js +1 -1
- package/build/utils/fs/fs_utils.js +12 -1
- package/build/utils/path_utils.js +18 -2
- package/build/utils/platform_utils.js +3 -0
- package/build/utils/zip/create_zip_utils.js +1 -1
- package/build/utils/zip/errors/create_zip_error.js +1 -1
- package/build/utils/zip/errors/open_zip_error.js +1 -1
- package/oclif.config.js +2 -2
- package/package.json +13 -8
- package/build/theme/commands/theme_init_command.js +0 -53
- package/build/theme/commands/theme_list_command.js +0 -16
- package/build/theme/commands/theme_pull_command.js +0 -126
- package/build/theme/commands/theme_push_command.js +0 -65
- package/build/theme/features/theme/directory/theme_directory_utils.js +0 -76
- package/build/theme/features/theme/publish/theme_publish_constants.js +0 -2
- package/build/theme/features/theme/utils/checksums/theme_checksums_utils.js +0 -94
- /package/build/cli/{features → class}/caches/cache_factory.js +0 -0
- /package/build/cli/{features → class}/caches/json_cache/json_cache.js +0 -0
- /package/build/cli/{features → class}/caches/memory_cache.js +0 -0
- /package/build/cli/class/errors/{app_error → app}/app_error.js +0 -0
- /package/build/cli/class/errors/{app_error → app}/app_error_constants.js +0 -0
- /package/build/theme/features/theme/{publish → skinstore}/theme_publish_utils.js +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import process from 'node:process';
|
|
2
2
|
import { EXECUTION_CONTEXTS } from './execution_context_constants.js';
|
|
3
|
-
import {
|
|
3
|
+
import { ThemeMetaDataUtils } from '../../../theme/features/theme/utils/meta_data/theme_meta_data_utils.js';
|
|
4
4
|
export class ExecutionContextService {
|
|
5
5
|
#executionContext;
|
|
6
6
|
async _obtainExecutionContext() {
|
|
7
|
-
if (await
|
|
7
|
+
if (await ThemeMetaDataUtils.closestThemeRootDirectory(process.cwd())) {
|
|
8
8
|
return await this.getThemeExecutionContext();
|
|
9
9
|
}
|
|
10
10
|
return await this._getGlobalExecutionContext();
|
|
@@ -20,14 +20,14 @@ export class ExecutionContextService {
|
|
|
20
20
|
return this.#executionContext;
|
|
21
21
|
}
|
|
22
22
|
async getThemeExecutionContext() {
|
|
23
|
-
const themeRoot = await
|
|
23
|
+
const themeRoot = await ThemeMetaDataUtils.closestThemeRootDirectory(process.cwd());
|
|
24
24
|
//TODO errors
|
|
25
25
|
if (!themeRoot)
|
|
26
26
|
throw 'Theme root directory not found';
|
|
27
|
-
const
|
|
27
|
+
const themeMetaData = await ThemeMetaDataUtils.getThemeMetadata(themeRoot);
|
|
28
28
|
return {
|
|
29
29
|
type: EXECUTION_CONTEXTS.theme,
|
|
30
|
-
themeId:
|
|
30
|
+
themeId: themeMetaData.themeId,
|
|
31
31
|
executionDir: process.cwd(),
|
|
32
32
|
themeRootDir: themeRoot
|
|
33
33
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CACHE_TYPES, CacheService, DEFAULT_REQUESTER_CACHE_NAMESPACE, FEATURE_CORES_TYPES, HTTP_REQUESTER_FEATURE_NAME, HTTPRequesterApi, HTTPRequesterBalancer, REQUEST_SOURCE, Requester, RequesterCacheServiceKeySerializer, SANITIZER_API_NAME, StrategiesContainer, SyncFeatureInitializer } from '@dreamcommerce/star_core';
|
|
2
2
|
import { HttpClient } from './http_client.js';
|
|
3
|
-
import { CacheFactory } from '
|
|
3
|
+
import { CacheFactory } from '../../class/caches/cache_factory.js';
|
|
4
4
|
export class HTTPRequesterInitializer extends SyncFeatureInitializer {
|
|
5
5
|
static featureName = HTTP_REQUESTER_FEATURE_NAME;
|
|
6
6
|
init() {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { COMMANDS_THAT_REQUIRE_AUTHORIZATION } from './ensure_authorization_hook_constants.js';
|
|
2
2
|
import { useApi } from '../ensure_cli_initialized_hook.js';
|
|
3
3
|
import { CLI_AUTH_API_NAME } from '../../auth/cli_auth_constants.js';
|
|
4
4
|
import { CLI_AUTH_TOKENS_API_NAME } from '../../auth/tokens/cli_auth_tokens_constants.js';
|
|
5
5
|
import { promptForToken } from '../../commands/utils/prompt_for_token_utils.js';
|
|
6
6
|
import { CliAuthUtils } from '../../auth/cli_auth_utils.js';
|
|
7
7
|
const ensureAuthorizationHook = async ({ Command }) => {
|
|
8
|
-
if (
|
|
8
|
+
if (!COMMANDS_THAT_REQUIRE_AUTHORIZATION.includes(Command.id))
|
|
9
9
|
return;
|
|
10
10
|
const cliAuthApi = useApi(CLI_AUTH_API_NAME);
|
|
11
11
|
const cliAuthTokensApi = useApi(CLI_AUTH_TOKENS_API_NAME);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { THEME_COMMANDS_NAME } from '../../../theme/commands/theme_commands_constants.js';
|
|
2
|
+
export const COMMANDS_THAT_REQUIRE_AUTHORIZATION = [
|
|
3
|
+
THEME_COMMANDS_NAME.push,
|
|
4
|
+
THEME_COMMANDS_NAME.pull,
|
|
5
|
+
THEME_COMMANDS_NAME.list,
|
|
6
|
+
THEME_COMMANDS_NAME.init,
|
|
7
|
+
THEME_COMMANDS_NAME.showChanges,
|
|
8
|
+
THEME_COMMANDS_NAME.verify
|
|
9
9
|
];
|
package/build/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { CliAuthListTokensCommand } from './cli/commands/auth/cli_auth_list_toke
|
|
|
7
7
|
import { CliAuthAddTokenCommand } from './cli/commands/auth/cli_auth_add_token_command.js';
|
|
8
8
|
import { CliAuthRemoveTokenCommand } from './cli/commands/auth/cli_auth_remove_token_command.js';
|
|
9
9
|
import { CliAuthSwitchTokenCommand } from './cli/commands/auth/cli_auth_switch_token_command.js';
|
|
10
|
+
import { CliUIDumpCommand } from './cli/commands/cli_ui_dump_command.js';
|
|
10
11
|
//TODO
|
|
11
12
|
//@ts-ignore
|
|
12
13
|
if (typeof global.crypto !== 'object') {
|
|
@@ -42,27 +43,44 @@ export const COMMANDS = {
|
|
|
42
43
|
[CLI_COMMANDS_NAMES.authAddToken]: CliAuthAddTokenCommand,
|
|
43
44
|
[CLI_COMMANDS_NAMES.authRemoveToken]: CliAuthRemoveTokenCommand,
|
|
44
45
|
[CLI_COMMANDS_NAMES.switchToken]: CliAuthSwitchTokenCommand,
|
|
46
|
+
[CLI_COMMANDS_NAMES.uiDump]: CliUIDumpCommand,
|
|
45
47
|
...THEME_COMMANDS
|
|
46
48
|
};
|
|
47
49
|
export { runCLI } from './cli/index.js';
|
|
48
50
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* -
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* -
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* -
|
|
66
|
-
*
|
|
67
|
-
*
|
|
51
|
+
* Przetestowane na win
|
|
52
|
+
* oglne
|
|
53
|
+
* moduly:
|
|
54
|
+
* - stworzony w admince
|
|
55
|
+
* - pull w cli - v
|
|
56
|
+
* - updejt modulu w adminc i pull w cli - v
|
|
57
|
+
* - zmiana nazwy katalogu w cli, modzenie w admince i pull - v
|
|
58
|
+
* - kopiowanie stworzonego modulu w admince i push (usuniety id i code) - v
|
|
59
|
+
* - zminaa w cli i push - v
|
|
60
|
+
* - tworzenie modulu w cli, min plikow i push
|
|
61
|
+
* - aktualizowanie js/twig/settings/schema
|
|
62
|
+
* - zmiana w adminc i pull
|
|
63
|
+
* - usuwanie modulu z cli - v
|
|
64
|
+
* - usuwanie modulu z adminki - v
|
|
65
|
+
* - dodanie niedozwolonego pliku do folderu modulu
|
|
66
|
+
* - dodanie niedozwolonego pliku do folderu modules/
|
|
67
|
+
* - translacje - v
|
|
68
|
+
* macro:
|
|
69
|
+
* - dodawanie pliku do macros - v
|
|
70
|
+
* - usuniecie macro - v
|
|
71
|
+
* - modzneie makro - v
|
|
72
|
+
* - dodawanie customowego macro - v
|
|
73
|
+
* - push customowego macro - v
|
|
74
|
+
* - modzenie w admince i pull - v
|
|
75
|
+
* settingsy:
|
|
76
|
+
* - uzupelniania schemy w admince, pull w cli
|
|
77
|
+
* - uzupelnianie wartosci a admince i pull
|
|
78
|
+
* - modzenie w cli
|
|
79
|
+
* - usuniecie pliku w cli
|
|
80
|
+
* styles:
|
|
81
|
+
* - modzenie stylu w src - niedozwolone - v
|
|
82
|
+
* - modzenie custom - v
|
|
83
|
+
* - usuniecie custom - v
|
|
84
|
+
* - modzenie schema i settings - v
|
|
85
|
+
* dodanie czegos w .shoper
|
|
68
86
|
*/
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { copyFile, fileExists, readJSONFile, readJSONFileSync, removeFile } from '../../../utils/fs/fs_utils.js';
|
|
2
|
+
import { ThemeChecksumsUtils } from './theme_checksums_utils.js';
|
|
3
|
+
import { isWindowsOs } from '../../../utils/platform_utils.js';
|
|
4
|
+
import { join, mapKeysPathsToWindowPlatform, toCurrentPlatformPath } from '../../../utils/path_utils.js';
|
|
5
|
+
import { createWriteStream } from 'node:fs';
|
|
6
|
+
import { JSON_FILE_INDENT } from '../../../cli/cli_constants.js';
|
|
7
|
+
import { ThemeChecksumsErrorFactory } from './theme_checksums_error_factory.js';
|
|
8
|
+
import { computeChecksumsFromFilesStructure, computeDirectoriesChecksums, computeFileChecksum } from '../../../utils/checksums/checksums_utils.js';
|
|
9
|
+
import { normalize } from 'node:path';
|
|
10
|
+
import { ThemePushUtils } from '../../../theme/features/theme/push/theme_push_utils.js';
|
|
11
|
+
import { SHOPER_THEME_METADATA_DIR } from '../../../theme/constants/directory_contstants.js';
|
|
12
|
+
import { THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME, THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME } from '../../../theme/features/theme/theme_constants.js';
|
|
13
|
+
export class ThemeChecksums {
|
|
14
|
+
#themeDir;
|
|
15
|
+
#currentChecksumsFilePath;
|
|
16
|
+
#currentChecksumsVerificationFilePath;
|
|
17
|
+
#initialChecksumsFilePath;
|
|
18
|
+
#initialChecksumsVerificationFilePath;
|
|
19
|
+
#initialChecksums;
|
|
20
|
+
#currentChecksums;
|
|
21
|
+
constructor(themeDir) {
|
|
22
|
+
this.#themeDir = themeDir;
|
|
23
|
+
this.#currentChecksumsFilePath = ThemeChecksumsUtils.getCurrentThemeChecksumsFilePath(themeDir);
|
|
24
|
+
this.#currentChecksumsVerificationFilePath = ThemeChecksumsUtils.getCurrentThemeChecksumsVerificationFilePath(themeDir);
|
|
25
|
+
this.#initialChecksumsFilePath = ThemeChecksumsUtils.getInitialThemeChecksumsFilePath(themeDir);
|
|
26
|
+
this.#initialChecksumsVerificationFilePath = ThemeChecksumsUtils.getInitialThemeChecksumsVerificationFilePath(themeDir);
|
|
27
|
+
}
|
|
28
|
+
async getInitialChecksums() {
|
|
29
|
+
if (this.#initialChecksums)
|
|
30
|
+
return this.#initialChecksums;
|
|
31
|
+
this.#initialChecksums = await this._getChecksums(this.#initialChecksumsFilePath);
|
|
32
|
+
return this.#initialChecksums;
|
|
33
|
+
}
|
|
34
|
+
getInitialChecksumsSync() {
|
|
35
|
+
if (this.#initialChecksums)
|
|
36
|
+
return this.#initialChecksums;
|
|
37
|
+
this.#initialChecksums = this._getChecksumsSync(this.#initialChecksumsFilePath);
|
|
38
|
+
return this.#initialChecksums;
|
|
39
|
+
}
|
|
40
|
+
async getCurrentChecksums() {
|
|
41
|
+
if (this.#currentChecksums)
|
|
42
|
+
return this.#currentChecksums;
|
|
43
|
+
this.#currentChecksums = await this._getChecksums(this.#currentChecksumsFilePath);
|
|
44
|
+
return this.#currentChecksums;
|
|
45
|
+
}
|
|
46
|
+
getCurrentChecksumsSync() {
|
|
47
|
+
if (this.#currentChecksums)
|
|
48
|
+
return this.#currentChecksums;
|
|
49
|
+
this.#currentChecksums = this._getChecksumsSync(this.#currentChecksumsFilePath);
|
|
50
|
+
return this.#currentChecksums;
|
|
51
|
+
}
|
|
52
|
+
async getCurrentChecksumFromPath(path) {
|
|
53
|
+
const checksums = await this.getCurrentChecksums();
|
|
54
|
+
return checksums[toCurrentPlatformPath(path)];
|
|
55
|
+
}
|
|
56
|
+
getCurrentChecksumFromPathSync(path) {
|
|
57
|
+
const checksums = this.getCurrentChecksumsSync();
|
|
58
|
+
return checksums[toCurrentPlatformPath(path)];
|
|
59
|
+
}
|
|
60
|
+
async getInitialChecksumFromPath(path) {
|
|
61
|
+
const checksums = await this.getInitialChecksums();
|
|
62
|
+
return checksums[toCurrentPlatformPath(path)];
|
|
63
|
+
}
|
|
64
|
+
getInitialChecksumFromPathSync(path) {
|
|
65
|
+
const checksums = this.getInitialChecksumsSync();
|
|
66
|
+
return checksums[toCurrentPlatformPath(path)];
|
|
67
|
+
}
|
|
68
|
+
async hasThemeBeenModified() {
|
|
69
|
+
const initialChecksums = await this._getInitialChecksumsVerification();
|
|
70
|
+
const currentChecksums = await this._getCurrentChecksumsVerification();
|
|
71
|
+
return !!initialChecksums && !!currentChecksums && initialChecksums !== currentChecksums;
|
|
72
|
+
}
|
|
73
|
+
async hasThemeFileBeenCreated(path) {
|
|
74
|
+
const initialChecksum = await this.getInitialChecksumFromPath(path);
|
|
75
|
+
return !initialChecksum && (await fileExists(join(this.#themeDir, path)));
|
|
76
|
+
}
|
|
77
|
+
async hasThemeFileBeenModified(path) {
|
|
78
|
+
const currentChecksum = await this.getCurrentChecksumFromPath(path);
|
|
79
|
+
const initialChecksum = await this.getInitialChecksumFromPath(path);
|
|
80
|
+
return !!currentChecksum && !!initialChecksum && currentChecksum !== initialChecksum;
|
|
81
|
+
}
|
|
82
|
+
async verify() {
|
|
83
|
+
const initialChecksumFilePath = this.#initialChecksumsFilePath;
|
|
84
|
+
const initialChecksumVerifyFilePath = this.#initialChecksumsVerificationFilePath;
|
|
85
|
+
const initialChecksum = await computeFileChecksum(initialChecksumFilePath);
|
|
86
|
+
const initialChecksumVerify = await readJSONFile(initialChecksumVerifyFilePath);
|
|
87
|
+
return initialChecksum === initialChecksumVerify;
|
|
88
|
+
}
|
|
89
|
+
async updateAllChecksums() {
|
|
90
|
+
const checksums = await this.computeThemeChecksums();
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
const currentChecksumFilePath = this.#currentChecksumsFilePath;
|
|
93
|
+
const initialChecksumFilePath = this.#initialChecksumsFilePath;
|
|
94
|
+
const checksumStream = createWriteStream(initialChecksumFilePath);
|
|
95
|
+
checksumStream.write(JSON.stringify(checksums, null, JSON_FILE_INDENT));
|
|
96
|
+
checksumStream.end();
|
|
97
|
+
checksumStream
|
|
98
|
+
.on('finish', async () => {
|
|
99
|
+
const initialChecksumVerifyFilePath = this.#initialChecksumsVerificationFilePath;
|
|
100
|
+
const currentChecksumVerifyFilePath = this.#currentChecksumsVerificationFilePath;
|
|
101
|
+
await this._createThemeChecksumVerifyFile(initialChecksumFilePath, initialChecksumVerifyFilePath);
|
|
102
|
+
await copyFile(initialChecksumFilePath, currentChecksumFilePath);
|
|
103
|
+
await copyFile(initialChecksumVerifyFilePath, currentChecksumVerifyFilePath);
|
|
104
|
+
resolve();
|
|
105
|
+
})
|
|
106
|
+
.on('error', async (err) => {
|
|
107
|
+
await removeFile(initialChecksumFilePath, { force: true });
|
|
108
|
+
reject(ThemeChecksumsErrorFactory.createThemeChecksumError(err.stack));
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
async updateCurrentChecksums() {
|
|
113
|
+
const checksums = await this.computeThemeChecksums();
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
const currentChecksumFilePath = this.#currentChecksumsFilePath;
|
|
116
|
+
const checksumStream = createWriteStream(currentChecksumFilePath);
|
|
117
|
+
checksumStream.write(JSON.stringify(checksums, null, JSON_FILE_INDENT));
|
|
118
|
+
checksumStream.end();
|
|
119
|
+
checksumStream
|
|
120
|
+
.on('finish', async () => {
|
|
121
|
+
const currentChecksumVerifyFilePath = this.#currentChecksumsVerificationFilePath;
|
|
122
|
+
await this._createThemeChecksumVerifyFile(currentChecksumFilePath, currentChecksumVerifyFilePath);
|
|
123
|
+
resolve();
|
|
124
|
+
})
|
|
125
|
+
.on('error', async (err) => {
|
|
126
|
+
await removeFile(currentChecksumFilePath, { force: true });
|
|
127
|
+
reject(ThemeChecksumsErrorFactory.createThemeChecksumError(err.stack));
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
async computeThemeChecksums() {
|
|
132
|
+
const filesToIgnoreInChecksums = [
|
|
133
|
+
join(SHOPER_THEME_METADATA_DIR, THEME_CURRENT_CHECKSUMS_FILE_NAME),
|
|
134
|
+
join(SHOPER_THEME_METADATA_DIR, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME),
|
|
135
|
+
join(SHOPER_THEME_METADATA_DIR, THEME_INITIAL_CHECKSUMS_FILE_NAME),
|
|
136
|
+
join(SHOPER_THEME_METADATA_DIR, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME)
|
|
137
|
+
];
|
|
138
|
+
const filesToComputeChecksums = (await ThemePushUtils.getAllFilesThatAreSendToRemote(this.#themeDir))
|
|
139
|
+
.filter((path) => !filesToIgnoreInChecksums.some((ignorePath) => normalize(path) === ignorePath))
|
|
140
|
+
.map((relativePath) => join(this.#themeDir, relativePath));
|
|
141
|
+
const { filesChecksumsInDirectories, filesChecksums } = await computeChecksumsFromFilesStructure(filesToComputeChecksums, this.#themeDir);
|
|
142
|
+
const directoriesChecksums = computeDirectoriesChecksums(filesChecksumsInDirectories);
|
|
143
|
+
return { ...filesChecksums, ...directoriesChecksums };
|
|
144
|
+
}
|
|
145
|
+
async _getInitialChecksumsVerification() {
|
|
146
|
+
return await readJSONFile(this.#initialChecksumsVerificationFilePath);
|
|
147
|
+
}
|
|
148
|
+
async _getCurrentChecksumsVerification() {
|
|
149
|
+
return await readJSONFile(this.#currentChecksumsVerificationFilePath);
|
|
150
|
+
}
|
|
151
|
+
async _getChecksums(path) {
|
|
152
|
+
const checksums = await readJSONFile(path);
|
|
153
|
+
if (!isWindowsOs())
|
|
154
|
+
return checksums;
|
|
155
|
+
return mapKeysPathsToWindowPlatform(checksums);
|
|
156
|
+
}
|
|
157
|
+
_getChecksumsSync(path) {
|
|
158
|
+
const checksums = readJSONFileSync(path);
|
|
159
|
+
if (!isWindowsOs())
|
|
160
|
+
return checksums;
|
|
161
|
+
return mapKeysPathsToWindowPlatform(checksums);
|
|
162
|
+
}
|
|
163
|
+
async _createThemeChecksumVerifyFile(checksumFilePath, checksumVerifyFullPath) {
|
|
164
|
+
const checksumVerifyStream = createWriteStream(checksumVerifyFullPath);
|
|
165
|
+
const checksumVerify = await computeFileChecksum(checksumFilePath);
|
|
166
|
+
checksumVerifyStream
|
|
167
|
+
.on('error', async (err) => {
|
|
168
|
+
await removeFile(checksumFilePath, { force: true });
|
|
169
|
+
throw ThemeChecksumsErrorFactory.createThemeChecksumError(err.stack);
|
|
170
|
+
})
|
|
171
|
+
.write(JSON.stringify(checksumVerify));
|
|
172
|
+
checksumVerifyStream.end();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { join } from '../../../utils/path_utils.js';
|
|
2
|
+
import { THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME } from '../../features/theme/theme_constants.js';
|
|
3
|
+
import { HiddenDirectoryUtils } from '../../features/theme/utils/hidden_directory/hidden_directory_utils.js';
|
|
4
|
+
export class ThemeChecksumsUtils {
|
|
5
|
+
static getCurrentThemeChecksumsFilePath(themeDir) {
|
|
6
|
+
return join(HiddenDirectoryUtils.getThemeHiddenDirectoryPath(themeDir), THEME_CURRENT_CHECKSUMS_FILE_NAME);
|
|
7
|
+
}
|
|
8
|
+
static getInitialThemeChecksumsFilePath(themeDir) {
|
|
9
|
+
return join(HiddenDirectoryUtils.getThemeHiddenDirectoryPath(themeDir), THEME_INITIAL_CHECKSUMS_FILE_NAME);
|
|
10
|
+
}
|
|
11
|
+
static getCurrentThemeChecksumsVerificationFilePath(themeDir) {
|
|
12
|
+
return join(HiddenDirectoryUtils.getThemeHiddenDirectoryPath(themeDir), THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME);
|
|
13
|
+
}
|
|
14
|
+
static getInitialThemeChecksumsVerificationFilePath(themeDir) {
|
|
15
|
+
return join(HiddenDirectoryUtils.getThemeHiddenDirectoryPath(themeDir), THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AppError } from '../../../cli/class/errors/
|
|
1
|
+
import { AppError } from '../../../cli/class/errors/app/app_error.js';
|
|
2
2
|
export class FetchResourcesErrorsFactory {
|
|
3
3
|
static createErrorFetchingResource(shopUrl, messages) {
|
|
4
4
|
return new AppError({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { join } from '../../../utils/path_utils.js';
|
|
2
2
|
import { RESOURCES_FILE_NAME } from './fetch_resources_constants.js';
|
|
3
3
|
import { SHOPER_THEME_METADATA_DIR } from '../../constants/directory_contstants.js';
|
|
4
|
-
import { fileExists, readJSONFile } from '../../../utils/fs/fs_utils.js';
|
|
4
|
+
import { fileExists, readJSONFile, removeFiles } from '../../../utils/fs/fs_utils.js';
|
|
5
5
|
export const isResourceObject = (resource) => {
|
|
6
6
|
return typeof resource === 'object' && resource !== null && 'url' in resource && typeof resource.url === 'string';
|
|
7
7
|
};
|
|
@@ -15,6 +15,9 @@ export const getResources = async (root) => {
|
|
|
15
15
|
}
|
|
16
16
|
return await readJSONFile(resourcesPath);
|
|
17
17
|
};
|
|
18
|
+
export const removeOldResources = async (rootDir, resources) => {
|
|
19
|
+
await removeFiles(Object.keys(resources).map((path) => join(rootDir, path)));
|
|
20
|
+
};
|
|
18
21
|
export const mapResourcesToTree = (resources, separator = '/') => {
|
|
19
22
|
const tree = {};
|
|
20
23
|
Object.entries(resources).forEach(([path, value]) => {
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Args } from '@oclif/core';
|
|
2
|
+
import { BaseThemeCommand } from '../../class/base_theme_command.js';
|
|
3
|
+
import { CLI_AUTH_API_NAME } from '../../../cli/auth/cli_auth_constants.js';
|
|
4
|
+
import { THEME_ACTION_NOT_FOUND_ERROR_CODE, THEME_ACTIONS_API_NAME, THEME_ACTIONS_TYPES } from '../../features/theme/actions/theme_actions_constants.js';
|
|
5
|
+
import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../../cli/features/execution_context/execution_context_constants.js';
|
|
6
|
+
import { renderOnce } from '../../../ui/ui_utils.js';
|
|
7
|
+
import { MissingCredentialsError } from '../../../cli/commands/auth/ui/missing_credentials_error.js';
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import { THEME_DELETE_API_NAME } from '../../features/theme/delete/theme_delete_constants.js';
|
|
10
|
+
import { UnpermittedCommandError } from '../ui/unpermitted_command_error.js';
|
|
11
|
+
import { Error } from '../../../ui/message_box/error.js';
|
|
12
|
+
import { Text } from '../../../ui/text.js';
|
|
13
|
+
import { Info } from '../../../ui/message_box/info.js';
|
|
14
|
+
import { MissingThemeIdError } from '../ui/missing_theme_id_error.js';
|
|
15
|
+
import { Box } from '../../../ui/box.js';
|
|
16
|
+
import { ThemeDeletedSuccessfully } from './ui/theme_deleted_successfully.js';
|
|
17
|
+
import { ThemeDeletionWarning } from './ui/theme_deletion_warning.js';
|
|
18
|
+
import { promptConfirmation } from '../../../ui/prompts/prompt_confirmation.js';
|
|
19
|
+
export class ThemeDeleteCommand extends BaseThemeCommand {
|
|
20
|
+
static summary = 'Permanently deletes the specified theme from your store.';
|
|
21
|
+
static description = 'This action cannot be undone, so make sure you really want to remove this theme.\n\nYou can run this command from a specific theme directory (ID not needed) or outside any theme directory (theme ID required).';
|
|
22
|
+
static examples = [
|
|
23
|
+
{
|
|
24
|
+
description: 'This will delete the theme with ID 123 permanently from your store. Make sure you have a backup if needed.',
|
|
25
|
+
command: '<%= config.bin %> <%= command.id %> 123'
|
|
26
|
+
}
|
|
27
|
+
];
|
|
28
|
+
static hidden = true;
|
|
29
|
+
static args = {
|
|
30
|
+
id: Args.string({
|
|
31
|
+
description: 'Theme id',
|
|
32
|
+
name: 'id',
|
|
33
|
+
required: false,
|
|
34
|
+
type: 'string'
|
|
35
|
+
})
|
|
36
|
+
};
|
|
37
|
+
async run() {
|
|
38
|
+
const data = await this.parse(ThemeDeleteCommand);
|
|
39
|
+
const { args } = data;
|
|
40
|
+
const themeId = args.id;
|
|
41
|
+
const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
|
|
42
|
+
const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
|
|
43
|
+
const credentials = cliAuthApi.getCredentials();
|
|
44
|
+
if (!credentials) {
|
|
45
|
+
renderOnce(React.createElement(MissingCredentialsError, null));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const executionContext = await executionContextApi.getExecutionContext();
|
|
49
|
+
try {
|
|
50
|
+
let _themeId = themeId;
|
|
51
|
+
if (executionContext.type !== EXECUTION_CONTEXTS.theme && !_themeId) {
|
|
52
|
+
renderOnce(React.createElement(MissingThemeIdError, null,
|
|
53
|
+
React.createElement(Box, { flexDirection: "column", gap: 1 },
|
|
54
|
+
React.createElement(Text, null, "Usage: shoper theme delete [ID]"),
|
|
55
|
+
React.createElement(Text, null, "Please run this command inside a theme directory or provide a theme ID."))));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (executionContext.type === EXECUTION_CONTEXTS.theme)
|
|
59
|
+
_themeId = _themeId ?? executionContext.themeId;
|
|
60
|
+
if (!_themeId) {
|
|
61
|
+
renderOnce(React.createElement(MissingThemeIdError, null));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const themeActionsApi = this.getApi(THEME_ACTIONS_API_NAME);
|
|
65
|
+
const deleteAction = themeActionsApi.getThemeAction({
|
|
66
|
+
actionType: THEME_ACTIONS_TYPES.delete,
|
|
67
|
+
themeId: _themeId,
|
|
68
|
+
credentials
|
|
69
|
+
});
|
|
70
|
+
if (!deleteAction) {
|
|
71
|
+
renderOnce(React.createElement(UnpermittedCommandError, { themeId: _themeId, commandName: "delete" }));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
renderOnce(React.createElement(ThemeDeletionWarning, { themeId: _themeId }));
|
|
75
|
+
const { proceed } = await promptConfirmation('Proceed?');
|
|
76
|
+
if (!proceed) {
|
|
77
|
+
renderOnce(React.createElement(Info, { header: "Theme deletion was cancelled." }));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const themeDeleteApi = this.getApi(THEME_DELETE_API_NAME);
|
|
81
|
+
const resp = await themeDeleteApi.deleteTheme({
|
|
82
|
+
actionData: deleteAction.data,
|
|
83
|
+
credentials
|
|
84
|
+
});
|
|
85
|
+
themeActionsApi.removeThemeActions({
|
|
86
|
+
themeId: _themeId,
|
|
87
|
+
credentials
|
|
88
|
+
});
|
|
89
|
+
if (!resp?.isSuccess)
|
|
90
|
+
return;
|
|
91
|
+
renderOnce(React.createElement(ThemeDeletedSuccessfully, null));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
this._handleError(err, themeId);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
_handleError(err, themeId) {
|
|
100
|
+
if (err?.code === THEME_ACTION_NOT_FOUND_ERROR_CODE && themeId) {
|
|
101
|
+
renderOnce(React.createElement(UnpermittedCommandError, { themeId: themeId, commandName: "delete" }));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (err?.message) {
|
|
105
|
+
renderOnce(React.createElement(Error, null,
|
|
106
|
+
React.createElement(Text, null, err.message)));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
this.error(String(err));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Text } from '../../../../ui/text.js';
|
|
3
|
+
import { List } from '../../../../ui/list/list.js';
|
|
4
|
+
import { Tip } from '../../../../ui/tip.js';
|
|
5
|
+
import { Success } from '../../../../ui/message_box/success.js';
|
|
6
|
+
export const ThemeDeletedSuccessfully = () => {
|
|
7
|
+
return (React.createElement(Success, { header: "Success: Theme was deleted from the store." },
|
|
8
|
+
React.createElement(Text, null, "The theme is no longer available in your store panel, but its files remain locally."),
|
|
9
|
+
React.createElement(Tip, null, "If you want to reuse this theme:"),
|
|
10
|
+
React.createElement(List, { items: [
|
|
11
|
+
'create a new theme using shoper theme init [id]',
|
|
12
|
+
'copy the local files into the new theme folder',
|
|
13
|
+
'and push it using shoper theme push'
|
|
14
|
+
] })));
|
|
15
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Warning } from '../../../../ui/message_box/warning.js';
|
|
2
|
+
import { Text } from '../../../../ui/text.js';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
export const ThemeDeletionWarning = ({ themeId }) => {
|
|
5
|
+
return (React.createElement(Warning, { header: `Warning: This will permanently delete the theme (ID: ${themeId}) from your store and cannot be undone.` },
|
|
6
|
+
React.createElement(Text, null,
|
|
7
|
+
"Your local files ",
|
|
8
|
+
React.createElement(Text, { bold: true }, "will not be removed"),
|
|
9
|
+
". You\u2019ll still be able to access and modify them.")));
|
|
10
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { BaseThemeCommand } from '../../class/base_theme_command.js';
|
|
2
|
+
import { CLI_AUTH_API_NAME } from '../../../cli/auth/cli_auth_constants.js';
|
|
3
|
+
import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../../cli/features/execution_context/execution_context_constants.js';
|
|
4
|
+
import { renderOnce } from '../../../ui/ui_utils.js';
|
|
5
|
+
import { MissingCredentialsError } from '../../../cli/commands/auth/ui/missing_credentials_error.js';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { THEMES_LIST_API_NAME } from '../../features/themes/list/themes_list_constants.js';
|
|
8
|
+
import { Args } from '@oclif/core';
|
|
9
|
+
import { ThemeMetaDataUtils } from '../../features/theme/utils/meta_data/theme_meta_data_utils.js';
|
|
10
|
+
import { MissingThemeIdError } from '../ui/missing_theme_id_error.js';
|
|
11
|
+
import { Text } from '../../../ui/text.js';
|
|
12
|
+
import { THEME_WORK_URL_MISMATCH_ERROR } from '../../features/theme/utils/meta_data/theme_meta_data_constants.js';
|
|
13
|
+
import { Error } from '../../../ui/message_box/error.js';
|
|
14
|
+
import { ThemeWorkUrlMismatch } from '../ui/theme_work_url_mismatch.js';
|
|
15
|
+
import { Table } from '../../../ui/table/table.js';
|
|
16
|
+
import { ThemeInfoCommandUtils } from './theme_info_command_utils.js';
|
|
17
|
+
import { InvalidThemeIdError } from '../ui/invalid_theme_id.js';
|
|
18
|
+
import { Box } from '../../../ui/box.js';
|
|
19
|
+
export class ThemeInfoCommand extends BaseThemeCommand {
|
|
20
|
+
static summary = 'View details about the current theme.';
|
|
21
|
+
static description = 'Displays key information about the theme you’re working on — including its ID, name, description (if provided), and status.\n\nYou can run this command from a specific theme directory (ID not needed) or outside any theme directory (theme ID required).';
|
|
22
|
+
static examples = [
|
|
23
|
+
{
|
|
24
|
+
description: 'The command will display the theme ID, name, description, and status.',
|
|
25
|
+
command: '<%= config.bin %> <%= command.id %> 2'
|
|
26
|
+
}
|
|
27
|
+
];
|
|
28
|
+
static args = {
|
|
29
|
+
id: Args.string({
|
|
30
|
+
description: 'Theme id',
|
|
31
|
+
name: 'id',
|
|
32
|
+
type: 'string'
|
|
33
|
+
})
|
|
34
|
+
};
|
|
35
|
+
async run() {
|
|
36
|
+
const data = await this.parse(ThemeInfoCommand);
|
|
37
|
+
const { args } = data;
|
|
38
|
+
const themeId = args.id;
|
|
39
|
+
const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
|
|
40
|
+
const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
|
|
41
|
+
const themesListApi = this.getApi(THEMES_LIST_API_NAME);
|
|
42
|
+
const credentials = cliAuthApi.getCredentials();
|
|
43
|
+
if (!credentials) {
|
|
44
|
+
renderOnce(React.createElement(MissingCredentialsError, null));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const executionContext = await executionContextApi.getExecutionContext();
|
|
48
|
+
try {
|
|
49
|
+
let _themeId = themeId;
|
|
50
|
+
if (executionContext.type !== EXECUTION_CONTEXTS.theme && !_themeId) {
|
|
51
|
+
renderOnce(React.createElement(MissingThemeIdError, null,
|
|
52
|
+
React.createElement(Box, { flexDirection: "column", gap: 1 },
|
|
53
|
+
React.createElement(Text, null, "Usage: shoper theme info [ID]"),
|
|
54
|
+
React.createElement(Text, null, "Please run this command inside a theme directory or provide a theme ID."))));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (executionContext.type === EXECUTION_CONTEXTS.theme) {
|
|
58
|
+
await ThemeMetaDataUtils.ensureThemeWorkUrlMatch(executionContext.themeRootDir, credentials.shopUrl);
|
|
59
|
+
_themeId = themeId ?? executionContext.themeId;
|
|
60
|
+
}
|
|
61
|
+
if (!_themeId) {
|
|
62
|
+
renderOnce(React.createElement(MissingThemeIdError, null));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const theme = await themesListApi.getTheme({
|
|
66
|
+
themeId: _themeId,
|
|
67
|
+
shopUrl: credentials.shopUrl
|
|
68
|
+
});
|
|
69
|
+
if (!theme) {
|
|
70
|
+
renderOnce(_themeId ? React.createElement(InvalidThemeIdError, { themeId: _themeId }) : React.createElement(Error, { header: "Error: Theme information is not available." }));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
this._displayThemeInfo(theme);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
this._handleError(err);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
_handleError(err) {
|
|
80
|
+
if (err?.code === THEME_WORK_URL_MISMATCH_ERROR) {
|
|
81
|
+
renderOnce(React.createElement(ThemeWorkUrlMismatch, { command: "info" }));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (err?.message) {
|
|
85
|
+
renderOnce(React.createElement(Error, null,
|
|
86
|
+
React.createElement(Text, null, err.message)));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
this.error(String(err));
|
|
90
|
+
}
|
|
91
|
+
_displayThemeInfo(theme) {
|
|
92
|
+
renderOnce(React.createElement(Table, { data: ThemeInfoCommandUtils.mapThemeMetaDataToTableData(theme) }));
|
|
93
|
+
}
|
|
94
|
+
}
|