@shoper/cli 0.1.0-31 → 0.1.0-33

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 (26) hide show
  1. package/build/cli/auth/tokens/cli_auth_tokens_initalizer.js +1 -1
  2. package/build/cli/features/controls/controls_dto_to_ui_mappers.js +39 -0
  3. package/build/cli/features/controls/ui/controls_mappers.js +44 -0
  4. package/build/cli/features/controls/validators/greater_eq_than_validator.js +5 -0
  5. package/build/cli/features/controls/validators/length_validator.js +6 -0
  6. package/build/cli/features/controls/validators/required_validator.js +5 -0
  7. package/build/cli/features/controls/validators/validator_constants.js +13 -0
  8. package/build/cli/features/http_requester/http_requester_initializer.js +1 -1
  9. package/build/theme/class/fetch_resources/fetch_resources.js +1 -0
  10. package/build/theme/class/fetch_resources/fetch_resources_utils.js +4 -1
  11. package/build/theme/features/theme/actions/theme_actions_initializer.js +1 -1
  12. package/build/theme/features/theme/actions/theme_actions_utils.js +18 -8
  13. package/build/theme/features/theme/fetch/service/theme_fetch_service.js +3 -2
  14. package/build/theme/features/theme/push/service/theme_push_service.js +15 -4
  15. package/build/theme/features/theme/skinstore/api/theme_skinstore_api.js +1 -1
  16. package/build/theme/features/theme/skinstore/http/theme_skinstore_http_api.js +11 -1
  17. package/build/theme/features/theme/skinstore/service/theme_skinstore_service.js +29 -1
  18. package/build/theme/features/theme/utils/theme_images_utils.js +1 -1
  19. package/build/theme/hooks/themes_actions/ensure_themes_actions_hook_constants.js +1 -0
  20. package/package.json +1 -1
  21. package/build/ui/form/controls_mappers.js +0 -39
  22. /package/build/cli/{features → class}/caches/cache_factory.js +0 -0
  23. /package/build/cli/{features → class}/caches/json_cache/json_cache.js +0 -0
  24. /package/build/cli/{features → class}/caches/memory_cache.js +0 -0
  25. /package/build/{ui/form → cli/features/controls/ui}/form.js +0 -0
  26. /package/build/{ui/form → cli/features/controls/ui}/form_constants.js +0 -0
@@ -3,7 +3,7 @@ import { CliAuthTokensApi } from './api/cli_auth_tokens_api.js';
3
3
  import { CLiAuthTokensService } from './service/cli_auth_tokens_service.js';
4
4
  import { CLI_AUTH_TOKENS_FEATURE_NAME, CLI_AUTH_TOKENS_FILE_NAME } from './cli_auth_tokens_constants.js';
5
5
  import { CLI_DATA_DIRECTORY_API_NAME } from '../../features/data_directory/cli_data_directory_constants.js';
6
- import { JsonCache } from '../../features/caches/json_cache/json_cache.js';
6
+ import { JsonCache } from '../../class/caches/json_cache/json_cache.js';
7
7
  // schema
8
8
  // {
9
9
  // default: string;
