@swell/cli 2.0.1-alpha.13 → 2.0.1-alpha.17

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 (91) hide show
  1. package/dist/app-command.d.ts +1 -1
  2. package/dist/app-command.js +8 -8
  3. package/dist/commands/app/dev.d.ts +18 -0
  4. package/dist/commands/app/dev.js +31 -0
  5. package/dist/commands/app/frontend/deploy.d.ts +17 -0
  6. package/dist/commands/app/frontend/deploy.js +44 -0
  7. package/dist/commands/app/frontend/dev.d.ts +21 -0
  8. package/dist/commands/app/frontend/dev.js +111 -0
  9. package/dist/commands/app/info.js +15 -8
  10. package/dist/commands/app/init.d.ts +12 -0
  11. package/dist/commands/app/init.js +34 -0
  12. package/dist/commands/app/install.d.ts +4 -4
  13. package/dist/commands/app/install.js +37 -42
  14. package/dist/commands/app/pull.d.ts +15 -0
  15. package/dist/commands/app/pull.js +50 -0
  16. package/dist/commands/app/push.d.ts +11 -14
  17. package/dist/commands/app/push.js +71 -143
  18. package/dist/commands/app/release.d.ts +13 -0
  19. package/dist/commands/app/release.js +150 -0
  20. package/dist/commands/app/version.d.ts +7 -6
  21. package/dist/commands/app/version.js +64 -43
  22. package/dist/commands/app/watch.d.ts +2 -4
  23. package/dist/commands/app/watch.js +3 -83
  24. package/dist/commands/create/app.d.ts +35 -11
  25. package/dist/commands/create/app.js +150 -144
  26. package/dist/commands/create/content.d.ts +2 -2
  27. package/dist/commands/create/content.js +10 -10
  28. package/dist/commands/create/frontend.d.ts +12 -0
  29. package/dist/commands/create/frontend.js +41 -0
  30. package/dist/commands/create/function.d.ts +3 -3
  31. package/dist/commands/create/function.js +22 -22
  32. package/dist/commands/create/model.d.ts +2 -2
  33. package/dist/commands/create/model.js +11 -11
  34. package/dist/commands/create/notification.d.ts +4 -4
  35. package/dist/commands/create/notification.js +38 -40
  36. package/dist/commands/login.d.ts +1 -1
  37. package/dist/commands/login.js +12 -9
  38. package/dist/commands/logs.js +2 -1
  39. package/dist/commands/theme/dev.d.ts +23 -0
  40. package/dist/commands/theme/dev.js +167 -0
  41. package/dist/commands/theme/init.d.ts +9 -0
  42. package/dist/commands/theme/init.js +15 -0
  43. package/dist/commands/theme/pull.d.ts +20 -0
  44. package/dist/commands/theme/pull.js +65 -0
  45. package/dist/commands/theme/push.d.ts +19 -0
  46. package/dist/commands/theme/push.js +92 -0
  47. package/dist/create-app-command.d.ts +20 -0
  48. package/dist/create-app-command.js +254 -0
  49. package/dist/create-collection-command.d.ts +9 -9
  50. package/dist/create-collection-command.js +23 -23
  51. package/dist/{create-command.d.ts → create-config-command.d.ts} +1 -1
  52. package/dist/{create-command.js → create-config-command.js} +9 -7
  53. package/dist/lib/api.d.ts +6 -4
  54. package/dist/lib/api.js +58 -29
  55. package/dist/lib/app-config.d.ts +13 -5
  56. package/dist/lib/app-config.js +60 -23
  57. package/dist/lib/apps/app-config.d.ts +22 -8
  58. package/dist/lib/apps/app-config.js +202 -68
  59. package/dist/lib/apps/index.d.ts +93 -13
  60. package/dist/lib/apps/index.js +150 -50
  61. package/dist/lib/apps/paths.d.ts +14 -7
  62. package/dist/lib/apps/paths.js +73 -28
  63. package/dist/lib/bundle.js +4 -5
  64. package/dist/lib/config.d.ts +5 -1
  65. package/dist/lib/config.js +14 -0
  66. package/dist/lib/constants.d.ts +5 -0
  67. package/dist/lib/constants.js +22 -3
  68. package/dist/lib/create/content.d.ts +2 -2
  69. package/dist/lib/create/content.js +1 -1
  70. package/dist/lib/create/function.d.ts +2 -2
  71. package/dist/lib/create/function.js +2 -2
  72. package/dist/lib/create/index.d.ts +1 -1
  73. package/dist/lib/create/index.js +11 -7
  74. package/dist/lib/create/model.d.ts +2 -2
  75. package/dist/lib/create/notification.d.ts +2 -2
  76. package/dist/lib/info.js +2 -2
  77. package/dist/lib/sessions.js +2 -2
  78. package/dist/lib/stores.d.ts +5 -2
  79. package/dist/lib/stores.js +9 -6
  80. package/dist/lib/style.d.ts +2 -0
  81. package/dist/lib/style.js +2 -0
  82. package/dist/lib/swell-function-wrapper.d.ts +2 -2
  83. package/dist/lib/swell-function-wrapper.js +2 -2
  84. package/dist/push-app-command.d.ts +73 -0
  85. package/dist/push-app-command.js +765 -0
  86. package/dist/remote-app-command.d.ts +35 -9
  87. package/dist/remote-app-command.js +436 -164
  88. package/oclif.manifest.json +841 -125
  89. package/package.json +13 -1
  90. package/dist/commands/app/_pull.d.ts +0 -8
  91. package/dist/commands/app/_pull.js +0 -45
