@swell/cli 2.0.9 → 2.0.11

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.
@@ -32,6 +32,7 @@ The app must be connected to a partner account with access to publish.`;
32
32
  'swell app release',
33
33
  'swell app release 2.0.0',
34
34
  'swell app release 2.0.0 --amend --release-notes ./releases/v2.0.0.md',
35
+ 'swell app release 2.0.0 -y',
35
36
  ];
36
37
  static flags = {
37
38
  amend: Flags.boolean({
@@ -50,11 +51,15 @@ The app must be connected to a partner account with access to publish.`;
50
51
  'release-notes': Flags.string({
51
52
  description: 'relative path to a file containing release notes',
52
53
  }),
54
+ yes: Flags.boolean({
55
+ char: 'y',
56
+ description: 'skip confirmation prompt',
57
+ }),
53
58
  };
54
59
  static summary = 'Release a new version of your an app for publishing to the App Store.';
55
60
  async run() {
56
61
  const { args, flags } = await this.parse(AppRelease);
57
- const { amend, message, 'not-supported': notSupported, 'release-notes': releaseNotesFile, } = flags;
62
+ const { amend, message, 'not-supported': notSupported, 'release-notes': releaseNotesFile, yes, } = flags;
58
63
  if (!(await this.ensureAppExists(undefined, false))) {
59
64
  return;
60
65
  }
@@ -83,7 +88,7 @@ The app must be connected to a partner account with access to publish.`;
83
88
  ? true
84
89
  : appVersion.supported,
85
90
  };
86
- if (!amend) {
91
+ if (!amend && !yes) {
87
92
  const continueVersion = await confirm({
88
93
  message: `Release ${style.appConfigValue(this.app.name)} version ${appVersion.version}?`,
89
94
  });
@@ -135,6 +140,7 @@ The app must be connected to a partner account with access to publish.`;
135
140
  version,
136
141
  ...(flags.message ? [`-m ${JSON.stringify(flags.message)}`] : []),
137
142
  ...(flags['no-git-tag'] ? ['--no-git-tag'] : []),
143
+ ...(flags.yes ? ['-y'] : []),
138
144
  ]);
139
145
  this.log();
140
146
  appVersion = await this.getVersion(version);
@@ -9,6 +9,7 @@ export default class AppVersion extends PushAppCommand {
9
9
  amend: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
10
10
  message: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
11
11
  'no-git-tag': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
12
+ yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
12
13
  };
13
14
  static summary: string;
14
15
  run(): Promise<void>;
@@ -49,6 +49,7 @@ behavior by using the --no-git-tag option.`;
49
49
  'swell app version',
50
50
  'swell app version minor',
51
51
  'swell app version 1.0.0 -m "First release"',
52
+ 'swell app version patch -y',
52
53
  ];
53
54
  static flags = {
54
55
  amend: Flags.boolean({
@@ -61,11 +62,15 @@ behavior by using the --no-git-tag option.`;
61
62
  'no-git-tag': Flags.boolean({
62
63
  description: 'do not create a git tag for this version',
63
64
  }),
65
+ yes: Flags.boolean({
66
+ char: 'y',
67
+ description: 'skip confirmation prompt',
68
+ }),
64
69
  };
65
70
  static summary = 'Increment the version of your Swell app.';
66
71
  async run() {
67
72
  const { args, flags } = await this.parse(AppVersion);
68
- const { amend, 'no-git-tag': noGitTag } = flags;
73
+ const { amend, 'no-git-tag': noGitTag, yes } = flags;
69
74
  let { message } = flags;
70
75
  let { nextVersion } = args;
71
76
  if (!(await this.ensureAppExists(undefined, false))) {
@@ -99,9 +104,7 @@ behavior by using the --no-git-tag option.`;
99
104
  }
100
105
  return;
101
106
  }
102
- else {
103
- nextVersion = this.validateAndComputeVersion(nextVersion, remoteVersion);
104
- }
107
+ nextVersion = this.validateAndComputeVersion(nextVersion, remoteVersion);
105
108
  await this.pushAppConfigs();
106
109
  await this.deployAppFrontend(false, false);
107
110
  if (!message) {
@@ -109,11 +112,13 @@ behavior by using the --no-git-tag option.`;
109
112
  message: `Describe the changes in version ${nextVersion}:`,
110
113
  });
