@shoper/cli 0.5.2-1 → 0.5.2-3

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 (28) hide show
  1. package/build/cli/class/errors/http/http_errors_factory.js +1 -1
  2. package/build/cli/core/cli_setup.js +7 -6
  3. package/build/cli/index.js +0 -1
  4. package/build/theme/class/archive/theme_archive.js +44 -0
  5. package/build/theme/{features/theme/utils/archive/theme_archive_utils_errors_factory.js → class/archive/theme_archive_errors_factory.js} +1 -1
  6. package/build/theme/class/checksums/theme_checksums.js +9 -47
  7. package/build/theme/commands/pull/theme_pull_command.js +3 -4
  8. package/build/theme/commands/push/theme_push_command.js +8 -20
  9. package/build/theme/commands/theme_verify_command.js +3 -3
  10. package/build/theme/features/theme/actions/theme_actions_constants.js +1 -2
  11. package/build/theme/features/theme/actions/theme_actions_utils.js +5 -31
  12. package/build/theme/features/theme/fetch/service/theme_fetch_service.js +2 -2
  13. package/build/theme/features/theme/init/service/theme_init_service.js +2 -2
  14. package/build/theme/features/theme/merge/service/theme_merge_service.js +2 -2
  15. package/build/theme/features/theme/push/api/theme_push_api.js +2 -2
  16. package/build/theme/features/theme/push/service/theme_push_service.js +28 -80
  17. package/build/theme/features/theme/push/theme_push_utils.js +2 -2
  18. package/build/theme/features/theme/utils/files_structure/theme_file_structure_errors_factory.js +10 -0
  19. package/build/theme/features/theme/utils/{files/theme_files_utils.js → files_structure/theme_files_structure_utils.js} +23 -30
  20. package/build/theme/features/theme/verify/verify/theme_verify_service.js +11 -17
  21. package/build/utils/array_utils.js +0 -3
  22. package/build/utils/fs/fs_utils.js +1 -1
  23. package/build/utils/stream_transforms/json_indent_transform.js +7 -2
  24. package/package.json +10 -12
  25. package/build/cli/utilities/features/logger/logger_initializer.js +0 -6
  26. package/build/theme/features/theme/utils/archive/theme_archive_utils.js +0 -24
  27. package/build/theme/features/theme/utils/files/them_files_constants.js +0 -1
  28. package/build/utils/fs/fs_constants.js +0 -6
@@ -15,7 +15,7 @@ export class HttpErrorsFactory {
15
15
  }
16
16
  static createNotFoundError() {
17
17
  return new AppError({
18
- message: '404 Not found',
18
+ message: 'Not found',
19
19
  code: HTTP_NOT_FOUND_ERROR_CODE
20
20
  });
21
21
  }
@@ -26,7 +26,7 @@ export const cliSetup = async () => {
26
26
  ExecutionContextInitializer,
27
27
  CliAuthTokensInitializer,
28
28
  CliAuthInitializer,
29
- ...getInitializersBasedOnCommand()
29
+ ...getCommandBaseInitializers()
30
30
  ],
31
31
  options: {
32
32
  featuresTracking: false,
@@ -34,15 +34,16 @@ export const cliSetup = async () => {
34
34
  }
35
35
  });
36
36
  };