@@ -1,26 +1,26 @@
1
- import { CreateCommand } from './create-command.js';
1
+ import { CreateConfigCommand } from './create-config-command.js';
2
2
  /**
3
3
  * A base class for Swell CLI Create [content|models] command input.
4
4
  *
5
- * This class extends the `CreateCommand` class and adds:
5
+ * This class extends the `CreateConfigCommand` class and adds:
6
6
  *
7
7
  * - promptCollection: Get collection name and description
8
8
  */
9
- export declare abstract class CreateCollectionCommand extends CreateCommand {
10
- static baseFlags: {
11
- 'app-path': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
12
- };
9
+ export declare abstract class CreateCollectionCommand extends CreateConfigCommand {
13
10
  static args: {
14
11
  collection: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
15
12
  };
13
+ static baseFlags: {
14
+ 'app-path': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
15
+ };
16
16
  static flags: {
17
- label: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
18
17
  description: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
18
+ label: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
19
19
  overwrite: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
20
20
  };
21
21
  promptCollection(): Promise<{
22
- label: string;
23
- description: string;
24
22
  collection: string;
23
+ description: string;
24
+ label: string;
25
25
  }>;
26
26
  }
@@ -1,39 +1,39 @@
1
- import { input, select, Separator } from '@inquirer/prompts';
1
+ import { Separator, input, select } from '@inquirer/prompts';
2
2
  import { Args, Flags } from '@oclif/core';
3
- import { CreateCommand } from './create-command.js';
4
- import { toCollectionName, toCollectionLabel } from './lib/create/index.js';
3
+ import { CreateConfigCommand } from './create-config-command.js';
4
+ import { toCollectionLabel, toCollectionName } from './lib/create/index.js';
5
5
  /**
6
6
  * A base class for Swell CLI Create [content|models] command input.
7
7
  *
8
- * This class extends the `CreateCommand` class and adds:
8
+ * This class extends the `CreateConfigCommand` class and adds:
9
9
  *
10
10
  * - promptCollection: Get collection name and description
11
11
  */
12
- export class CreateCollectionCommand extends CreateCommand {
12
+ export class CreateCollectionCommand extends CreateConfigCommand {
13
13
  // base flags for all AppCommands
14
- // needs to be in a ES2021 format: https://github.com/oclif/oclif/issues/1100
15
- static baseFlags = {
16
- 'app-path': Flags.string({
17
- description: 'path to the app directory',
18
- }),
19
- };
20
14
  static args = {
21
15
  collection: Args.string({
22
16
  default: '',
23
17
  description: 'collection to create or apply to, i.e. products',
24
18
  }),
25
19
  };
26
- static flags = {
27
- label: Flags.string({
28
- char: 'l',
29
- default: '',
30
- description: 'the collection label',
20
+ // needs to be in a ES2021 format: https://github.com/oclif/oclif/issues/1100
21
+ static baseFlags = {
22
+ 'app-path': Flags.string({
23
+ description: 'path to your app directory',
31
24
  }),
25
+ };
26
+ static flags = {
32
27
  description: Flags.string({
33
28
  char: 'd',
34
29
  default: '',
35
30
  description: 'the collection description',
36
31
  }),
32
+ label: Flags.string({
33
+ char: 'l',
34
+ default: '',
35
+ description: 'the collection label',
36
+ }),
37
37
  overwrite: Flags.boolean({
38
38
  char: 'o',
39
39
  default: false,
@@ -42,14 +42,13 @@ export class CreateCollectionCommand extends CreateCommand {
42
42
  };
43
43
  async promptCollection() {
44
44
  const { args, flags } = await this.parse(CreateCollectionCommand);
45
- let { label, description } = flags;
45
+ let { description, label } = flags;
46
46
  let { collection } = args;
47
47
  let isStandardCollection = false;
48
48
  let collectionInput = collection;
49
49
  if (!collection) {
50
50
  const collections = await this.getCollectionOptions();
51
51
  collectionInput = await select({
52
- message: 'Where will content be stored?',
53
52
  choices: [
54
53
  { name: 'Create a new collection', value: '' },
55
54
  new Separator(),
@@ -58,6 +57,7 @@ export class CreateCollectionCommand extends CreateCommand {
58
57
  value: collectionName,
59
58
  })),
60
59
  ],
60
+ message: 'Where will content be stored?',
61
61
  pageSize: 25,
62
62
  });
63
63
  if (collectionInput) {
@@ -65,8 +65,8 @@ export class CreateCollectionCommand extends CreateCommand {
65
65
  }
66
66
  else {
67
67
  collectionInput = await input({
68
- message: 'Collection name',
69
68
  default: 'special-things',
69
+ message: 'Collection name',
70
70
  });
71
71
  }
72
72
  // we replace unwanted characters with underscores to make things easier
@@ -75,23 +75,23 @@ export class CreateCollectionCommand extends CreateCommand {
75
75
  }
76
76
  if (!label && !isStandardCollection) {
77
77
  label = await input({
78
- message: 'Collection label',
79
78
  default: toCollectionLabel(collection),
79
+ message: 'Collection label',
80
80
  });
81
81
  label = toCollectionLabel(label);
82
82
  }
83
83
  description =
84
84
  description ||
85
85
  (await input({
86
+ default: 'Special things for special people',
86
87
  message: isStandardCollection
87
88
  ? `Describe the purpose of fields being added to ${collection}`
88
89
  : 'Describe what this collection is for',
89
- default: 'Special things for special people',
90
90
  }));
91
91
  return {
92
- label,
93
- description,
94
92
  collection,
93
+ description,
94
+ label,
95
95
  };
96
96
  }
97
97
  }
@@ -9,7 +9,7 @@ import { CreateFileParams } from './lib/create/index.js';
9
9
  * - createType: Type of Config to generate file path
10
10
  * - createFile: File creation, including general prompts
11
11
  */
12
- export declare abstract class CreateCommand extends AppCommand {
12
+ export declare abstract class CreateConfigCommand extends AppCommand {
13
13
  protected createType: '' | ConfigType;
14
14
  protected createFile({ extension, fileBody, fileName }: CreateFileParams, overwrite: boolean, shouldConfirm?: boolean): Promise<boolean | undefined>;
15
15
  protected getCollectionOptions(): Promise<any>;
@@ -1,7 +1,7 @@
1
1
  import { confirm } from '@inquirer/prompts';
2
2
  import * as path from 'node:path';
3
3
  import { AppCommand } from './app-command.js';
4
- import { ConfigPaths, fileExists, writeFile, writeJsonFile, } from './lib/apps/index.js';
4
+ import { ConfigPaths, filePathExists, writeFile, writeJsonFile, } from './lib/apps/index.js';
5
5
  /**
6
6
  * A base class for Swell CLI Create commands for file and input handling.
7
7
  *
@@ -10,7 +10,7 @@ import { ConfigPaths, fileExists, writeFile, writeJsonFile, } from './lib/apps/i
10
10
  * - createType: Type of Config to generate file path
11
11
  * - createFile: File creation, including general prompts
12
12
  */
13
- export class CreateCommand extends AppCommand {
13
+ export class CreateConfigCommand extends AppCommand {
14
14
  createType = '';
15
15
  async createFile({ extension = 'json', fileBody, fileName }, overwrite, shouldConfirm = true) {
16
16
  const isJson = extension === 'json';
@@ -18,7 +18,7 @@ export class CreateCommand extends AppCommand {
18
18
  if (shouldConfirm) {
19
19
  this.log(`\nCreating app ${this.createType} in ${filePath}`);
20
20
  this.log(`\n${isJson ? JSON.stringify(fileBody, null, 4) : fileBody}\n`);
21
- if (fileExists(filePath) && !overwrite) {
21
+ if (filePathExists(filePath) && !overwrite) {
22
22
  const continueWrite = await confirm({
23
23
  message: `This will overwrite an existing ${this.createType} file. Ok to continue?`,
24
24
  });
@@ -44,14 +44,16 @@ export class CreateCommand extends AppCommand {
44
44
  async getCollectionOptions() {
45
45
  const models = await this.api.post({ adminPath: `/data/$get/:models` }, {
46
46
  body: {
47
- limit: 1000,
48
- client_id: null,
49
- app_id: null,
50
47
  abstract: { $ne: true },
48
+ // eslint-disable-next-line camelcase
49
+ app_id: null,
50
+ // eslint-disable-next-line camelcase
51
+ client_id: null,
51
52
  deprecated: { $ne: true },
53
+ fields: 'name, namespace',
54
+ limit: 1000,
52
55
  name: { $nin: ['events', 'notifications', 'settings'] },
53
56
  sort: 'namespace asc, name asc',
54
- fields: 'name, namespace',
55
57
  },
56
58
  });
57
59
  return (models?.results?.map((model) => model.namespace ? `${model.namespace}/${model.name}` : model.name) || []);
package/dist/lib/api.d.ts CHANGED
@@ -1,13 +1,15 @@
1
1
  export default class Api {
2
+ private envId;
2
3
  private secretKey;
3
4
  private storeId;
4
- private envId;
5
5
  constructor(storeId?: string, envId?: string, secretKey?: string);
6
- setStoreEnv(storeId: string, envId?: string): void;
7
6
  api(pathOpts: Api.Paths, options: Api.RequestOptions): Promise<any>;
8
- delete(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
9
- get(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
10
7
  isAdmin(): boolean;
8
+ waitForAsyncResponse(response: any, pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
9
+ get(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
11
10
  post(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
12
11
  put(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
12
+ delete(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
13
+ setStoreEnv(storeId: string, envId?: string): void;
14
+ truncatePath(path: string | undefined): string | undefined;
13
15
  }
package/dist/lib/api.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import fetch from 'node-fetch';
2
+ import qs from 'qs';
2
3
  import config from './config.js';
3
- import { getAdminApiBaseUrl, API_BASE_URL } from './constants.js';
4
+ import { API_BASE_URL, getAdminApiBaseUrl } from './constants.js';
4
5
  const defaultHeaders = (opts) => ({
5
6
  'Content-Type': 'application/json',
6
7
  ...opts,
@@ -23,18 +24,14 @@ const authenticatedHeaders = (storeId, opts = {}) => {
23
24
  return defaultHeaders(moreOpts);
24
25
  };
25
26
  export default class Api {
27
+ envId;
26
28
  secretKey;
27
29
  storeId;
28
- envId;
29
30
  constructor(storeId, envId, secretKey) {
30
31
  this.storeId = storeId;
31
32
  this.envId = envId;
32
33
  this.secretKey = secretKey;
33
34
  }
34
- setStoreEnv(storeId, envId) {
35
- this.storeId = storeId;
36
- this.envId = envId;
37
- }
38
35
  async api(pathOpts, options) {
39
36
  const storeId = this.storeId || config.getDefaultStore();
40
37
  let path;
@@ -51,11 +48,10 @@ export default class Api {
51
48
  },
52
49
  };
53
50
  path = this.isAdmin()
54
- ? `${getAdminApiBaseUrl(storeId)}/${pathOpts.adminPath}`
55
- : `${API_BASE_URL}/${pathOpts.backendPath}`;
51
+ ? `${getAdminApiBaseUrl(storeId)}/${this.truncatePath(pathOpts.adminPath)}`
52
+ : `${API_BASE_URL}/${this.truncatePath(pathOpts.backendPath)}`;
56
53
  if (options.query) {
57
- const query = new URLSearchParams(options.query);
58
- path += `?${query.toString()}`;
54
+ path += `?${qs.stringify(options.query)}`;
59
55
  }
60
56
  path = path
61
57
  // eslint-disable-next-line no-template-curly-in-string
@@ -63,38 +59,55 @@ export default class Api {
63
59
  .replaceAll(/([^:]\/)\/+/g, '$1'); // remove duplicate slashes
64
60
  if (!path)
65
61
  throw new Error('Operation not supported.');
66
- const resp = await fetch(path, fetchOptions);
67
- const respData = await resp.text();
68
- if (!resp.ok) {
62
+ const res = await fetch(path, fetchOptions);
63
+ const resData = await res.text();
64
+ if (!res.ok) {
69
65
  // Try to parse error message
70
66
  let errorJson;
71
67
  try {
72
- errorJson = JSON.parse(respData);
68
+ errorJson = JSON.parse(resData);
73
69
  }
74
70
  catch {
75
71
  // ignore
76
72
  }
77
- throw new Error(errorJson?.error?.message || errorJson?.error || respData);
73
+ const error = new Error(errorJson?.error?.message || errorJson?.error || resData);
74
+ error.status = res.status;
75
+ throw error;
78
76
  }
79
77
  try {
80
- return JSON.parse(respData);
78
+ return JSON.parse(resData);
81
79
  }
82
80
  catch (error) {
83
81
  // respData could be "{}" (length: >=2) but it shouldn't be "{", " " (whitespace - length: 1) or
84
82
  // "" (empty response - length: 0) while logging the error.
85
- if (respData.length >= 2)
83
+ if (resData.length >= 2)
86
84
  console.log(error);
87
85
  return null;
88
86
  }
89
87
  }
90
- async delete(pathOpts, options = {}) {
91
- // ensure post body is stringified
92
- if (options.body)
93
- options.body = JSON.stringify(options.body);
94
- return this.api(pathOpts, {
95
- method: 'DELETE',
96
- ...options,
88
+ isAdmin() {
89
+ return !this.secretKey;
90
+ }
91
+ async waitForAsyncResponse(response, pathOpts, options = {}) {
92
+ const { onAsyncGetPath, spinner } = options;
93
+ if (!response?.async_progressing || !onAsyncGetPath) {
94
+ return response;
95
+ }
96
+ await new Promise((resolve) => setTimeout(resolve, 1000));
97
+ const asyncResponse = await this.api(onAsyncGetPath(response), {
98
+ method: 'GET',
99
+ onAsyncGetPath,
97
100
  });
101
+ if (asyncResponse?.async_error) {
102
+ throw new Error(asyncResponse.async_error);
103
+ }
104
+ if (!asyncResponse?.async_progressing && spinner) {
105
+ spinner.suffixText = '';
106
+ }
107
+ else if (asyncResponse?.async_progress > 0 && spinner) {
108
+ spinner.suffixText = `${asyncResponse.async_progress}%`;
109
+ }
110
+ return this.waitForAsyncResponse(asyncResponse, pathOpts, options);
98
111
  }
99
112
  async get(pathOpts, options = {}) {
100
113
  return this.api(pathOpts, {
@@ -102,25 +115,41 @@ export default class Api {
102
115
  ...options,
103
116
  });
104
117
  }
105
- isAdmin() {
106
- return !this.secretKey;
107
- }
108
118
  async post(pathOpts, options = {}) {
109
119
  // ensure post body is stringified
110
120
  if (options.body)
111
121
  options.body = JSON.stringify(options.body);
112
- return this.api(pathOpts, {
122
+ const response = await this.api(pathOpts, {
113
123
  method: 'POST',
114
124
  ...options,
115
125
  });
126
+ return this.waitForAsyncResponse(response, pathOpts, options);
116
127
  }
117
128
  async put(pathOpts, options = {}) {
118
129
  // ensure post body is stringified
119
130
  if (options.body)
120
131
  options.body = JSON.stringify(options.body);
121
- return this.api(pathOpts, {
132
+ const response = await this.api(pathOpts, {
122
133
  method: 'PUT',
123
134
  ...options,
124
135
  });
136
+ return this.waitForAsyncResponse(response, pathOpts, options);
137
+ }
138
+ async delete(pathOpts, options = {}) {
139
+ // ensure post body is stringified
140
+ if (options.body)
141
+ options.body = JSON.stringify(options.body);
142
+ const response = await this.api(pathOpts, {
143
+ method: 'DELETE',
144
+ ...options,
145
+ });
146
+ return this.waitForAsyncResponse(response, pathOpts, options);
147
+ }
148
+ setStoreEnv(storeId, envId) {
149
+ this.storeId = storeId;
150
+ this.envId = envId;
151
+ }
152
+ truncatePath(path) {
153
+ return path?.startsWith('/') ? path.slice(1) : path;
125
154
  }
126
155
  }
@@ -1,29 +1,37 @@
1
1
  import { App } from './apps';
2
2
  /**
3
- * Checks if the app config file exists.
3
+ * Checks if the swell config file exists at the given path, default to cwd.
4
4
  *
5
5
  * @param configFilePath - the path to the app config file
6
6
  * @returns boolean
7
7
  * @throws Error
8
8
  */
9
- declare function appConfigFileExists(configFilePath?: string): boolean;
9
+ declare function swellConfigFileExists(configFilePath?: string): boolean;
10
10
  declare function writeRcFile(path: string, data: any): Promise<void>;
11
11
  declare function readRcFile(path: string): App;
12
12
  /**
13
13
  * Returns a new configuration instance in the current working directory or
14
14
  * a parent directory.
15
15
  *
16
- * @param configDirPath - the path to the app config directory. If not provided,
16
+ * @param configDir - the path to the app config directory. If not provided,
17
17
  * the config file will be searched for in the current working directory or
18
18
  * a parent directory.
19
19
  *
20
20
  * @returns Conf
21
21
  */
22
- declare function config(configDirPath?: string): LocalApp;
22
+ declare function config(configDir?: string): LocalApp;
23
23
  /**
24
24
  * Returns a new configuration instance in the current working directory only.
25
25
  *
26
+ * @param path Path of the current working directory
26
27
  * @returns Conf
27
28
  */
28
29
  declare function newConfig(path?: string): any;
29
- export { appConfigFileExists, config as default, newConfig, readRcFile, writeRcFile, };
30
+ /**
31
+ * Returns a new configuration instance at the specified path.
32
+ *
33
+ * @param path Path of the current working directory
34
+ * @returns Conf
35
+ */
36
+ declare function newConfigAtPath(appPath?: string): any;
37
+ export { swellConfigFileExists, config as default, newConfig, newConfigAtPath, readRcFile, writeRcFile, };
@@ -6,10 +6,13 @@ import * as fs from 'node:fs';
6
6
  import * as path from 'node:path';
7
7
  const schema = {
8
8
  id: { type: 'string' },
9
- version: { type: 'string' },
10
9
  name: { type: 'string' },
11
- description: { type: 'string' },
12
10
  type: { type: 'string' },
11
+ version: { type: 'string' },
12
+ description: { type: 'string' },
13
+ storefront: { type: 'object' },
14
+ theme: { type: 'object' },
15
+ compatibilities: { type: 'object' },
13
16
  permissions: { type: 'array' },
14
17
  };
15
18
  const APP_FILE_NAME = 'swell';
@@ -21,23 +24,23 @@ const APP_FILE_EXT = 'json';
21
24
  * @param dir - the directory to use for the config file path
22
25
  * @returns string
23
26
  */
24
- function appConfigFile(dir = '') {
27
+ function swellConfigFile(dir = '') {
25
28
  if (!dir) {
26
29
  dir = process.cwd();
27
30
  }
28
31
  return path.join(dir, [APP_FILE_NAME, '.', APP_FILE_EXT].join(''));
29
32
  }
30
33
  /**
31
- * Checks if the app config file exists.
34
+ * Checks if the swell config file exists at the given path, default to cwd.
32
35
  *
33
36
  * @param configFilePath - the path to the app config file
34
37
  * @returns boolean
35
38
  * @throws Error
36
39
  */
37
- function appConfigFileExists(configFilePath = '') {
40
+ function swellConfigFileExists(configFilePath = '') {
38
41
  // if the config file path is not provided, try to find it as the default
39
42
  if (!configFilePath) {
40
- configFilePath = appConfigFile();
43
+ configFilePath = swellConfigFile();
41
44
  }
42
45
  try {
43
46
  // eslint-disable-next-line no-bitwise
@@ -59,9 +62,9 @@ function appConfigFileExists(configFilePath = '') {
59
62
  * @returns string
60
63
  * @throws Error
61
64
  */
62
- function appConfigFilePath(dir = '') {
63
- const configFilePath = appConfigFile(dir);
64
- if (appConfigFileExists(configFilePath)) {
65
+ function swellConfigFilePath(dir = '') {
66
+ const configFilePath = swellConfigFile(dir);
67
+ if (swellConfigFileExists(configFilePath)) {
65
68
  return configFilePath;
66
69
  }
67
70
  // if the file doesn't exist, try to find it in the parent directory
@@ -69,10 +72,10 @@ function appConfigFilePath(dir = '') {
69
72
  if (dir && dir === path.parse(dir).root) {
70
73
  return '';
71
74
  }
72
- return appConfigFilePath(path.resolve(dir, '..'));
75
+ return swellConfigFilePath(path.resolve(dir, '..'));
73
76
  }
74
77
  async function writeRcFile(path, data) {
75
- let dataToWrite = '';
78
+ let dataToWrite = '# This file is automatically generated by the Swell CLI\n';
76
79
  for (const [key, value] of Object.entries(data)) {
77
80
  dataToWrite += `${key}=${value}\n`;
78
81
  }
@@ -83,9 +86,15 @@ function readRcFile(path) {
83
86
  const dataFromFile = fs.readFileSync(path, 'utf8');
84
87
  const lines = dataFromFile.split('\n');
85
88
  for (const line of lines) {
86
- const [key, value] = line.split('=');
87
- if (key && value) {
88
- data[key] = value;
89
+ const cleanLine = line.trim();
90
+ if (cleanLine.startsWith('#')) {
91
+ // Ignore comments
92
+ continue;
93
+ }
94
+ const [key, value] = cleanLine.trim().split('=');
95
+ const cleanValue = value && value.trim();
96
+ if (key && cleanValue) {
97
+ data[key] = cleanValue;
89
98
  }
90
99
  }
91
100
  return data;
@@ -94,19 +103,26 @@ function readRcFile(path) {
94
103
  * Returns a new configuration instance in the current working directory or
95
104
  * a parent directory.
96
105
  *
97
- * @param configDirPath - the path to the app config directory. If not provided,
106
+ * @param configDir - the path to the app config directory. If not provided,
98
107
  * the config file will be searched for in the current working directory or
99
108
  * a parent directory.
100
109
  *
101
110
  * @returns Conf
102
111
  */
103
- function config(configDirPath = '') {
104
- const dirPath = configDirPath || path.dirname(appConfigFilePath());
105
- const config = new Conf({
106
- configName: APP_FILE_NAME,
107
- cwd: dirPath,
108
- schema,
109
- });
112
+ function config(configDir = '') {
113
+ const dirPath = configDir || path.dirname(swellConfigFilePath());
114
+ let config;
115
+ try {
116
+ config = new Conf({
117
+ configName: APP_FILE_NAME,
118
+ cwd: dirPath,
119
+ schema,
120
+ clearInvalidConfig: true,
121
+ });
122
+ }
123
+ catch (err) {
124
+ throw new Error(`Error parsing swell.json: ${err.toString()}`);
125
+ }
110
126
  // for convenience, we add custom properties to the Conf object
111
127
  // we prefix them with "sw" to avoid conflicts with Conf's properties
112
128
  config.swDirPath = dirPath;
@@ -115,6 +131,7 @@ function config(configDirPath = '') {
115
131
  /**
116
132
  * Returns a new configuration instance in the current working directory only.
117
133
  *
134
+ * @param path Path of the current working directory
118
135
  * @returns Conf
119
136
  */
120
137
  function newConfig(path) {
@@ -122,6 +139,26 @@ function newConfig(path) {
122
139
  configName: APP_FILE_NAME,
123
140
  cwd: `${process.cwd()}${path ? `/${path}` : ''}`,
124
141
  schema,
142
+ serialize,
143
+ clearInvalidConfig: true,
125
144
  });
126
145
  }
127
- export { appConfigFileExists, config as default, newConfig, readRcFile, writeRcFile, };
146
+ /**
147
+ * Returns a new configuration instance at the specified path.
148
+ *
149
+ * @param path Path of the current working directory
150
+ * @returns Conf
151
+ */
152
+ function newConfigAtPath(appPath) {
153
+ const dirPath = appPath || path.dirname(swellConfigFilePath());
154
+ return new Conf({
155
+ configName: APP_FILE_NAME,
156
+ cwd: dirPath,
157
+ schema,
158
+ serialize,
159
+ });
160
+ }
161
+ function serialize(value) {
162
+ return JSON.stringify(value, null, 2);
163
+ }
164
+ export { swellConfigFileExists, config as default, newConfig, newConfigAtPath, readRcFile, writeRcFile, };
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import { ConfigType } from './index.js';
2
3
  declare class IgnoringFileError extends Error {
3
4
  constructor(message: string);
@@ -14,29 +15,42 @@ type AppConfigFile = {
14
15
  length?: number;
15
16
  md5?: string;
16
17
  url?: string;
18
+ content_type?: string;
17
19
  };
18
20
  /**
19
21
  * An app configuration as defined by the Swell API. This implies that the
20
22
  * app & the configuration are saved to the API.
21
23
  */
22
24
  declare abstract class AppConfig {
23
- date_created?: string;
24
- file?: AppConfigFile;
25
- fileData?: string;
26
25
  id?: string;
27
- /** The local path of a remote AppConfig */
28
- localPath?: string;
26
+ version?: string;
27
+ hash?: string;
28
+ fileHash?: string;
29
+ file?: AppConfigFile;
30
+ file_path?: string;
29
31
  name?: string;
30
32
  parent_id?: string;
31
33
  slug?: string;
32
34
  values: {
33
35
  [key: string]: any;
34
36
  };
35
- constructor(attrs?: Partial<AppConfig>);
36
- static create(attrs?: Partial<AppConfig>): AppConfig;
37
- postData(): Promise<any>;
37
+ date_created?: string;
38
+ date_updated?: string;
39
+ appConfigId?: string;
40
+ filePath: string;
41
+ appPath: string;
42
+ fileData?: Buffer;
43
+ fileContent?: string;
44
+ byteSize?: number;
45
+ mbSize?: number;
38
46
  /** build the JSON used when making requests (usually push) to the API */
39
47
  protected abstract preparePostData(postData: any): Promise<any>;
40
48
  abstract type: ConfigType;
49
+ abstract hasValues: boolean;
50
+ constructor(attrs?: Partial<AppConfig>);
51
+ static create(attrs?: Partial<AppConfig>): AppConfig;
52
+ postData(): Promise<any>;
53
+ prepareFileData(): any;
54
+ isRootConfig(configDir: string): boolean;
41
55
  }
42
56
  export { AppConfig, FunctionProcessingError, IgnoringFileError };