@@ -0,0 +1,39 @@
1
+ import { CONTROLS_TYPES } from './ui/form_constants.js';
2
+ export const toTextControl = ({ validators, label, isRequired, defaultValue, name }) => {
3
+ return {
4
+ type: CONTROLS_TYPES.text,
5
+ name,
6
+ label,
7
+ isRequired,
8
+ defaultValue,
9
+ validators
10
+ };
11
+ };
12
+ export const toNumberControl = ({ validators, label, isRequired, name }) => {
13
+ return {
14
+ type: 'number',
15
+ name,
16
+ label,
17
+ isRequired,
18
+ validators
19
+ };
20
+ };
21
+ export const toSelectControl = ({ label, isRequired, name, options }) => {
22
+ return {
23
+ type: 'list',
24
+ name,
25
+ label,
26
+ isRequired,
27
+ options: options.selectOptions.map(({ label, key }) => ({ label, value: key }))
28
+ };
29
+ };
30
+ export const toMultiSelectControl = ({ label, isRequired, name, options }) => {
31
+ //TODO multiple checkboxes
32
+ return {
33
+ type: 'checkbox',
34
+ name,
35
+ label,
36
+ isRequired,
37
+ options: options.selectOptions.map(({ label, key }) => ({ label, value: key }))
38
+ };
39
+ };
@@ -0,0 +1,44 @@
1
+ export const toTextControl = ({ validators, label, isRequired, defaultValue, name }) => {
2
+ return {
3
+ type: 'input',
4
+ name,
5
+ message: isRequired ? `${label} (required)` : label,
6
+ default: defaultValue,
7
+ validate: toInquirerValidate(validators)
8
+ };
9
+ };
10
+ export const toNumberControl = ({ validators, label, isRequired, defaultValue, name }) => {
11
+ return {
12
+ type: 'number',
13
+ name,
14
+ message: isRequired ? `${label} (required)` : label,
15
+ default: defaultValue,
16
+ validate: toInquirerValidate(validators)
17
+ };
18
+ };
19
+ export const toSelectControl = ({ validators, label, isRequired, defaultValue, name, options }) => {
20
+ return {
21
+ type: 'list',
22
+ name,
23
+ message: isRequired ? `${label} (required)` : label,
24
+ choices: options,
25
+ default: defaultValue,
26
+ validate: toInquirerValidate(validators)
27
+ };
28
+ };
29
+ export const toMultiSelectControl = ({ validators, label, isRequired, defaultValue, name, options }) => {
30
+ //TODO multiple checkboxes
31
+ return {
32
+ type: 'checkbox',
33
+ name,
34
+ message: isRequired ? `${label} (required)` : label,
35
+ choices: options,
36
+ default: defaultValue,
37
+ validate: toInquirerValidate(validators)
38
+ };
39
+ };
40
+ export const toInquirerValidate = (validators) => {
41
+ return (value) => {
42
+ return validators?.find((v) => !v.isValid(value))?.getErrorMessage() ?? true;
43
+ };
44
+ };
@@ -0,0 +1,5 @@
1
+ export class GreaterEqThanValidator {
2
+ isValid(value, { min }) {
3
+ return value >= min;
4
+ }
5
+ }
@@ -0,0 +1,6 @@
1
+ export class LengthValidator {
2
+ isValid(value, { min, max }) {
3
+ const length = value.length;
4
+ return length >= min && length <= max;
5
+ }
6
+ }
@@ -0,0 +1,5 @@
1
+ export class RequiredValidator {
2
+ isValid(value) {
3
+ return value !== null && value !== undefined && value !== '';
4
+ }
5
+ }
@@ -0,0 +1,13 @@
1
+ import { RequiredValidator } from './required_validator.js';
2
+ import { GreaterEqThanValidator } from './greater_eq_than_validator.js';
3
+ import { LengthValidator } from './length_validator.js';
4
+ export const VALIDATORS_TYPES = {
5
+ required: 'required',
6
+ greaterEqThan: 'greaterEqThan',
7
+ length: 'length'
8
+ };
9
+ export const VALIDATOR_TYPE_TO_VALIDATOR = {
10
+ [VALIDATORS_TYPES.required]: new RequiredValidator(),
11
+ [VALIDATORS_TYPES.greaterEqThan]: new GreaterEqThanValidator(),
12
+ [VALIDATORS_TYPES.length]: new LengthValidator()
13
+ };
@@ -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 '../caches/cache_factory.js';
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() {
@@ -58,6 +58,7 @@ export class FetchResources {
58
58
  });
59
59
  }));
60
60
  }
61
+ return;
61
62
  }