37
- const getInitializersBasedOnCommand = () => {
38
- if (isCommandWithTopic(process.argv[2]))
39
- return getInitializersBasedOnCommandWithTopic();
37
+ const getCommandBaseInitializers = () => {
38
+ // console.log('process.argv', process.argv);
39
+ if (isCommandsTopic(process.argv[2]))
40
+ return getCommandWithTopicBaseInitializers();
40
41
  return getCommandWithoutTopicBaseInitializers();
41
42
  };
42
- const isCommandWithTopic = (arg) => {
43
+ const isCommandsTopic = (arg) => {
43
44
  return arg === THEME_TOPIC_NAME || arg === CLI_AUTH_TOPIC_NAME;
44
45
  };
45
- const getInitializersBasedOnCommandWithTopic = () => {
46
+ const getCommandWithTopicBaseInitializers = () => {
46
47
  const topic = process.argv[2];
47
48
  const command = process.argv[3];
48
49
  switch (topic) {
@@ -6,7 +6,6 @@ export const runCLI = async () => {
6
6
  await execute({ dir: import.meta.url });
7
7
  }
8
8
  catch (error) {
9
- console.log('Error executing CLI command:', error);
10
9
  // TODO handle error
11
10
  }
12
11
  };
@@ -0,0 +1,44 @@
1
+ import globs from 'fast-glob';
2
+ import { createZip } from '../../../utils/zip/create_zip_utils.js';
3
+ import { ThemeFilesStructureUtils } from '../../features/theme/utils/files_structure/theme_files_structure_utils.js';
4
+ import { extname, join } from '../../../utils/path_utils.js';
5
+ import { formatJSONFile } from '../../../utils/fs/fs_utils.js';
6
+ import { ThemeArchiveErrorsFactory } from './theme_archive_errors_factory.js';
7
+ import { ThemeFileStructureErrorsFactory } from '../../features/theme/utils/files_structure/theme_file_structure_errors_factory.js';
8
+ import { ThemeActionsUtils } from '../../features/theme/actions/theme_actions_utils.js';
9
+ export class ThemeArchive {
10
+ #themeRootDir;
11
+ constructor(themeRootDir) {
12
+ this.#themeRootDir = themeRootDir;
13
+ }
14
+ async createFullArchive({ dist, actionValue, actionType }) {
15
+ const filesStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(this.#themeRootDir);
16
+ if (!filesStructure)
17
+ throw ThemeFileStructureErrorsFactory.createNoFilesStructureError();
18
+ try {
19
+ const filesInThemeDirectory = await globs(ThemeActionsUtils.getFilesGlobsThatMatchesActionName({
20
+ actionType,
21
+ actionValue,
22
+ filesStructure
23
+ }), {
24
+ suppressErrors: true,
25
+ onlyFiles: true,
26
+ cwd: this.#themeRootDir
27
+ });
28
+ await this._formatJsonFiles(this.#themeRootDir, filesInThemeDirectory);
29
+ return createZip({
30
+ files: filesInThemeDirectory,
31
+ baseDir: this.#themeRootDir,
32
+ dist
33
+ });
34
+ }
35
+ catch (err) {
36
+ throw ThemeArchiveErrorsFactory.createErrorWhileCreatingThemeArchive(err);
37
+ }
38
+ }
39
+ async _formatJsonFiles(themeRootDir, filesToUpload) {
40
+ await Promise.all(filesToUpload
41
+ .filter((path) => extname(path).toLowerCase() === '.json')
42
+ .map((jsonFile) => formatJSONFile(join(themeRootDir, jsonFile))));
43
+ }
44
+ }
@@ -1,4 +1,4 @@
1
- import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
1
+ import { AppError } from '../../../cli/class/errors/app/app_error.js';
2
2
  export class ThemeArchiveErrorsFactory {
3
3
  static createErrorWhileCreatingThemeArchive(error) {
4
4
  return new AppError({
@@ -10,7 +10,6 @@ import { normalize } from 'node:path';
10
10
  import { ThemePushUtils } from '../../features/theme/push/theme_push_utils.js';
11
11
  import { SHOPER_THEME_METADATA_DIR } from '../../constants/directory_contstants.js';
12
12
  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';
13
- import { FILE_STATES } from '../../../utils/fs/fs_constants.js';
14
13
  export class ThemeChecksums {
15
14
  #themeDir;
16
15
  #currentChecksumsFilePath;
@@ -32,6 +31,12 @@ export class ThemeChecksums {
32
31
  this.#initialChecksums = await this._getChecksums(this.#initialChecksumsFilePath);
33
32
  return this.#initialChecksums;
34
33
  }
34
+ getInitialChecksumsSync() {
35
+ if (this.#initialChecksums)
36
+ return this.#initialChecksums;
37
+ this.#initialChecksums = this._getChecksumsSync(this.#initialChecksumsFilePath);
38
+ return this.#initialChecksums;
39
+ }
35
40
  async getCurrentChecksums() {
36
41
  if (this.#currentChecksums)
37
42
  return this.#currentChecksums;
@@ -65,22 +70,10 @@ export class ThemeChecksums {
65
70
  const initialChecksum = await this.getInitialChecksumFromPath(path);
66
71
  return !initialChecksum && (await fileExists(join(this.#themeDir, path)));
67
72
  }
68
- async getFileState(path) {
69
- const initialChecksum = await this.getInitialChecksumFromPath(path);
73
+ async hasThemeFileBeenModified(path) {
70
74
  const currentChecksum = await this.getCurrentChecksumFromPath(path);
71
- const fileExistsInFs = await fileExists(join(this.#themeDir, path));
72
- if (!initialChecksum && fileExistsInFs) {
73
- return FILE_STATES.created;
74
- }
75
- else if (initialChecksum && !fileExistsInFs) {
76
- return FILE_STATES.deleted;
77
- }
78
- else if (initialChecksum && currentChecksum && initialChecksum !== currentChecksum) {
79
- return FILE_STATES.modified;
80
- }
81
- else {
82
- return FILE_STATES.unchanged;
83
- }
75
+ const initialChecksum = await this.getInitialChecksumFromPath(path);
76
+ return !!currentChecksum && !!initialChecksum && currentChecksum !== initialChecksum;
84
77
  }
85
78
  async verify() {
86
79
  const initialChecksumFilePath = this.#initialChecksumsFilePath;
@@ -145,37 +138,6 @@ export class ThemeChecksums {
145
138
  const directoriesChecksums = computeDirectoriesChecksums(filesChecksumsInDirectories);
146
139
  return { ...filesChecksums, ...directoriesChecksums };
147
140
  }
148
- async groupFilesByStatus(files) {
149
- const initialChecksums = await this.getInitialChecksums();
150
- const currentChecksums = await this.getCurrentChecksums();
151
- return files.reduce((acc, filePath) => {
152
- const initialChecksum = initialChecksums[toCurrentPlatformPath(filePath)];
153
- const currentChecksum = currentChecksums[toCurrentPlatformPath(filePath)];
154
- if (!initialChecksum) {
155
- acc.created.push(filePath);
156
- }
157
- else if (currentChecksum && initialChecksum !== currentChecksum) {
158
- acc.modified.push(filePath);
159
- }
160
- else if (initialChecksum && !currentChecksum) {
161
- acc.deleted.push(filePath);
162
- }
163
- else {
164
- acc.unchanged.push(filePath);
165
- }
166
- return acc;
167
- }, {
168
- created: [],
169
- modified: [],
170
- unchanged: [],
171
- deleted: []
172
- });
173
- }
174
- async getDeletedFiles() {
175
- const initialChecksums = await this.getInitialChecksums();
176
- const currentChecksums = await this.getCurrentChecksums();
177
- return Object.keys(initialChecksums).filter((filePath) => !currentChecksums[filePath]);
178
- }
179
141
  async _getInitialChecksumsVerification() {
180
142
  return await readJSONFile(this.#initialChecksumsVerificationFilePath);
181
143
  }
@@ -24,8 +24,7 @@ import { Info } from '../../../ui/message_box/info.js';
24
24
  import { directoryExists } from '../../../utils/fs/fs_utils.js';
25
25
  import { ThemeMetaDataUtils } from '../../features/theme/utils/meta_data/theme_meta_data_utils.js';
26
26
  import { ThemeChecksums } from '../../class/checksums/theme_checksums.js';
27
- import { ThemeError } from '../ui/theme_error.js';
28
- import { MODULES_DIRECTORY_NAME } from '../../features/theme/theme_constants.js'; //TODO jak jest error w pullu wowczas usuwamy docelowo pociagniety skin
27
+ import { ThemeError } from '../ui/theme_error.js'; //TODO jak jest error w pullu wowczas usuwamy docelowo pociagniety skin
29
28
  //TODO jak jest error w pullu wowczas usuwamy docelowo pociagniety skin
30
29
  export class ThemePullCommand extends BaseThemeCommand {
31
30
  static summary = 'Downloads the current version of your theme from the store and overwrites your local theme files.';
@@ -152,9 +151,9 @@ export class ThemePullCommand extends BaseThemeCommand {
152
151
  dist: tmpDir
153
152
  }
154
153
  });
155
- const localModulesPath = join(executionContext.themeRootDir, MODULES_DIRECTORY_NAME);
154
+ const localModulesPath = join(executionContext.themeRootDir, 'modules');
156
155
  const fetchedThemePath = join(tmpDir, name);
157
- const fetchedModulesPath = join(fetchedThemePath, MODULES_DIRECTORY_NAME);
156
+ const fetchedModulesPath = join(fetchedThemePath, 'modules');
158
157
  if ((await directoryExists(localModulesPath)) && (await directoryExists(fetchedModulesPath)))
159
158
  await ThemeResourcesWithIdDirectoryUtils.updateDirectoryNamesOfResourcesWithIdAccordingToLocalThemeNames(localModulesPath, fetchedModulesPath, fetchedThemePath);
160
159
  this.#spinner.stop();
@@ -4,6 +4,8 @@ import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../../cli/fea
4
4
  import { THEME_ACTIONS_API_NAME, THEME_ACTIONS_TYPES } from '../../features/theme/actions/theme_actions_constants.js';
5
5
  import { THEME_PUSH_API_NAME } from '../../features/theme/push/theme_push_constants.js';
6
6
  import { ThemeMetaDataUtils } from '../../features/theme/utils/meta_data/theme_meta_data_utils.js';
7
+ import { mapChecksumToTree } from '../../../utils/checksums/checksums_utils.js';
8
+ import { mapToPermissionsTree } from '../../utils/directory_validator/directory_validator_utils.js';
7
9
  import { renderOnce } from '../../../ui/ui_utils.js';
8
10
  import { UnpermittedCommandError } from '../ui/unpermitted_command_error.js';
9
11
  import React from 'react';
@@ -12,7 +14,7 @@ import { MissingCredentialsError } from '../../../cli/commands/auth/ui/missing_c
12
14
  import { ThemePushedSuccess } from './ui/theme_pushed_success.js';
13
15
  import ora from 'ora';
14
16
  import { ThemePushSkipInfo } from './ui/theme_push_skip_into.js';
15
- import { ThemeFilesUtils } from '../../features/theme/utils/files/theme_files_utils.js';
17
+ import { ThemeFilesStructureUtils } from '../../features/theme/utils/files_structure/theme_files_structure_utils.js';
16
18
  import { ThemeInfoUtils } from '../../features/theme/info/theme_info_utils.js';
17
19
  import { ThemeChecksums } from '../../class/checksums/theme_checksums.js';
18
20
  import { ThemeFilesUpload } from '../../class/files_upload/theme_files_upload.js';
@@ -22,10 +24,7 @@ import { MissingThemeFiles } from '../ui/missing_theme_files.js';
22
24
  import { SHOPER_THEME_METADATA_DIR } from '../../constants/directory_contstants.js';
23
25
  import { THEME_FILES_STRUCTURE_FILE_NAME } from '../../features/theme/theme_constants.js';
24
26
  import { ThemeError } from '../ui/theme_error.js';
25
- import { mapToPermissionsTree } from '../../utils/directory_validator/directory_validator_utils.js';
26
- import { mapChecksumToTree } from '../../../utils/checksums/checksums_utils.js';
27
27
  import { ThemeUnpermittedActionsError } from './ui/theme_unpermitted_actions_error.js';
28
- import { promptConfirmation } from '../../../ui/prompts/prompt_confirmation.js';
29
28
  export class ThemePushCommand extends BaseThemeCommand {
30
29
  static summary = 'Uploads your local theme files to the store and overwrites the current version of the theme in your store.';
31
30
  static description = 'Check your local changes before pushing.\n\nYou must run this command from a specific theme directory (ID not needed).';
@@ -64,7 +63,7 @@ export class ThemePushCommand extends BaseThemeCommand {
64
63
  return;
65
64
  }
66
65
  const initialChecksums = await themeChecksums.getInitialChecksums();
67
- const permissions = await ThemeFilesUtils.getFilesPermissions(executionContext.themeRootDir);
66
+ const permissions = await ThemeFilesStructureUtils.getFilesPermissions(executionContext.themeRootDir);
68
67
  const themeFilesUploadApi = new ThemeFilesUpload({
69
68
  themeRootDir: executionContext.themeRootDir,
70
69
  credentials,
@@ -76,7 +75,7 @@ export class ThemePushCommand extends BaseThemeCommand {
76
75
  renderOnce(React.createElement(ThemePushSkipInfo, null));
77
76
  return;
78
77
  }
79
- const validationResult = await ThemeFilesUtils.validateThemeDirectoryStructure({
78
+ const validationResult = await ThemeFilesStructureUtils.validateThemeDirectoryStructure({
80
79
  //TDO przeniesc do theme checksums
81
80
  checksums: mapChecksumToTree(initialChecksums),
82
81
  permissions: mapToPermissionsTree(permissions),
@@ -88,36 +87,25 @@ export class ThemePushCommand extends BaseThemeCommand {
88
87
  renderOnce(React.createElement(ThemeUnpermittedActionsError, { unpermittedActions: validationResult.unpermittedActions }));
89
88
  return;
90
89
  }
91
- const filesStructure = await ThemeFilesUtils.getThemeFilesStructure(executionContext.themeRootDir);
90
+ const filesStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(executionContext.themeRootDir);
92
91
  if (!filesStructure) {
93
92
  renderOnce(React.createElement(MissingThemeFiles, { files: `${SHOPER_THEME_METADATA_DIR}/${THEME_FILES_STRUCTURE_FILE_NAME}` }));
94
93
  return;
95
94
  }
96
95
  spinner = ora('Pushing theme...').start();
97
- const partialPushAction = themeActionsApi.getThemeAction({
98
- actionType: THEME_ACTIONS_TYPES.partialPush,
99
- themeId: executionContext.themeId,
100
- credentials
101
- });
102
- if (!pushAction) {
103
- renderOnce(React.createElement(UnpermittedCommandError, { themeId: executionContext.themeId, commandName: "push" }));
104
- return;
105
- }
106
- await themePushApi.partialPush({
96
+ await themePushApi.push({
107
97
  credentials,
108
98
  filesStructure,
109
- action: partialPushAction,
99
+ pushAction,
110
100
  themeChecksums,
111
101
  executionContext,
112
102
  themeFilesUploadApi
113
103
  });
114
104
  spinner.stop();
115
- await promptConfirmation('Continue');
116
105
  renderOnce(React.createElement(ThemePushedSuccess, { themeName: await ThemeInfoUtils.getThemeName(executionContext.themeRootDir) }));
117
106
  }
118
107
  catch (err) {
119
108
  spinner?.stop();
120
- await promptConfirmation('Continue');
121
109
  renderOnce(React.createElement(ThemeError, { err: err, executionContext: executionContext }));
122
110
  }
123
111
  }
@@ -1,6 +1,7 @@
1
1
  import { BaseThemeCommand } from '../class/base_theme_command.js';
2
2
  import { CLI_AUTH_API_NAME } from '../../cli/auth/cli_auth_constants.js';
3
3
  import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../cli/features/execution_context/execution_context_constants.js';
4
+ import { ThemeFilesStructureUtils } from '../features/theme/utils/files_structure/theme_files_structure_utils.js';
4
5
  import { ThemeChecksums } from '../class/checksums/theme_checksums.js';
5
6
  import { THEME_VERIFY_API_NAME } from '../features/theme/verify/theme_verify_constants.js';
6
7
  import { THEME_ACTIONS_API_NAME, THEME_ACTIONS_TYPES } from '../features/theme/actions/theme_actions_constants.js';
@@ -17,7 +18,6 @@ import { MissingCredentialsError } from '../../cli/commands/auth/ui/missing_cred
17
18
  import { OutsideOfThemeDirectoryContextError } from './ui/ouside_of_theme_directory_context_error.js';
18
19
  import ora from 'ora';
19
20
  import { ThemeError } from './ui/theme_error.js';
20
- import { ThemeFilesUtils } from '../features/theme/utils/files/theme_files_utils.js';
21
21
  export class ThemeVerifyCommand extends BaseThemeCommand {
22
22
  static description = 'Verify theme files structure';
23
23
  async run() {
@@ -34,7 +34,7 @@ export class ThemeVerifyCommand extends BaseThemeCommand {
34
34
  return;
35
35
  }
36
36
  const themeChecksums = new ThemeChecksums(executionContext.themeRootDir);
37
- const permissions = await ThemeFilesUtils.getFilesPermissions(executionContext.themeRootDir);
37
+ const permissions = await ThemeFilesStructureUtils.getFilesPermissions(executionContext.themeRootDir);
38
38
  if (!themeChecksums || !permissions)
39
39
  this.error('Theme checksums or permissions not found. Please ensure you are in the correct theme directory.');
40
40
  let spinner;
@@ -51,7 +51,7 @@ export class ThemeVerifyCommand extends BaseThemeCommand {
51
51
  themeId: executionContext.themeId,
52
52
  credentials
53
53
  });
54
- const filesStructure = await ThemeFilesUtils.getThemeFilesStructure(executionContext.themeRootDir);
54
+ const filesStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(executionContext.themeRootDir);
55
55
  if (!filesStructure) {
56
56
  renderOnce(React.createElement(MissingThemeFiles, { files: `${SHOPER_THEME_METADATA_DIR}/${THEME_FILES_STRUCTURE_FILE_NAME}` }));
57
57
  return;
@@ -8,8 +8,7 @@ export const THEME_ACTIONS_TYPES = {
8
8
  delete: 'delete',
9
9
  publishForm: 'publish_form',
10
10
  publish: 'publish',
11
- verify: 'verify',
12
- partialPush: 'partial_push'
11
+ verify: 'verify'
13
12
  };
14
13
  export const THEME_ACTION_DATA_TYPE = {
15
14
  file: 'file',
@@ -3,10 +3,8 @@ import { basename, looksLikeDirectory, toUnixPath } from '../../../../utils/path
3
3
  import { THEME_ACTION_DATA_TYPE } from './theme_actions_constants.js';
4
4
  import globs from 'fast-glob';
5
5
  import { THEME_PUSH_WILDCARD_GLOBS_FOR_FILES } from '../push/service/theme_push_service_constants.js';
6
- import micromatch from 'micromatch';
7
- import difference from 'lodash/difference.js';
8
6
  export class ThemeActionsUtils {
9
- static getFilesGlobsThatMatchesAction({ filesStructure, actionValue, actionType }) {
7
+ static getFilesGlobsThatMatchesActionName({ filesStructure, actionValue, actionType }) {
10
8
  return Object.entries(filesStructure).reduce((acc, [filePath, fileStructureItem]) => {
11
9
  if (fileStructureItem._links?.[actionType] && this._doesActionValueMatch(fileStructureItem._links[actionType], actionValue)) {
12
10
  return [...acc, toUnixPath(filePath)];
@@ -14,32 +12,11 @@ export class ThemeActionsUtils {
14
12
  return acc;
15
13
  }, []);
16
14
  }
17
- static async getFilesThatMatchesAction({ actionType, actionValue, filesStructure, rootDir }) {
18
- return await globs(ThemeActionsUtils.getFilesGlobsThatMatchesAction({
19
- actionType,
20
- actionValue,
21
- filesStructure
22
- }), {
23
- suppressErrors: true,
24
- onlyFiles: true,
25
- cwd: rootDir
26
- });
27
- }
28
- static async getDeletedFilesThatMatchesAction({ actionType, actionValue, themeChecksums, filesStructure }) {
29
- const deletedFiles = await themeChecksums.getDeletedFiles();
30
- const globs = ThemeActionsUtils.getFilesGlobsThatMatchesAction({
31
- actionType,
32
- actionValue,
33
- filesStructure
34
- });
35
- return deletedFiles.filter((path) => micromatch.isMatch(path, globs));
36
- }
37
- static async getFilesRecordsFromActionData({ themeRootDir, themeAction, filesStructure, themeChecksums }) {
15
+ static async getFilesRecordsFromActionData({ themeRootDir, themeAction, filesStructure }) {
38
16
  const filesRecords = [];
39
- const initialChecksums = await themeChecksums.getInitialChecksums();
40
17
  for (const [actionKey, actionData] of Object.entries(themeAction.data)) {
41
18
  if (actionData.type === THEME_ACTION_DATA_TYPE.file) {
42
- const filesGlobs = ThemeActionsUtils.getFilesGlobsThatMatchesAction({
19
+ const filesGlobs = ThemeActionsUtils.getFilesGlobsThatMatchesActionName({
43
20
  //TODO remove when backend fixed
44
21
  actionType: 'push',
45
22
  // actionType: themeAction.actionType,
@@ -47,7 +24,6 @@ export class ThemeActionsUtils {
47
24
  filesStructure
48
25
  });
49
26
  for (const fileGlob of filesGlobs) {
50
- const checksumMatchedFiles = micromatch(Object.keys(initialChecksums), [fileGlob]);
51
27
  const files = await globs(fileGlob, {
52
28
  suppressErrors: true,
53
29
  onlyFiles: true,
@@ -59,15 +35,13 @@ export class ThemeActionsUtils {
59
35
  ? fileGlob.slice(0, fileGlob.length - 2)
60
36
  : fileGlob;
61
37
  }
62
- const deletedFiles = difference(checksumMatchedFiles, files);
63
- for (const filePath of [...files, ...deletedFiles]) {
38
+ for (const filePath of files) {
64
39
  filesRecords.push({
65
40
  actionData,
66
41
  actionKey,
67
42
  path: filePath,
68
43
  fileName: basename(filePath),
69
- fileGlob: processedFileGlob,
70
- state: await themeChecksums.getFileState(filePath)
44
+ fileGlob: processedFileGlob
71
45
  });
72
46
  }
73
47
  }
@@ -8,9 +8,9 @@ import { FetchResources } from '../../../../class/fetch_resources/fetch_resource
8
8
  import { jsonIndentTransform } from '../../../../../utils/stream_transforms/json_indent_transform.js';
9
9
  import { JSON_FILE_INDENT } from '../../../../../cli/cli_constants.js';
10
10
  import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
11
+ import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
11
12
  import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
12
13
  import { ThemeMetaDataUtils } from '../../utils/meta_data/theme_meta_data_utils.js';
13
- import { ThemeFilesUtils } from '../../utils/files/theme_files_utils.js';
14
14
  export class ThemeFetchService {
15
15
  #themeHttpApi;
16
16
  #httpApi;
@@ -39,7 +39,7 @@ export class ThemeFetchService {
39
39
  await this.fetchResources(shopUrl, themeDir, resources);
40
40
  }
41
41
  try {
42
- await ThemeFilesUtils.updateFilesStructure(themeDir);
42
+ await ThemeFilesStructureUtils.updateFilesStructure(themeDir);
43
43
  }
44
44
  catch (err) {
45
45
  throw new AppError({
@@ -6,8 +6,8 @@ import { extractZip } from '../../../../../utils/zip/extract_zip_utils.js';
6
6
  import { ThemeMetaDataUtils } from '../../utils/meta_data/theme_meta_data_utils.js';
7
7
  import { ThemeInfoUtils } from '../../info/theme_info_utils.js';
8
8
  import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
9
+ import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
9
10
  import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
10
- import { ThemeFilesUtils } from '../../utils/files/theme_files_utils.js';
11
11
  export class ThemeInitService {
12
12
  #httpApi;
13
13
  constructor({ httpApi }) {
@@ -26,7 +26,7 @@ export class ThemeInitService {
26
26
  dist: themeDir
27
27
  });
28
28
  try {
29
- await ThemeFilesUtils.updateFilesStructure(themeDir);
29
+ await ThemeFilesStructureUtils.updateFilesStructure(themeDir);
30
30
  }
31
31
  catch (err) {
32
32
  throw new AppError({
@@ -2,9 +2,9 @@ import FSTree from 'fs-tree-diff';
2
2
  import { copyFileSync, getAllDirectoriesNamesInside } from '../../../../../utils/fs/fs_utils.js';
3
3
  import walkSync from 'walk-sync';
4
4
  import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
5
+ import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
5
6
  import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
6
7
  import { join, platformSeparator } from '../../../../../utils/path_utils.js';
7
- import { ThemeFilesUtils } from '../../utils/files/theme_files_utils.js';
8
8
  export class ThemeMergeService {
9
9
  async applyChanges(fromTheme, toTheme, changes) {
10
10
  FSTree.applyPatch(fromTheme, toTheme, changes, {
@@ -39,7 +39,7 @@ export class ThemeMergeService {
39
39
  });
40
40
  }
41
41
  async _getUserRootDirectories(themeDir) {
42
- const filesStructure = await ThemeFilesUtils.getThemeRootDirectories(themeDir);
42
+ const filesStructure = await ThemeFilesStructureUtils.getThemeRootDirectories(themeDir);
43
43
  return (await getAllDirectoriesNamesInside(themeDir, {
44
44
  recursive: false,
45
45
  hidden: true
@@ -7,7 +7,7 @@ export class ThemePushApi extends FeatureApi {
7
7
  super();
8
8
  this.#service = service;
9
9
  }
10
- async partialPush(props) {
11
- return this.#service.partialPush(props);
10
+ async push(props) {
11
+ return this.#service.push(props);
12
12
  }
13
13
  }
@@ -1,27 +1,25 @@
1
1
  import tmp from 'tmp-promise';
2
2
  import { THEME_ACTIONS_TYPES } from '../../actions/theme_actions_constants.js';
3
- import { dirname, join } from '../../../../../utils/path_utils.js';
3
+ import { join } from '../../../../../utils/path_utils.js';
4
4
  import { v4 as uuid } from 'uuid';
5
5
  import { THEME_WILDCARD_ACTION_NAME } from '../../actions/service/theme_actions_service_constants.js';
6
- import { THEME_FILES_LIST_FILE_NAME, THEME_MODULE_SETTINGS_FILE_NAME } from '../theme_push_constants.js';
6
+ import { THEME_MODULE_SETTINGS_FILE_NAME } from '../theme_push_constants.js';
7
7
  import { ThemePushErrorsFactory } from '../theme_push_errors_factory.js';
8
8
  import { ThemeImagesUtils } from '../../utils/theme_images_utils.js';
9
9
  import { ThemePublishUtils } from '../../skinstore/theme_publish_utils.js';
10
- import { fileExists, getAllDirectoriesNamesInside, readJSONFile, writeJSONFile } from '../../../../../utils/fs/fs_utils.js';
10
+ import { removeFile, writeJSONFile } from '../../../../../utils/fs/fs_utils.js';
11
11
  import { MODULES_DIRECTORY_NAME } from '../../theme_constants.js';
12
12
  import { removeOldResources } from '../../../../class/fetch_resources/fetch_resources_utils.js';
13
- import { ThemeFilesUtils } from '../../utils/files/theme_files_utils.js';
13
+ import { ThemeArchive } from '../../../../class/archive/theme_archive.js';
14
+ import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
14
15
  import { ThemeActionsUtils } from '../../actions/theme_actions_utils.js';
15
- import { ThemeArchiveUtils } from '../../utils/archive/theme_archive_utils.js';
16
- import { FILE_STATES } from '../../../../../utils/fs/fs_constants.js';
17
- import uniq from 'lodash/uniq.js';
18
- import { FILES_LIST_CUSTOM_MODULES_TO_KEEP_IDS } from '../../utils/files/them_files_constants.js';
16
+ import { ArrayUtils } from '@dreamcommerce/utilities';
19
17
  export class ThemePushService {
20
18
  #themeFetchApi;
21
19
  constructor({ themeFetchApi }) {
22
20
  this.#themeFetchApi = themeFetchApi;
23
21
  }
24
- async partialPush({ action, filesStructure, executionContext, themeChecksums, themeFilesUploadApi, credentials }) {
22
+ async push({ pushAction, credentials, filesStructure, executionContext, themeChecksums, themeFilesUploadApi }) {
25
23
  const { path: tmpDir } = await tmp.dir({ unsafeCleanup: true });
26
24
  const themeRootDir = executionContext.themeRootDir;
27
25
  if (await themeChecksums.hasThemeFileBeenCreated(ThemePublishUtils.getSkinStoreSettingsFilePath(themeRootDir)))
@@ -30,54 +28,30 @@ export class ThemePushService {
30
28
  //TODO to do api?
31
29
  const filesRecords = await ThemeActionsUtils.getFilesRecordsFromActionData({
32
30
  themeRootDir,
33
- themeAction: action,
34
- filesStructure,
35
- themeChecksums
31
+ themeAction: pushAction,
32
+ filesStructure
36
33
  });
37
- const filesToUpload = filesRecords.filter(({ state }) => [FILE_STATES.modified, FILE_STATES.created].includes(state));
38
- let localFileNameToUploaded;
34
+ const filesToUpload = await ArrayUtils.asyncFilter(filesRecords, async ({ path }) => (await themeChecksums.hasThemeFileBeenCreated(path)) || (await themeChecksums.hasThemeFileBeenModified(path)));
39
35
  if (filesToUpload.length) {
40
- const uploadData = await this._uploadThemeFiles({
36
+ const { localFileNameToUploaded } = await this._uploadThemeFiles({
41
37
  filesToUpload,
42
38
  credentials,
43
39
  themeRootDir,
44
40
  themeFilesUploadApi
45
41
  });
46
- localFileNameToUploaded = uploadData.localFileNameToUploaded;
42
+ await this._createFilesList(themeRootDir, filesRecords, localFileNameToUploaded);
43
+ }
44
+ else {
45
+ await this._createFilesList(themeRootDir, filesRecords);
47
46
  }
48
47
  const themeArchivePath = join(tmpDir, `${uuid()}.zip`);
49
- const filesInArchive = await ThemeActionsUtils.getFilesThatMatchesAction({
50
- actionValue: THEME_WILDCARD_ACTION_NAME,
51
- actionType: THEME_ACTIONS_TYPES.push,
52
- filesStructure,
53
- rootDir: themeRootDir
54
- });
55
- const groupedFiles = await themeChecksums.groupFilesByStatus(filesInArchive);
56
- const deletedFiles = await ThemeActionsUtils.getDeletedFilesThatMatchesAction({
57
- actionType: THEME_ACTIONS_TYPES.push,
58
- actionValue: THEME_WILDCARD_ACTION_NAME,
59
- themeChecksums,
60
- filesStructure
61
- });
62
- await this._createFilesList({
63
- themeRootDir,
64
- filesRecords,
65
- localFileNameToUploaded,
66
- deletedFiles,
67
- allCustomModulesIds: await this._getAllModulesIds(themeRootDir)
68
- });
69
- await ThemeArchiveUtils.create({
48
+ await new ThemeArchive(themeRootDir).createFullArchive({
70
49
  dist: themeArchivePath,
71
- rootDir: themeRootDir,
72
- files: [
73
- ...(await this._appendSettingsIfModifiedFileFromFolderThatContainsOne(groupedFiles.modified)),
74
- ...groupedFiles.created,
75
- (await fileExists(ThemeFilesUtils.getFilesListFilePath(themeRootDir))) ? THEME_FILES_LIST_FILE_NAME : undefined
76
- ].filter(Boolean)
50
+ actionValue: THEME_WILDCARD_ACTION_NAME,
51
+ actionType: THEME_ACTIONS_TYPES.push
77
52
  });
78
- await ThemeFilesUtils.removeAFilesListFile(themeRootDir);
79
53
  const { resources, modules } = await themeFilesUploadApi.uploadArchive({
80
- action,
54
+ action: pushAction,
81
55
  themeArchivePath,
82
56
  credentials
83
57
  });
@@ -87,20 +61,18 @@ export class ThemePushService {
87
61
  await removeOldResources(themeRootDir, resources);
88
62
  await this.#themeFetchApi.fetchResources(credentials.shopUrl, themeRootDir, resources);
89
63
  }
90
- //TODO only changed files checksum
91
64
  await themeChecksums.updateAllChecksums();
92
65
  }
93
- catch (err) {
94
- console.log('err', err);
95
- await ThemeFilesUtils.removeAFilesListFile(themeRootDir);
96
- throw err;
66
+ finally {
67
+ await ThemeFilesStructureUtils.removeAFilesListFile(themeRootDir);
97
68
  }
98
69
  }
99
70
  async _uploadThemeFiles({ filesToUpload, themeRootDir, credentials, themeFilesUploadApi }) {
100
71
  try {
101
- const { uploadedImageData } = await themeFilesUploadApi.uploadFiles(filesToUpload);
72
+ const { uploadedImageData, rejectedImageData } = await themeFilesUploadApi.uploadFiles(filesToUpload);
102
73
  if (uploadedImageData.length)
103
74
  await ThemeImagesUtils.removeUploadedOriginalFiles(themeRootDir, uploadedImageData);
75
+ // if (rejectedImageData.length) await this._removeUploadedThemeFiles(rejectedImageData, themeRootDir);
104
76
  return {
105
77
  localFileNameToUploaded: uploadedImageData.reduce((acc, { originalFilename, uploadedFilename }) => {
106
78
  return {
@@ -114,39 +86,15 @@ export class ThemePushService {
114
86
  throw ThemePushErrorsFactory.createErrorWhileUploadingThemeFiles(credentials.shopUrl, err);
115
87
  }
116
88
  }
89
+ async _removeUploadedThemeFiles(uploadedImageData, themeRootDir) {
90
+ await Promise.all(uploadedImageData.map(({ location, originalFilename }) => removeFile(join(themeRootDir, location, originalFilename))));
91
+ }
117
92
  async _updateDataForNewCreatedModules({ modules, themeRootDir }) {
118
93
  for (const [moduleDirectoryName, metaData] of Object.entries(modules)) {
119
94
  await writeJSONFile(join(themeRootDir, MODULES_DIRECTORY_NAME, moduleDirectoryName, THEME_MODULE_SETTINGS_FILE_NAME), JSON.parse(metaData[THEME_MODULE_SETTINGS_FILE_NAME]));
120
95
  }
121
96
  }
122
- async _createFilesList({ deletedFiles, localFileNameToUploaded, filesRecords, themeRootDir, allCustomModulesIds }) {
123
- const filesListContent = ThemeFilesUtils.mapFilesRecordsToFilesList(filesRecords, localFileNameToUploaded);
124
- if (deletedFiles?.length)
125
- filesListContent.removed = deletedFiles;
126
- if (allCustomModulesIds?.length)
127
- filesListContent[FILES_LIST_CUSTOM_MODULES_TO_KEEP_IDS] = allCustomModulesIds;
128
- await ThemeFilesUtils.createAFilesListFile(themeRootDir, filesListContent);
129
- }
130
- async _appendSettingsIfModifiedFileFromFolderThatContainsOne(modifiedFiles) {
131
- const withSettingsFiles = [...modifiedFiles];
132
- for (const filePath of modifiedFiles) {
133
- if (await fileExists(join(dirname(filePath), 'settings.json'))) {
134
- withSettingsFiles.push(join(dirname(filePath), 'settings.json'));
135
- }
136
- }
137
- return uniq(withSettingsFiles);
138
- }
139
- async _getAllModulesIds(themeRootDir) {
140
- const moduleDirs = await getAllDirectoriesNamesInside(join(themeRootDir, MODULES_DIRECTORY_NAME));
141
- const modulesIds = [];
142
- for (const moduleDir of moduleDirs) {
143
- const moduleSettingsPath = join(themeRootDir, MODULES_DIRECTORY_NAME, moduleDir, THEME_MODULE_SETTINGS_FILE_NAME);
144
- if (await fileExists(moduleSettingsPath)) {
145
- const settingsContent = await readJSONFile(moduleSettingsPath);
146
- if (settingsContent.id && Number.isInteger(settingsContent.id))
147
- modulesIds.push(settingsContent.id);
148
- }
149
- }
150
- return modulesIds;
97
+ async _createFilesList(themeRootDir, filesRecords, localFileNameToUploaded = {}) {
98
+ await ThemeFilesStructureUtils.createAFilesListFile(themeRootDir, ThemeFilesStructureUtils.mapFilesRecordsToFilesList(filesRecords, localFileNameToUploaded));
151
99
  }
152
100
  }
@@ -1,10 +1,10 @@
1
1
  import globs from 'fast-glob';
2
2
  import { AppError } from '../../../../cli/class/errors/app/app_error.js';
3
3
  import { toUnixPath } from '../../../../utils/path_utils.js';
4
- import { ThemeFilesUtils } from '../utils/files/theme_files_utils.js';
4
+ import { ThemeFilesStructureUtils } from '../utils/files_structure/theme_files_structure_utils.js';
5
5
  export class ThemePushUtils {
6
6
  static async getAllFilesThatAreSendToRemote(themeDir) {
7
- const filesStructure = await ThemeFilesUtils.getThemeFilesStructure(themeDir);
7
+ const filesStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(themeDir);
8
8
  if (!filesStructure)
9
9
  throw new AppError({
10
10
  message: `Files structure not found in theme directory: ${themeDir}`,
@@ -0,0 +1,10 @@
1
+ import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
2
+ export class ThemeFileStructureErrorsFactory {
3
+ static createNoFilesStructureError() {
4
+ return new AppError({
5
+ code: 'theme.file_structure.no_files_structure',
6
+ message: 'No files structure found for the theme.',
7
+ level: 'error'
8
+ });
9
+ }
10
+ }
@@ -1,4 +1,4 @@
1
- import { fileExists, isDirectory, readJSONFile, removeFile, writeJSONFile } from '../../../../../utils/fs/fs_utils.js';
1
+ import { readJSONFile, removeFile, writeJSONFile } from '../../../../../utils/fs/fs_utils.js';
2
2
  import { join, looksLikeDirectory, mapKeysPathsToWindowPlatform, toUnixPath } from '../../../../../utils/path_utils.js';
3
3
  import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
4
4
  import { THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_FILES_STRUCTURE_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME } from '../../theme_constants.js';
@@ -7,8 +7,7 @@ import { validateDirectory } from '../../../../utils/directory_validator/directo
7
7
  import path from 'node:path';
8
8
  import { THEME_FILES_LIST_FILE_NAME } from '../../push/theme_push_constants.js';
9
9
  import { THEME_ACTIONS_TYPES } from '../../actions/theme_actions_constants.js';
10
- import { FILE_STATES } from '../../../../../utils/fs/fs_constants.js';
11
- export class ThemeFilesUtils {
10
+ export class ThemeFilesStructureUtils {
12
11
  static async getThemeFilesStructure(themeDirectory) {
13
12
  const filesStructure = await readJSONFile(join(themeDirectory, SHOPER_THEME_METADATA_DIR, THEME_FILES_STRUCTURE_FILE_NAME));
14
13
  if (!isWindowsOs())
@@ -20,7 +19,7 @@ export class ThemeFilesUtils {
20
19
  await writeJSONFile(filePath, filesStructure);
21
20
  }
22
21
  static async getFilesPermissions(themeDirectory) {
23
- const fileStructure = await ThemeFilesUtils.getThemeFilesStructure(themeDirectory);
22
+ const fileStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(themeDirectory);
24
23
  return Object.entries(fileStructure).reduce((acc, [key, value]) => {
25
24
  return {
26
25
  ...acc,
@@ -36,24 +35,14 @@ export class ThemeFilesUtils {
36
35
  });
37
36
  }
38
37
  static async getThemeRootDirectories(themeDirectory) {
39
- const filesStructure = await ThemeFilesUtils.getThemeFilesStructure(themeDirectory);
38
+ const filesStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(themeDirectory);
40
39
  return Object.keys(filesStructure).filter((path) => {
41
40
  return looksLikeDirectory(path);
42
41
  });
43
42
  }
44
43
  static mapFilesRecordsToFilesList(filesRecords, localFileNameToUploaded = {}) {
45
- return filesRecords.reduce((acc, { fileGlob, fileName, state, actionKey }) => {
44
+ const mappedFilesRecords = filesRecords.reduce((acc, { fileGlob, fileName }) => {
46
45
  const name = localFileNameToUploaded[fileName] ?? fileName;
47
- if (state === FILE_STATES.deleted && actionKey === 'thumbnail') {
48
- return {
49
- ...acc,
50
- [fileGlob]: null
51
- };
52
- }
53
- if (state === FILE_STATES.deleted)
54
- return acc;
55
- if (state === FILE_STATES.unchanged)
56
- return acc;
57
46
  if (looksLikeDirectory(fileGlob)) {
58
47
  const existingFiles = acc[fileGlob] || [];
59
48
  return {
@@ -68,28 +57,32 @@ export class ThemeFilesUtils {
68
57
  };
69
58
  }
70
59
  }, {});
60
+ /*
61
+ * Brzydki fix, poprawione w partial push na ładniej
62
+ */
63
+ if (!mappedFilesRecords['settings/thumbnail.jpg']) {
64
+ mappedFilesRecords['settings/thumbnail.jpg'] = null;
65
+ }
66
+ return mappedFilesRecords;
71
67
  }
72
68
  static async createAFilesListFile(themeRootDir, filesList) {
73
69
  if (!filesList || !Object.keys(filesList).length)
74
70
  return;
75
- const toUnixStyleFilesList = {};
76
- for (const [filePath, value] of Object.entries(filesList)) {
71
+ const toUnixStyleFilesList = Object.entries(filesList).reduce((acc, [filePath, value]) => {
77
72
  const unixPath = toUnixPath(filePath);
78
- const finalPath = (await fileExists(join(themeRootDir, filePath))) && (await isDirectory(join(themeRootDir, filePath)))
79
- ? `${unixPath}${path.posix.sep}`
80
- : unixPath;
81
- toUnixStyleFilesList[finalPath] = value;
82
- }
83
- await writeJSONFile(this.getFilesListFilePath(themeRootDir), toUnixStyleFilesList);
84
- }
85
- static getFilesListFilePath(themeRootDir) {
86
- return join(themeRootDir, THEME_FILES_LIST_FILE_NAME);
73
+ const finalPath = looksLikeDirectory(unixPath) ? `${unixPath}${path.posix.sep}` : unixPath;
74
+ return {
75
+ ...acc,
76
+ [finalPath]: value
77
+ };
78
+ }, {});
79
+ await writeJSONFile(join(themeRootDir, THEME_FILES_LIST_FILE_NAME), toUnixStyleFilesList);
87
80
  }
88
81
  static async removeAFilesListFile(themeRootDir) {
89
- await removeFile(this.getFilesListFilePath(themeRootDir));
82
+ await removeFile(join(themeRootDir, THEME_FILES_LIST_FILE_NAME));
90
83
  }
91
84
  static async updateFilesStructure(themeDir) {
92
- const fileStructure = await ThemeFilesUtils.getThemeFilesStructure(themeDir);
85
+ const fileStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(themeDir);
93
86
  const checksumsFiles = [
94
87
  `${SHOPER_THEME_METADATA_DIR}/${THEME_INITIAL_CHECKSUMS_FILE_NAME}`,
95
88
  `${SHOPER_THEME_METADATA_DIR}/${THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME}`,
@@ -122,6 +115,6 @@ export class ThemeFilesUtils {
122
115
  }
123
116
  };
124
117
  });
125
- await ThemeFilesUtils.writeThemeFilesStructure(themeDir, fileStructure);
118
+ await ThemeFilesStructureUtils.writeThemeFilesStructure(themeDir, fileStructure);
126
119
  }
127
120
  }
@@ -3,12 +3,12 @@ import { ThemePublishUtils } from '../../skinstore/theme_publish_utils.js';
3
3
  import { ThemePushErrorsFactory } from '../../push/theme_push_errors_factory.js';
4
4
  import { join } from '../../../../../utils/path_utils.js';
5
5
  import { v4 as uuid } from 'uuid';
6
- import { ThemeArchiveUtils } from '../../utils/archive/theme_archive_utils.js';
7
- import { ThemeActionsUtils } from '../../actions/theme_actions_utils.js';
8
- import { ThemeFilesUtils } from '../../utils/files/theme_files_utils.js';
6
+ import { ThemeArchive } from '../../../../class/archive/theme_archive.js';
9
7
  import { THEME_WILDCARD_ACTION_NAME } from '../../actions/service/theme_actions_service_constants.js';
10
8
  import { THEME_ACTIONS_TYPES } from '../../actions/theme_actions_constants.js';
11
- import { FILE_STATES } from '../../../../../utils/fs/fs_constants.js';
9
+ import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
10
+ import { ThemeActionsUtils } from '../../actions/theme_actions_utils.js';
11
+ import { ArrayUtils } from '@dreamcommerce/utilities';
12
12
  export class ThemeVerifyService {
13
13
  async verifyTheme({ verifyAction, executionContext, credentials, themeChecksums, filesStructure, themeFilesUploadApi }) {
14
14
  const { path: tmpDir } = await tmp.dir({ unsafeCleanup: true });
@@ -20,10 +20,9 @@ export class ThemeVerifyService {
20
20
  const filesRecords = await ThemeActionsUtils.getFilesRecordsFromActionData({
21
21
  themeRootDir,
22
22
  themeAction: verifyAction,
23
- filesStructure,
24
- themeChecksums
23
+ filesStructure
25
24
  });
26
- const filesToVerify = filesRecords.filter(({ state }) => [FILE_STATES.modified, FILE_STATES.created].includes(state));
25
+ const filesToVerify = await ArrayUtils.asyncFilter(filesRecords, async ({ path }) => (await themeChecksums.hasThemeFileBeenModified(path)) || !(await themeChecksums.hasThemeFileBeenCreated(path)));
27
26
  if (filesToVerify.length) {
28
27
  const { rejectedImageData } = await themeFilesUploadApi.uploadFiles(filesToVerify);
29
28
  if (rejectedImageData.length)
@@ -34,15 +33,10 @@ export class ThemeVerifyService {
34
33
  }
35
34
  await this._createFilesList(themeRootDir, filesToVerify);
36
35
  const themeArchivePath = join(tmpDir, `${uuid()}.zip`);
37
- await ThemeArchiveUtils.create({
36
+ await new ThemeArchive(themeRootDir).createFullArchive({
38
37
  dist: themeArchivePath,
39
- rootDir: themeRootDir,
40
- files: await ThemeActionsUtils.getFilesThatMatchesAction({
41
- actionValue: THEME_WILDCARD_ACTION_NAME,
42
- actionType: THEME_ACTIONS_TYPES.push,
43
- filesStructure,
44
- rootDir: themeRootDir
45
- })
38
+ actionValue: THEME_WILDCARD_ACTION_NAME,
39
+ actionType: THEME_ACTIONS_TYPES.push
46
40
  });
47
41
  const { isSuccess, messages } = await themeFilesUploadApi.uploadArchive({
48
42
  action: verifyAction,
@@ -52,10 +46,10 @@ export class ThemeVerifyService {
52
46
  return { isSuccess, messages };
53
47
  }
54
48
  finally {
55
- await ThemeFilesUtils.removeAFilesListFile(themeRootDir);
49
+ await ThemeFilesStructureUtils.removeAFilesListFile(themeRootDir);
56
50
  }
57
51
  }
58
52
  async _createFilesList(themeRootDir, filesRecords) {
59
- await ThemeFilesUtils.createAFilesListFile(themeRootDir, ThemeFilesUtils.mapFilesRecordsToFilesList(filesRecords));
53
+ await ThemeFilesStructureUtils.createAFilesListFile(themeRootDir, ThemeFilesStructureUtils.mapFilesRecordsToFilesList(filesRecords));
60
54
  }
61
55
  }
@@ -4,6 +4,3 @@ export const asyncFilter = async (array, callback) => {
4
4
  return array.filter((_v, index) => results[index]);
5
5
  });
6
6
  };
7
- export const asyncMap = async (array, callback) => {
8
- return Promise.all(array.map(callback));
9
- };
@@ -100,7 +100,7 @@ export const getAllFilesAndDirectoriesInside = async (path, options) => {
100
100
  withFileTypes
101
101
  });
102
102
  };
103
- export const getAllDirectoriesNamesInside = async (path, options = { recursive: false, hidden: false }) => {
103
+ export const getAllDirectoriesNamesInside = async (path, options) => {
104
104
  const { recursive = true, hidden = true } = options;
105
105
  const files = await fsPromises.readdir(path, {
106
106
  recursive,
@@ -12,9 +12,14 @@ export const jsonIndentTransform = (space = JSON_FILE_INDENT) => {
12
12
  if (!data) {
13
13
  return callback();
14
14
  }
15
- const json = JSON.parse(data);
15
+ // 1. Escape backslashes to preserve literal '\u' during parsing
16
+ const escapedJsonString = data.replace(/\\u/g, '\\\\u');
17
+ const json = JSON.parse(escapedJsonString);
18
+ // 2. Stringify the object, which will re-escape the backslashes (e.g., '\\u' -> '\\\\u')
16
19
  const pretty = JSON.stringify(json, null, space);
17
- this.push(pretty);
20
+ // 3. Un-escape the double backslashes to get the desired literal '\u'
21
+ const finalString = pretty.replace(/\\\\u/g, '\\u');
22
+ this.push(finalString);
18
23
  callback();
19
24
  }
20
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.5.2-1",
5
+ "version": "0.5.2-3",
6
6
  "description": "CLI tool for Shoper",
7
7
  "author": "Joanna Firek",
8
8
  "license": "MIT",
@@ -39,32 +39,31 @@
39
39
  "@oclif/plugin-help": "6.2.27",
40
40
  "@oclif/plugin-version": "2.2.27",
41
41
  "@oclif/plugin-warn-if-update-available": "3.1.38",
42
- "axios": "1.12.0",
42
+ "axios": "1.8.4",
43
43
  "chalk": "5.4.1",
44
44
  "conf": "13.1.0",
45
45
  "fast-glob": "3.3.3",
46
+ "figures": "6.1.0",
47
+ "fs-extra": "11.3.0",
46
48
  "fs-tree-diff": "2.0.1",
47
49
  "ink": "6.0.1",
50
+ "ink-link": "4.1.0",
48
51
  "inquirer": "12.5.2",
52
+ "inquirer-select-line": "1.1.3",
49
53
  "is-hidden-file": "1.1.2",
50
54
  "jsonwebtoken": "9.0.2",
51
55
  "klaw": "4.1.0",
52
56
  "lodash": "4.17.21",
57
+ "log-symbols": "7.0.1",
53
58
  "memfs": "4.17.0",
54
59
  "ora": "8.2.0",
55
60
  "react": "19.1.0",
56
61
  "reflect-metadata": "0.2.2",
57
62
  "rxjs": "7.8.2",
58
63
  "semver": "7.7.1",
64
+ "strip-ansi": "7.1.0",
59
65
  "tmp-promise": "3.0.3",
60
66
  "uuid": "11.1.0",
61
- "fs-extra": "11.3.0",
62
- "ink-link": "4.1.0",
63
- "log-symbols": "7.0.1",
64
- "figures": "6.1.0",
65
- "strip-ansi": "7.1.0",
66
- "inquirer-select-line": "1.1.3",
67
- "micromatch": "4.0.8",
68
67
  "walk-sync": "3.0.0",
69
68
  "yauzl": "3.2.0",
70
69
  "yazl": "3.3.1"
@@ -78,15 +77,14 @@
78
77
  "@types/fs-extra": "11.0.4",
79
78
  "@types/jest": "29.5.14",
80
79
  "@types/jsonwebtoken": "9.0.9",
80
+ "@types/klaw": "3.0.7",
81
+ "@types/lodash": "4.17.17",
81
82
  "@types/node": "18.19.84",
82
83
  "@types/react": "19.1.8",
83
84
  "@types/semver": "7.7.0",
84
85
  "@types/tmp": "0.2.6",
85
86
  "@types/yauzl": "2.10.3",
86
87
  "@types/yazl": "2.4.6",
87
- "@types/klaw": "3.0.7",
88
- "@types/lodash": "4.17.17",
89
- "@types/micromatch": "4.0.9",
90
88
  "@typescript-eslint/eslint-plugin": "8.29.1",
91
89
  "babel-jest": "29.7.0",
92
90
  "eslint": "9.24.0",
@@ -1,6 +0,0 @@
1
- // export class LoggerInitializer extends SyncFeatureInitializer {
2
- // public initialize(): void {
3
- // // this.feature.logger = new LoggerFeature(this.app);
4
- // }
5
- // }
6
- export {};
@@ -1,24 +0,0 @@
1
- import { createZip } from '../../../../../utils/zip/create_zip_utils.js';
2
- import { extname, join } from '../../../../../utils/path_utils.js';
3
- import { formatJSONFile } from '../../../../../utils/fs/fs_utils.js';
4
- import { ThemeArchiveErrorsFactory } from './theme_archive_utils_errors_factory.js';
5
- export class ThemeArchiveUtils {
6
- static async create({ dist, files, rootDir }) {
7
- try {
8
- await this._formatJsonFiles(rootDir, files);
9
- return createZip({
10
- files,
11
- baseDir: rootDir,
12
- dist
13
- });
14
- }
15
- catch (err) {
16
- throw ThemeArchiveErrorsFactory.createErrorWhileCreatingThemeArchive(err);
17
- }
18
- }
19
- static async _formatJsonFiles(themeRootDir, filesToUpload) {
20
- await Promise.all(filesToUpload
21
- .filter((path) => extname(path).toLowerCase() === '.json')
22
- .map((jsonFile) => formatJSONFile(join(themeRootDir, jsonFile))));
23
- }
24
- }
@@ -1 +0,0 @@
1
- export const FILES_LIST_CUSTOM_MODULES_TO_KEEP_IDS = 'customModulesIdsToKeep';
@@ -1,6 +0,0 @@
1
- export const FILE_STATES = {
2
- created: 'created',
3
- modified: 'modified',
4
- deleted: 'deleted',
5
- unchanged: 'unchanged'
6
- };