111
114
  }
112
- const continueVersion = await confirm({
113
- message: `Create ${style.appConfigValue(this.app.name)} version ${nextVersion}?`,
114
- });
115
- if (!continueVersion) {
116
- return;
115
+ if (!yes) {
116
+ const continueVersion = await confirm({
117
+ message: `Create ${style.appConfigValue(this.app.name)} version ${nextVersion}?`,
118
+ });
119
+ if (!continueVersion) {
120
+ return;
121
+ }
117
122
  }
118
123
  if (!message) {
119
124
  message = nextVersion;
@@ -132,17 +132,23 @@ declare function writeFile(file: string, data: string): Promise<void>;
132
132
  declare function deleteFile(file: string): Promise<void>;
133
133
  declare function writeJsonFile(file: string, data?: any): Promise<void>;
134
134
  declare function hashFile(filePath: string, fileContents?: Buffer, relativePath?: string): string;
135
- declare function hashString(contents: string): string;
135
+ declare function hashString(...contents: (Buffer | string)[]): string;
136
136
  declare function appAssetImage(appPath: string, fileName: string): string | undefined;
137
137
  declare function appConfigFromFile(filePath: string, configType: ConfigType, appPath: string): AppConfig;
138
138
  declare function findAppConfig(app: App, filePath: string, configType: ConfigType): AppConfig | undefined;
139
+ interface BatchAppFiles {
140
+ configs: AppConfig[];
141
+ type: ConfigType;
142
+ label: string;
143
+ concurrency: number;
144
+ }
139
145
  /**
140
146
  * Get files to push in batches prioritized by dependencies
141
147
  *
142
- * @param configs - List of app configs
143
- * @returns {Array} Batches of files to push
148
+ * @param {AppConfig[]} configs - List of app configs
149
+ * @returns {BatchAppFiles[]} Batches of files to push
144
150
  */
145
- declare function batchAppFilesByType(configs: AppConfig[]): Array<any>;
151
+ declare function batchAppFilesByType(configs: AppConfig[]): BatchAppFiles[];
146
152
  export { PUSH_CONCURRENCY, App, AppVersion, ConfigInputFields, ConfigPaths, ConfigPathsType, ConfigType, FrontendProjectType, FrontendProjectTypes, StorefrontConfigPaths, StorefrontConfigTypes, SwellJsonFields, ThemeConfigPaths, ThemeConfigTypes, appAssetImage, appConfigFromFile, batchAppFilesByType, deleteFile, filePathExists, findAppConfig, getAppSlugId, getConfigTypeFromPath, getConfigTypeKeyFromValue, getFrontendProjectType, hashFile, hashString, writeFile, writeJsonFile, };
147
153
  export { AppConfig, FunctionProcessingError, IgnoringFileError, } from './app-config.js';
148
154
  export { allBaseFilesInDir, allConfigDirsPaths, allConfigFilesInDir, allConfigFilesPaths, allConfigFilesPathsByType, getAllConfigPaths, globAllFilesByPath, isPathDirectory, } from './paths.js';
@@ -1,4 +1,4 @@
1
- import { hash as blake3hash } from 'blake3-wasm';
1
+ import { createHash as createBlake3Hash } from 'blake3-wasm';
2
2
  import { pluralize, titleize } from 'inflection';
3
3
  import * as fs from 'node:fs';
4
4
  import * as path from 'node:path';
@@ -186,13 +186,16 @@ async function writeJsonFile(file, data = {}) {
186
186
  // Hash method adapted from wrangler-sdk
187
187
  function hashFile(filePath, fileContents, relativePath) {
188
188
  const contents = fileContents ?? fs.readFileSync(filePath);
189
- const base64Contents = contents.toString('base64');
190
189
  // Include relative file path because we typically cache by hash including file metadata
191
190
  // This allows de-duplication of cache entries for the same file contents
192
- return hashString(base64Contents + relativePath);
191
+ return hashString(contents, relativePath || '');
193
192
  }
194
- function hashString(contents) {
195
- return blake3hash(contents).toString('hex').slice(0, 32);
193
+ function hashString(...contents) {
194
+ const hash = createBlake3Hash();
195
+ for (const content of contents) {
196
+ hash.update(content);
197
+ }
198
+ return hash.digest('hex', { length: 16 });
196
199
  }
197
200
  function appAssetImage(appPath, fileName) {
198
201
  const assetsDirPath = path.join(appPath, ConfigPaths['ASSET']);
@@ -228,28 +231,26 @@ function findAppConfig(app, filePath, configType) {
228
231
  /**
229
232
  * Get files to push in batches prioritized by dependencies
230
233
  *
231
- * @param configs - List of app configs
232
- * @returns {Array} Batches of files to push
234
+ * @param {AppConfig[]} configs - List of app configs
235
+ * @returns {BatchAppFiles[]} Batches of files to push
233
236
  */
234
237
  function batchAppFilesByType(configs) {
235
238
  const modelsWithExtends = configs.filter((config) => config.type === 'model' && config.values.extends);
236
239
  const modelsWithoutExtends = configs.filter((config) => config.type === 'model' && !config.values.extends);
237
240
  const contentTypesWithCollection = configs.filter((config) => config.type === 'content' && config.values.collection);
238
241
  const contentTypesWithoutCollection = configs.filter((config) => config.type === 'content' && !config.values.collection);
239
- const prioritized = [
242
+ const prioritized = new Set([
240
243
  ...modelsWithExtends,
241
244
  ...modelsWithoutExtends,
242
245
  ...contentTypesWithCollection,
243
246
  ...contentTypesWithoutCollection,
244
- ];
247
+ ]);
245
248
  const sorted = [
246
- ...prioritized,
247
- ...configs.filter((config) => !prioritized.includes(config)),
249
+ ...prioritized.values(),
250
+ ...configs.filter((config) => !prioritized.has(config)),
248
251
  ];
249
252
  const batches = [];
250
- // eslint-disable-next-line guard-for-in
251
- for (const type in ConfigTypeBatchOrder) {
252
- const configType = ConfigTypeBatchOrder[type];
253
+ for (const configType of ConfigTypeBatchOrder) {
253
254
  const configsByType = sorted.filter((config) => config.type === configType);
254
255
  const label = configType === ConfigType.FILE ? 'App files' : titleize(configType);
255
256
  const concurrency = configType === ConfigType.NOTIFICATION || configType === ConfigType.ASSET
@@ -375,7 +375,7 @@ export class PushAppCommand extends RemoteAppCommand {
375
375
  const packageHash = localConfigs.find((config) => config.filePath === 'package.json')?.hash;
376
376
  frontendHashes += `|${packageHash}`;
377
377
  }
378
- return frontendHashes?.length > 0 ? hashString(frontendHashes) : undefined;
378
+ return frontendHashes.length > 0 ? hashString(frontendHashes) : undefined;
379
379
  }
380
380
  getFrontendProjectType(required = true) {
381
381
  this.frontendPath = path.join(this.appPath, 'frontend');
@@ -379,9 +379,8 @@ export class RemoteAppCommand extends AppCommand {
379
379
  }
380
380
  if (pullFiles.length > 0) {
381
381
  while (pullFiles.length > 0) {
382
- await Promise.all(pullFiles
383
- .splice(0, PUSH_CONCURRENCY)
384
- .map(async (config) => {
382
+ // eslint-disable-next-line no-await-in-loop
383
+ await Promise.all(pullFiles.splice(0, PUSH_CONCURRENCY).map(async (config) => {
385
384
  await this.pullRemoteFile(config);
386
385
  pulled.push(config.id);
387
386
  }));
@@ -393,6 +392,7 @@ export class RemoteAppCommand extends AppCommand {
393
392
  const removeList = filesToRemove
394
393
  .map((config) => config.filePath)
395
394
  .join('\n');
395
+ // eslint-disable-next-line no-await-in-loop
396
396
  const confirmed = await confirm({
397
397
  default: false,
398
398
  message: `The following files are not in the remote app:\n\n${removeList}\n\nDo you want to delete these files locally?`,
@@ -402,6 +402,7 @@ export class RemoteAppCommand extends AppCommand {
402
402
  }
403
403
  }
404
404
  while (filesToRemove.length > 0) {
405
+ // eslint-disable-next-line no-await-in-loop
405
406
  await Promise.all(filesToRemove.splice(0, PUSH_CONCURRENCY).map(async (config) => {
406
407
  await this.removeLocalFile(config);
407
408
  removed.push(config.id);
@@ -479,10 +480,9 @@ export class RemoteAppCommand extends AppCommand {
479
480
  this.log(`${style.appConfigName(`${batch.label} ${updatedLog}`)}`);
480
481
  }
481
482
  if (pushFiles.length > 0) {
482
- while (pushFiles.length) {
483
- await Promise.all(pushFiles
484
- .splice(0, batch.concurrency)
485
- .map(async (config) => {
483
+ while (pushFiles.length > 0) {
484
+ // eslint-disable-next-line no-await-in-loop
485
+ await Promise.all(pushFiles.splice(0, batch.concurrency).map(async (config) => {
486
486
  const pushedConfig = await this.pushRemoteFile(config);
487
487
  if (pushedConfig) {
488
488
  pushed.push(pushedConfig.id);
@@ -495,7 +495,8 @@ export class RemoteAppCommand extends AppCommand {
495
495
  }
496
496
  // Remove any deleted files
497
497
  if (filesToRemove.length > 0) {
498
- while (filesToRemove.length) {
498
+ while (filesToRemove.length > 0) {
499
+ // eslint-disable-next-line no-await-in-loop
499
500
  await Promise.all(filesToRemove.splice(0, batch.concurrency).map(async (config) => {
500
501
  await this.removeRemoteFile(config);
501
502
  removed.push(config.id);
@@ -698,7 +698,8 @@
698
698
  "examples": [
699
699
  "swell app release",
700
700
  "swell app release 2.0.0",
701
- "swell app release 2.0.0 --amend --release-notes ./releases/v2.0.0.md"
701
+ "swell app release 2.0.0 --amend --release-notes ./releases/v2.0.0.md",
702
+ "swell app release 2.0.0 -y"
702
703
  ],
703
704
  "flags": {
704
705
  "app-path": {
@@ -740,6 +741,13 @@
740
741
  "hasDynamicHelp": false,
741
742
  "multiple": false,
742
743
  "type": "option"
744
+ },
745
+ "yes": {
746
+ "char": "y",
747
+ "description": "skip confirmation prompt",
748
+ "name": "yes",
749
+ "allowNo": false,
750
+ "type": "boolean"
743
751
  }
744
752
  },
745
753
  "hasDynamicHelp": false,
@@ -770,7 +778,8 @@
770
778
  "examples": [
771
779
  "swell app version",
772
780
  "swell app version minor",
773
- "swell app version 1.0.0 -m \"First release\""
781
+ "swell app version 1.0.0 -m \"First release\"",
782
+ "swell app version patch -y"
774
783
  ],
775
784
  "flags": {
776
785
  "app-path": {
@@ -799,6 +808,13 @@
799
808
  "name": "no-git-tag",
800
809
  "allowNo": false,
801
810
  "type": "boolean"
811
+ },
812
+ "yes": {
813
+ "char": "y",
814
+ "description": "skip confirmation prompt",
815
+ "name": "yes",
816
+ "allowNo": false,
817
+ "type": "boolean"
802
818
  }
803
819
  },
804
820
  "hasDynamicHelp": false,
@@ -1841,5 +1857,5 @@
1841
1857
  ]
1842
1858
  }
1843
1859
  },
1844
- "version": "2.0.9"
1860
+ "version": "2.0.11"
1845
1861
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swell/cli",
3
- "version": "2.0.9",
3
+ "version": "2.0.11",
4
4
  "type": "module",
5
5
  "description": "Swell's command line interface/utility",
6
6
  "keywords": [