62
63
  async _getResourcesFileContent(resourcePath) {
63
64
  return mapResourcesToTree(await readJSONFile(resourcePath));
@@ -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]) => {
@@ -1,6 +1,6 @@
1
1
  import { AsyncFeatureInitializer, FEATURE_CORES_TYPES } from '@dreamcommerce/star_core';
2
2
  import { THEMES_LIST_API_NAME } from '../../themes/list/themes_list_constants.js';
3
- import { JsonCache } from '../../../../cli/features/caches/json_cache/json_cache.js';
3
+ import { JsonCache } from '../../../../cli/class/caches/json_cache/json_cache.js';
4
4
  import { CLI_DATA_DIRECTORY_API_NAME } from '../../../../cli/features/data_directory/cli_data_directory_constants.js';
5
5
  import { THEME_ACTIONS_FEATURE_NAME, THEMES_ACTIONS_FILE_NAME } from './theme_actions_constants.js';
6
6
  import { ThemeActionsApi } from './api/theme_actions_api.js';
@@ -1,11 +1,21 @@
1
1
  import { THEME_ALL_ACTIONS_NAME } from './service/theme_actions_service_constants.js';
2
2
  import { toUnixPath } from '../../../../utils/path_utils.js';
3
- export const getFilesGlobsThatMatchesActionName = (actionType, actionValue, filesStructure) => {
4
- return Object.entries(filesStructure).reduce((acc, [filePath, fileStructureItem]) => {
5
- if (fileStructureItem._links?.[actionType] &&
6
- (fileStructureItem._links[actionType] === actionValue || actionValue === THEME_ALL_ACTIONS_NAME)) {
7
- return [...acc, toUnixPath(filePath)];
3
+ export class ThemeActionsUtils {
4
+ static getFilesGlobsThatMatchesActionName({ filesStructure, actionValue, actionType }) {
5
+ return Object.entries(filesStructure).reduce((acc, [filePath, fileStructureItem]) => {
6
+ if (fileStructureItem._links?.[actionType] && this._doesActionValueMatch(fileStructureItem._links[actionType], actionValue)) {
7
+ return [...acc, toUnixPath(filePath)];
8
+ }
9
+ return acc;
10
+ }, []);
11
+ }
12
+ static _doesActionValueMatch(currentActionValue, valuesToMatch) {
13
+ if (typeof valuesToMatch === 'string') {
14
+ return currentActionValue === valuesToMatch || valuesToMatch === THEME_ALL_ACTIONS_NAME;
8
15
  }
9
- return acc;
10
- }, []);
11
- };
16
+ if (Array.isArray(valuesToMatch)) {
17
+ return valuesToMatch.includes(currentActionValue) || valuesToMatch.includes(THEME_ALL_ACTIONS_NAME);
18
+ }
19
+ return false;
20
+ }
21
+ }
@@ -4,7 +4,7 @@ import { downloadFile } from '../../../../../utils/download_file/download_file_u
4
4
  import { extractZip } from '../../../../../utils/zip/extract_zip_utils.js';
5
5
  import { join } from '../../../../../utils/path_utils.js';
6
6
  import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
7
- import { getResources, mapResourcesToTree } from '../../../../class/fetch_resources/fetch_resources_utils.js';
7
+ import { getResources, mapResourcesToTree, removeOldResources } from '../../../../class/fetch_resources/fetch_resources_utils.js';
8
8
  import { FetchResources } from '../../../../class/fetch_resources/fetch_resources.js';
9
9
  import { jsonIndentTransform } from '../../../../../utils/stream_transforms/json_indent_transform.js';
10
10
  import { THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME } from '../../theme_constants.js';
@@ -15,7 +15,7 @@ import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
15
15
  import { THEME_ACTIONS_TYPES } from '../../actions/theme_actions_constants.js';
16
16
  import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
17
17
  import { ThemeMetaDataUtils } from '../../utils/meta_data/theme_meta_data_utils.js';
18
- import { ThemeChecksums } from '../../../../../theme/class/checksums/theme_checksums.js';
18
+ import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
19
19
  export class ThemeFetchService {
20
20
  #themeHttpApi;
21
21
  #httpApi;
@@ -107,6 +107,7 @@ export class ThemeFetchService {
107
107
  });
108
108
  }
109
109
  async fetchResources(shopUrl, dist, resources) {
110
+ await removeOldResources(dist, resources);
110
111
  const resourcesTree = mapResourcesToTree(resources);
111
112
  await Promise.all(Object.keys(resourcesTree).map((resource) => new FetchResources(this.#httpApi).fetchResources({
112
113
  resourcesPart: resourcesTree[resource],
@@ -6,7 +6,7 @@ import { createReadStream } from 'node:fs';
6
6
  import { v4 as uuid } from 'uuid';
7
7
  import globs from 'fast-glob';
8
8
  import { THEME_WILDCARD_ACTION_NAME } from '../../actions/service/theme_actions_service_constants.js';
9
- import { getFilesGlobsThatMatchesActionName } from '../../actions/theme_actions_utils.js';
9
+ import { ThemeActionsUtils } from '../../actions/theme_actions_utils.js';
10
10
  import { THEME_FILES_LIST_FILE_NAME, THEME_MODULE_SETTINGS_FILE_NAME } from '../theme_push_constants.js';
11
11
  import { THEME_PUSH_WILDCARD_GLOBS_FOR_FILES } from './theme_push_service_constants.js';
12
12
  import { ThemePushErrorsFactory } from '../theme_push_errors_factory.js';
@@ -15,6 +15,7 @@ import { ThemePublishUtils } from '../../skinstore/theme_publish_utils.js';
15
15
  import { formatJSONFile, removeFile, writeJSONFile } from '../../../../../utils/fs/fs_utils.js';
16
16
  import { MODULES_DIRECTORY_NAME } from '../../theme_constants.js';
17
17
  import path from 'node:path';
18
+ import { removeOldResources } from '../../../../class/fetch_resources/fetch_resources_utils.js';
18
19
  export class ThemePushService {
19
20
  #themePushHttpApi;
20
21
  #themeFetchApi;
@@ -47,7 +48,11 @@ export class ThemePushService {
47
48
  try {
48
49
  await this._createThemeArchive({
49
50
  themeRootDir: executionContext.themeRootDir,
50
- filesToArchive: getFilesGlobsThatMatchesActionName(THEME_ACTIONS_TYPES.push, THEME_WILDCARD_ACTION_NAME, filesStructure),
51
+ filesToArchive: ThemeActionsUtils.getFilesGlobsThatMatchesActionName({
52
+ actionType: THEME_ACTIONS_TYPES.push,
53
+ actionValue: THEME_WILDCARD_ACTION_NAME,
54
+ filesStructure
55
+ }),
51
56
  dist: themeArchivePath
52
57
  });
53
58
  }
@@ -61,8 +66,10 @@ export class ThemePushService {
61
66
  });
62
67
  if (modules)
63
68
  await this._updateDataForNewCreatedModules({ modules, themeRootDir: executionContext.themeRootDir });
64
- if (resources)
69
+ if (resources) {
70
+ await removeOldResources(executionContext.themeRootDir, resources);
65
71
  await this.#themeFetchApi.fetchResources(credentials.shopUrl, executionContext.themeRootDir, resources);
72
+ }
66
73
  await removeFile(join(executionContext.themeRootDir, THEME_FILES_LIST_FILE_NAME));
67
74
  await themeChecksums.updateAllChecksums();
68
75
  }
@@ -150,7 +157,11 @@ export class ThemePushService {
150
157
  const localFiles = {};
151
158
  for (const [actionKey, actionData] of Object.entries(pushAction.data)) {
152
159
  if (actionData.type === THEME_ACTION_DATA_TYPE.file) {
153
- const filesGlobs = getFilesGlobsThatMatchesActionName(THEME_ACTIONS_TYPES.push, actionKey, filesStructure);
160
+ const filesGlobs = ThemeActionsUtils.getFilesGlobsThatMatchesActionName({
161
+ actionType: THEME_ACTIONS_TYPES.push,
162
+ actionValue: actionKey,
163
+ filesStructure
164
+ });
154
165
  for (const fileGlob of filesGlobs) {
155
166
  const files = await globs(fileGlob, {
156
167
  suppressErrors: true,
@@ -6,7 +6,7 @@ export class ThemeSkinstoreApi extends FeatureApi {
6
6
  this.#service = service;
7
7
  }
8
8
  async getPublishFormData() {
9
- return this.#service.getPublishFormData();
9
+ // return this.#service.getPublishFormData();
10
10
  }
11
11
  async publish(themeId) {
12
12
  // return this.#service.publish(themeId);
@@ -3,5 +3,15 @@ export class ThemeSkinstoreHttpApi {
3
3
  constructor(httpApi) {
4
4
  this.#httpApi = httpApi;
5
5
  }
6
- async getPublishFormData() { }
6
+ getPublishFormData({ actionData, shopUrl }) {
7
+ const { method, url } = actionData;
8
+ return this.#httpApi.fetch({
9
+ url: `${shopUrl}${url}`,
10
+ method,
11
+ sanitizeOptions: {
12
+ disable: true
13
+ },
14
+ isPrivate: true
15
+ });
16
+ }
7
17
  }
@@ -1,3 +1,31 @@
1
+ import { STATUS_CODES } from '@dreamcommerce/star_core';
2
+ import { HttpErrorsFactory } from '../../../../../cli/class/errors/http/http_errors_factory.js';
3
+ import { DownloadFileErrorsFactory } from '../../../../../utils/download_file/download_file_errors_factory.js';
1
4
  export class ThemeSkinstoreService {
2
- async getPublishFormData() { }
5
+ #httpApi;
6
+ constructor(httpApi) {
7
+ this.#httpApi = httpApi;
8
+ }
9
+ async getPublishFormData({ credentials, actionData }) {
10
+ try {
11
+ const { response: request } = this.#httpApi.getPublishFormData({ actionData, shopUrl: credentials.shopUrl });
12
+ const response = await request;
13
+ if (response?.status !== STATUS_CODES.ok)
14
+ return;
15
+ return response?.data;
16
+ }
17
+ catch (err) {
18
+ //TODO to basic class
19
+ switch (err.response?.status) {
20
+ case 403:
21
+ throw HttpErrorsFactory.createForbiddenError();
22
+ case 401:
23
+ throw HttpErrorsFactory.createUnauthorizedError();
24
+ case 404:
25
+ throw HttpErrorsFactory.createNotFoundError();
26
+ default:
27
+ throw DownloadFileErrorsFactory.downloadError(err.response.status);
28
+ }
29
+ }
30
+ }
3
31
  }
@@ -21,7 +21,7 @@ export class ThemeImagesUtils {
21
21
  }
22
22
  static async removeUploadedOriginalFiles(themeRootDir, uploadedImagesData) {
23
23
  await Promise.all(uploadedImagesData
24
- .filter(({ originalFilename }) => Boolean(originalFilename))
24
+ .filter(({ originalFilename, uploadedFilename }) => Boolean(originalFilename) && Boolean(uploadedFilename))
25
25
  .map(({ originalFilename, location }) => {
26
26
  const originalFilePath = join(themeRootDir, location, originalFilename);
27
27
  return removeFile(originalFilePath);
@@ -3,5 +3,6 @@ export const THEME_COMMANDS_THAT_REQUIRED_ACTIONS_LIST = [
3
3
  THEME_COMMANDS_NAME.pull,
4
4
  THEME_COMMANDS_NAME.init,
5
5
  THEME_COMMANDS_NAME.push,
6
+ THEME_COMMANDS_NAME.delete,
6
7
  THEME_COMMANDS_NAME.showChanges
7
8
  ];
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@shoper/cli",
3
3
  "packageManager": "yarn@3.2.0",
4
4
  "sideEffects": false,
5
- "version": "0.1.0-31",
5
+ "version": "0.1.0-33",
6
6
  "description": "CLI tool for Shoper",
7
7
  "author": "Joanna Firek",
8
8
  "license": "MIT",
@@ -1,39 +0,0 @@
1
- export const toTextControl = ({ type, validate, label, isRequired, defaultValue, name }) => {
2
- return {
3
- type: 'input',
4
- name,
5
- message: isRequired ? `${label} (required)` : label,
6
- default: defaultValue,
7
- validate
8
- };
9
- };
10
- export const toNumberControl = ({ type, validate, label, isRequired, defaultValue, name }) => {
11
- return {
12
- type: 'number',
13
- name,
14
- message: isRequired ? `${label} (required)` : label,
15
- default: defaultValue,
16
- validate
17
- };
18
- };
19
- export const toSelectControl = ({ type, validate, label, isRequired, defaultValue, name, choices }) => {
20
- return {
21
- type: 'list',
22
- name,
23
- message: isRequired ? `${label} (required)` : label,
24
- choices,
25
- default: defaultValue,
26
- validate
27
- };
28
- };
29
- export const toMultiSelectControl = ({ type, validate, label, isRequired, defaultValue, name, choices }) => {
30
- //TODO multiple checkboxes
31
- return {
32
- type: 'checkbox',
33
- name,
34
- message: isRequired ? `${label} (required)` : label,
35
- choices,
36
- default: defaultValue,
37
- validate
38
- };
39
- };