@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.
- package/dist/app-command.d.ts +1 -1
- package/dist/app-command.js +8 -8
- package/dist/commands/app/dev.d.ts +18 -0
- package/dist/commands/app/dev.js +31 -0
- package/dist/commands/app/frontend/deploy.d.ts +17 -0
- package/dist/commands/app/frontend/deploy.js +44 -0
- package/dist/commands/app/frontend/dev.d.ts +21 -0
- package/dist/commands/app/frontend/dev.js +111 -0
- package/dist/commands/app/info.js +15 -8
- package/dist/commands/app/init.d.ts +12 -0
- package/dist/commands/app/init.js +34 -0
- package/dist/commands/app/install.d.ts +4 -4
- package/dist/commands/app/install.js +37 -42
- package/dist/commands/app/pull.d.ts +15 -0
- package/dist/commands/app/pull.js +50 -0
- package/dist/commands/app/push.d.ts +11 -14
- package/dist/commands/app/push.js +71 -143
- package/dist/commands/app/release.d.ts +13 -0
- package/dist/commands/app/release.js +150 -0
- package/dist/commands/app/version.d.ts +7 -6
- package/dist/commands/app/version.js +64 -43
- package/dist/commands/app/watch.d.ts +2 -4
- package/dist/commands/app/watch.js +3 -83
- package/dist/commands/create/app.d.ts +35 -11
- package/dist/commands/create/app.js +150 -144
- package/dist/commands/create/content.d.ts +2 -2
- package/dist/commands/create/content.js +10 -10
- package/dist/commands/create/frontend.d.ts +12 -0
- package/dist/commands/create/frontend.js +41 -0
- package/dist/commands/create/function.d.ts +3 -3
- package/dist/commands/create/function.js +22 -22
- package/dist/commands/create/model.d.ts +2 -2
- package/dist/commands/create/model.js +11 -11
- package/dist/commands/create/notification.d.ts +4 -4
- package/dist/commands/create/notification.js +38 -40
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.js +12 -9
- package/dist/commands/logs.js +2 -1
- package/dist/commands/theme/dev.d.ts +23 -0
- package/dist/commands/theme/dev.js +167 -0
- package/dist/commands/theme/init.d.ts +9 -0
- package/dist/commands/theme/init.js +15 -0
- package/dist/commands/theme/pull.d.ts +20 -0
- package/dist/commands/theme/pull.js +65 -0
- package/dist/commands/theme/push.d.ts +19 -0
- package/dist/commands/theme/push.js +92 -0
- package/dist/create-app-command.d.ts +20 -0
- package/dist/create-app-command.js +254 -0
- package/dist/create-collection-command.d.ts +9 -9
- package/dist/create-collection-command.js +23 -23
- package/dist/{create-command.d.ts → create-config-command.d.ts} +1 -1
- package/dist/{create-command.js → create-config-command.js} +9 -7
- package/dist/lib/api.d.ts +6 -4
- package/dist/lib/api.js +58 -29
- package/dist/lib/app-config.d.ts +13 -5
- package/dist/lib/app-config.js +60 -23
- package/dist/lib/apps/app-config.d.ts +22 -8
- package/dist/lib/apps/app-config.js +202 -68
- package/dist/lib/apps/index.d.ts +93 -13
- package/dist/lib/apps/index.js +150 -50
- package/dist/lib/apps/paths.d.ts +14 -7
- package/dist/lib/apps/paths.js +73 -28
- package/dist/lib/bundle.js +4 -5
- package/dist/lib/config.d.ts +5 -1
- package/dist/lib/config.js +14 -0
- package/dist/lib/constants.d.ts +5 -0
- package/dist/lib/constants.js +22 -3
- package/dist/lib/create/content.d.ts +2 -2
- package/dist/lib/create/content.js +1 -1
- package/dist/lib/create/function.d.ts +2 -2
- package/dist/lib/create/function.js +2 -2
- package/dist/lib/create/index.d.ts +1 -1
- package/dist/lib/create/index.js +11 -7
- package/dist/lib/create/model.d.ts +2 -2
- package/dist/lib/create/notification.d.ts +2 -2
- package/dist/lib/info.js +2 -2
- package/dist/lib/sessions.js +2 -2
- package/dist/lib/stores.d.ts +5 -2
- package/dist/lib/stores.js +9 -6
- package/dist/lib/style.d.ts +2 -0
- package/dist/lib/style.js +2 -0
- package/dist/lib/swell-function-wrapper.d.ts +2 -2
- package/dist/lib/swell-function-wrapper.js +2 -2
- package/dist/push-app-command.d.ts +73 -0
- package/dist/push-app-command.js +765 -0
- package/dist/remote-app-command.d.ts +35 -9
- package/dist/remote-app-command.js +436 -164
- package/oclif.manifest.json +841 -125
- package/package.json +13 -1
- package/dist/commands/app/_pull.d.ts +0 -8
- package/dist/commands/app/_pull.js +0 -45
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export default class AppWatch extends
|
|
1
|
+
import { PushAppCommand } from '../../push-app-command.js';
|
|
2
|
+
export default class AppWatch extends PushAppCommand {
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
@@ -9,7 +9,5 @@ export default class AppWatch extends RemoteAppCommand {
|
|
|
9
9
|
env: string;
|
|
10
10
|
};
|
|
11
11
|
static summary: string;
|
|
12
|
-
private watchListener;
|
|
13
12
|
run(): Promise<void>;
|
|
14
|
-
private handleFileChange;
|
|
15
13
|
}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import { appConfigFileExists } from '../../lib/app-config.js';
|
|
5
|
-
import { appConfigFromFile, findAppConfig, getConfigTypeFromPath, hasAllowedFileExtension, } from '../../lib/apps/index.js';
|
|
6
|
-
import style from '../../lib/style.js';
|
|
7
|
-
import { RemoteAppCommand } from '../../remote-app-command.js';
|
|
8
|
-
export default class AppWatch extends RemoteAppCommand {
|
|
2
|
+
import { PushAppCommand } from '../../push-app-command.js';
|
|
3
|
+
export default class AppWatch extends PushAppCommand {
|
|
9
4
|
static description = `Watches configuration files including functions, and automatically pushes
|
|
10
5
|
to the remote store.
|
|
11
6
|
|
|
@@ -26,85 +21,10 @@ Optionally synchronize all configs on change.`;
|
|
|
26
21
|
env: 'test',
|
|
27
22
|
};
|
|
28
23
|
static summary = 'Watch for changes and push app configurations.';
|
|
29
|
-
watchListener = async (eventType, filename) => {
|
|
30
|
-
const configFile = filename;
|
|
31
|
-
const pathParsed = path.parse(configFile);
|
|
32
|
-
const fileDirs = pathParsed.dir.split(path.sep);
|
|
33
|
-
// only the first directory is relevant for us
|
|
34
|
-
const configDir = fileDirs[0];
|
|
35
|
-
// we only want to watch files in the root of the app directory
|
|
36
|
-
// and with the allowed extensions
|
|
37
|
-
if (!configDir ||
|
|
38
|
-
fileDirs.length > 1 ||
|
|
39
|
-
!hasAllowedFileExtension(configFile)) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
const configType = getConfigTypeFromPath(configDir);
|
|
43
|
-
if (!configType) {
|
|
44
|
-
this.debug(`watchListener: ${filename} is not a valid config type`);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
let watchFileEvent;
|
|
48
|
-
// per node docs:
|
|
49
|
-
//
|
|
50
|
-
// On most platforms, 'rename' is emitted whenever a filename appears
|
|
51
|
-
// or disappears in the directory.
|
|
52
|
-
//
|
|
53
|
-
// we want however to identify delete file events so we can send the
|
|
54
|
-
// correct API request
|
|
55
|
-
if (eventType === 'rename') {
|
|
56
|
-
watchFileEvent = 'new';
|
|
57
|
-
if (!appConfigFileExists(path.join(this.appPath, configFile))) {
|
|
58
|
-
watchFileEvent = 'deleted';
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
watchFileEvent = 'change';
|
|
63
|
-
}
|
|
64
|
-
try {
|
|
65
|
-
await this.handleFileChange(configFile, configType, watchFileEvent);
|
|
66
|
-
}
|
|
67
|
-
catch (error) {
|
|
68
|
-
// we don't want to break the watcher if an error is thrown while
|
|
69
|
-
// handling a file change
|
|
70
|
-
this.debug(error);
|
|
71
|
-
// for tests though, we want to break the watcher
|
|
72
|
-
if (process.env.NODE_ENV === 'test') {
|
|
73
|
-
// throwing does not break the test so we need to hard exit and log
|
|
74
|
-
// the error
|
|
75
|
-
console.error(style.error(error));
|
|
76
|
-
// eslint-disable-next-line no-process-exit, unicorn/no-process-exit
|
|
77
|
-
process.exit(1);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
// refetch app to get updated configs
|
|
81
|
-
this.app = await this.getAppWithConfig(this.app.id);
|
|
82
|
-
};
|
|
83
24
|
async run() {
|
|
84
25
|
const { flags } = await this.parse(AppWatch);
|
|
85
26
|
this.app = await this.getAppWithConfig();
|
|
86
27
|
this.log('Watching for changes...');
|
|
87
|
-
|
|
88
|
-
await this.syncAppConfigs();
|
|
89
|
-
fs.watch(this.appPath, { recursive: true }, async (eventType, filename) => {
|
|
90
|
-
if (filename && hasAllowedFileExtension(filename)) {
|
|
91
|
-
await this.syncAppConfigs();
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
fs.watch(this.appPath, { recursive: true }, this.watchListener);
|
|
97
|
-
}
|
|
98
|
-
async handleFileChange(configFile, configType, event) {
|
|
99
|
-
if (event === 'deleted') {
|
|
100
|
-
const appConfig = findAppConfig(this.app, configFile, configType);
|
|
101
|
-
if (!appConfig) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
return this.removeConfig(appConfig);
|
|
105
|
-
}
|
|
106
|
-
const appConfig = appConfigFromFile(path.join(this.appPath, configFile), configType);
|
|
107
|
-
const result = await this.pushConfigFile(appConfig);
|
|
108
|
-
this.debug(`handleFileChange: ${configFile} pushed`, result);
|
|
28
|
+
await this.watchForChanges({ syncAll: flags['sync-all'] });
|
|
109
29
|
}
|
|
110
30
|
}
|
|
@@ -1,21 +1,45 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export default class CreateApp extends
|
|
1
|
+
import { CreateAppCommand } from '../../create-app-command.js';
|
|
2
|
+
export default class CreateApp extends CreateAppCommand {
|
|
3
|
+
appType: string;
|
|
3
4
|
static args: {
|
|
4
5
|
id: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
5
6
|
};
|
|
6
|
-
static flags: {
|
|
7
|
-
pkg: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
8
|
-
yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
9
|
-
};
|
|
10
7
|
static description: string;
|
|
11
8
|
static examples: {
|
|
12
9
|
command: string;
|
|
13
10
|
description: string;
|
|
14
11
|
}[];
|
|
12
|
+
static flags: any;
|
|
15
13
|
run(): Promise<void>;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
createSwellConfig({ inputId, inputYes, inputType, inputStorefrontApp, allowOverwrite, nestedPath, }: {
|
|
15
|
+
inputId: string;
|
|
16
|
+
inputYes?: boolean;
|
|
17
|
+
inputType?: string;
|
|
18
|
+
inputStorefrontApp?: string;
|
|
19
|
+
allowOverwrite?: boolean;
|
|
20
|
+
nestedPath?: boolean;
|
|
21
|
+
}): Promise<{
|
|
22
|
+
appId: string;
|
|
23
|
+
swellConfigJson: {
|
|
24
|
+
permissions: never[];
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
description: string;
|
|
28
|
+
type: string;
|
|
29
|
+
version: string;
|
|
30
|
+
} | {
|
|
31
|
+
theme: {
|
|
32
|
+
storefront: {
|
|
33
|
+
app: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
description: string;
|
|
39
|
+
type: string;
|
|
40
|
+
version: string;
|
|
41
|
+
};
|
|
42
|
+
config: any;
|
|
43
|
+
installedStorefrontApp: any;
|
|
44
|
+
} | undefined>;
|
|
21
45
|
}
|
|
@@ -1,35 +1,20 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import { exec } from 'child_process';
|
|
3
|
-
import { promisify } from 'util';
|
|
4
1
|
import { confirm, input, select } from '@inquirer/prompts';
|
|
5
2
|
import { Args, Flags } from '@oclif/core';
|
|
3
|
+
import path from 'node:path';
|
|
6
4
|
import ora from 'ora';
|
|
7
|
-
import {
|
|
5
|
+
import { swellConfigFileExists, newConfig } from '../../lib/app-config.js';
|
|
6
|
+
import { toAppId, toAppName } from '../../lib/create/index.js';
|
|
8
7
|
import style from '../../lib/style.js';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const execAsync = promisify(exec);
|
|
13
|
-
export default class CreateApp extends SwellCommand {
|
|
8
|
+
import { CreateAppCommand } from '../../create-app-command.js';
|
|
9
|
+
export default class CreateApp extends CreateAppCommand {
|
|
10
|
+
appType = '';
|
|
14
11
|
static args = {
|
|
15
12
|
id: Args.string({
|
|
16
13
|
default: '',
|
|
17
14
|
description: `id of the app to create`,
|
|
18
15
|
}),
|
|
19
16
|
};
|
|
20
|
-
static
|
|
21
|
-
pkg: Flags.string({
|
|
22
|
-
char: 'p',
|
|
23
|
-
default: 'npm',
|
|
24
|
-
description: `use npm or yarn to install default dependencies, or none to disable`,
|
|
25
|
-
options: ['npm', 'yarn', 'none'],
|
|
26
|
-
}),
|
|
27
|
-
yes: Flags.boolean({
|
|
28
|
-
char: 'y',
|
|
29
|
-
description: `accept all default values`,
|
|
30
|
-
}),
|
|
31
|
-
};
|
|
32
|
-
static description = 'Initialize an app with config file and folder structure.';
|
|
17
|
+
static description = 'Create an app.';
|
|
33
18
|
static examples = [
|
|
34
19
|
{
|
|
35
20
|
command: 'swell create app',
|
|
@@ -48,63 +33,173 @@ export default class CreateApp extends SwellCommand {
|
|
|
48
33
|
description: 'Create app without installing TypeScript bindings, etc.',
|
|
49
34
|
},
|
|
50
35
|
];
|
|
36
|
+
static flags = {
|
|
37
|
+
type: Flags.string({
|
|
38
|
+
char: 't',
|
|
39
|
+
description: `create a specific app type`,
|
|
40
|
+
options: ['admin', 'integration', 'storefront', 'theme'],
|
|
41
|
+
}),
|
|
42
|
+
pkg: Flags.string({
|
|
43
|
+
char: 'p',
|
|
44
|
+
default: 'npm',
|
|
45
|
+
description: `use npm or yarn to install default dependencies, or none to disable`,
|
|
46
|
+
options: ['npm', 'yarn', 'none'],
|
|
47
|
+
}),
|
|
48
|
+
};
|
|
51
49
|
async run() {
|
|
52
50
|
const { args, flags } = await this.parse(CreateApp);
|
|
53
51
|
const { id } = args;
|
|
54
52
|
const { pkg, yes } = flags;
|
|
55
|
-
let confirmYes = yes && id;
|
|
53
|
+
let confirmYes = Boolean(yes && id);
|
|
54
|
+
const createParams = await this.createSwellConfig({
|
|
55
|
+
inputId: id,
|
|
56
|
+
inputYes: confirmYes,
|
|
57
|
+
inputType: flags['type'],
|
|
58
|
+
inputStorefrontApp: flags['storefront-app'],
|
|
59
|
+
});
|
|
60
|
+
if (!createParams) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const { appId, config, installedStorefrontApp } = createParams;
|
|
64
|
+
!confirmYes && this.log();
|
|
65
|
+
const spinner = ora();
|
|
66
|
+
spinner.start('Creating app...');
|
|
67
|
+
if (pkg !== 'none') {
|
|
68
|
+
await this.tryPackageSetup(appId, config, pkg);
|
|
69
|
+
}
|
|
70
|
+
await this.createAppConfigFolders(config);
|
|
71
|
+
spinner.succeed(`${style.appConfigValue(config.get('name'))} app created.\n`);
|
|
72
|
+
let createdFrontend, createdTheme;
|
|
73
|
+
if (installedStorefrontApp) {
|
|
74
|
+
createdTheme = await this.createThemeApp(config, flags, installedStorefrontApp);
|
|
75
|
+
}
|
|
76
|
+
else if (config.get('type') === 'storefront') {
|
|
77
|
+
createdFrontend = await this.createStorefrontApp(config, flags);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
createdFrontend = await this.createFrontendApp(config, flags);
|
|
81
|
+
}
|
|
82
|
+
this.log('\nNext steps:');
|
|
83
|
+
this.log(`Run ${style.command('swell app push')} to push configurations to your test store.`);
|
|
84
|
+
this.log(`Run ${style.command('swell app install')} to install the app in another store or environment.`);
|
|
85
|
+
if (createdFrontend) {
|
|
86
|
+
this.log(`Run ${style.command('swell app frontend dev')} to start a local dev server for your frontend app.`);
|
|
87
|
+
}
|
|
88
|
+
else if (createdTheme) {
|
|
89
|
+
this.log(`Run ${style.command('swell app theme dev')} to start a local dev server for your theme.`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async createSwellConfig({ inputId, inputYes, inputType, inputStorefrontApp, allowOverwrite = true, nestedPath = true, }) {
|
|
93
|
+
let confirmYes = inputYes;
|
|
94
|
+
const type = inputType ||
|
|
95
|
+
(confirmYes
|
|
96
|
+
? 'admin'
|
|
97
|
+
: await select({
|
|
98
|
+
choices: [
|
|
99
|
+
{ name: 'Admin', value: 'admin' },
|
|
100
|
+
{ name: 'Integration', value: 'integration' },
|
|
101
|
+
{ name: 'Storefront', value: 'storefront' },
|
|
102
|
+
{ name: 'Theme', value: 'theme' },
|
|
103
|
+
],
|
|
104
|
+
message: `What is the primary purpose of the app?`,
|
|
105
|
+
}));
|
|
106
|
+
const typeLabel = type === 'theme' ? 'theme' : 'app';
|
|
107
|
+
const typeLabelTitle = type === 'theme' ? 'Theme' : 'App';
|
|
56
108
|
const name = confirmYes
|
|
57
|
-
? toAppName(
|
|
109
|
+
? toAppName(inputId)
|
|
58
110
|
: await input({
|
|
59
|
-
|
|
60
|
-
|
|
111
|
+
default: inputId ? toAppName(inputId) : '',
|
|
112
|
+
message: `${typeLabelTitle} name`,
|
|
61
113
|
validate: (answer) => answer.length > 2,
|
|
62
114
|
});
|
|
63
|
-
let appId = toAppId(
|
|
115
|
+
let appId = toAppId(inputId || '');
|
|
64
116
|
if (!appId) {
|
|
65
117
|
appId = await input({
|
|
66
|
-
message: 'App ID',
|
|
67
118
|
default: toAppId(name),
|
|
119
|
+
message: `${typeLabelTitle} ID`,
|
|
68
120
|
validate: (answer) => answer.length > 2,
|
|
69
121
|
});
|
|
70
122
|
appId = toAppId(appId);
|
|
71
|
-
confirmYes =
|
|
123
|
+
confirmYes = Boolean(inputYes && appId);
|
|
72
124
|
}
|
|
125
|
+
const version = confirmYes
|
|
126
|
+
? '1.0.0'
|
|
127
|
+
: await input({
|
|
128
|
+
default: '1.0.0',
|
|
129
|
+
message: `${typeLabelTitle} version`,
|
|
130
|
+
});
|
|
73
131
|
const description = confirmYes
|
|
74
132
|
? ''
|
|
75
133
|
: await input({
|
|
76
|
-
message: 'Describe what the app does',
|
|
77
134
|
default: 'Something special',
|
|
135
|
+
message: `Describe your ${typeLabel}`,
|
|
78
136
|
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
137
|
+
let storefrontInstalledApps;
|
|
138
|
+
let storefrontAppId;
|
|
139
|
+
let installedStorefrontApp;
|
|
140
|
+
if (type === 'theme') {
|
|
141
|
+
storefrontInstalledApps = await this.getInstalledStorefrontApps();
|
|
142
|
+
if (storefrontInstalledApps === false) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
storefrontAppId =
|
|
146
|
+
inputStorefrontApp || (storefrontInstalledApps.length > 1
|
|
147
|
+
? (await select({
|
|
148
|
+
choices: [
|
|
149
|
+
...storefrontInstalledApps.map(({ id, app }) => ({
|
|
150
|
+
name: app.name,
|
|
151
|
+
value: id,
|
|
152
|
+
})),
|
|
153
|
+
],
|
|
154
|
+
message: `Which storefront app is your theme for?`,
|
|
155
|
+
}))
|
|
156
|
+
: storefrontInstalledApps[0].id);
|
|
157
|
+
installedStorefrontApp = storefrontInstalledApps.find((installedApp) => inputStorefrontApp
|
|
158
|
+
? inputStorefrontApp === installedApp.app_private_id ||
|
|
159
|
+
inputStorefrontApp === installedApp.app_public_id ||
|
|
160
|
+
inputStorefrontApp === installedApp.app_id ||
|
|
161
|
+
inputStorefrontApp === toAppId(installedApp.app_private_id)
|
|
162
|
+
: installedApp.id === storefrontAppId);
|
|
163
|
+
if (!installedStorefrontApp) {
|
|
164
|
+
this.error(`Could not find an installed storefront app by id: ${storefrontAppId}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const swellConfigJson = {
|
|
90
168
|
id: appId,
|
|
91
|
-
version: '1.0.0',
|
|
92
169
|
name,
|
|
93
170
|
description,
|
|
94
171
|
type,
|
|
95
|
-
|
|
172
|
+
version,
|
|
173
|
+
...(type !== 'theme'
|
|
174
|
+
? {
|
|
175
|
+
permissions: [],
|
|
176
|
+
}
|
|
177
|
+
: {
|
|
178
|
+
theme: {
|
|
179
|
+
storefront: {
|
|
180
|
+
app: toAppId(installedStorefrontApp.app_private_id),
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
}),
|
|
96
184
|
};
|
|
97
|
-
const
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
185
|
+
const appPath = path.join(process.cwd(), appId);
|
|
186
|
+
if (swellConfigFileExists(appPath)) {
|
|
187
|
+
if (allowOverwrite) {
|
|
188
|
+
if (!confirmYes) {
|
|
189
|
+
const continueCreateApp = await confirm({
|
|
190
|
+
message: `An app already exists in the target path ${appPath}. Overwrite?`,
|
|
191
|
+
});
|
|
192
|
+
if (!continueCreateApp) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
this.error(`An app already exists in the target path ${appPath}.`);
|
|
104
199
|
}
|
|
105
200
|
}
|
|
106
|
-
this.log(`\nCreating app ${style.appConfigValue(name)} in ${
|
|
107
|
-
this.log(`\n${JSON.stringify(
|
|
201
|
+
this.log(`\nCreating ${this.appType === 'theme' ? 'theme' : 'app'} ${style.appConfigValue(name)} in ${appPath}/swell.json`);
|
|
202
|
+
this.log(`\n${JSON.stringify(swellConfigJson, null, 2)}\n`);
|
|
108
203
|
const confirmCreateApp = confirmYes
|
|
109
204
|
? true
|
|
110
205
|
: await confirm({
|
|
@@ -113,98 +208,9 @@ export default class CreateApp extends SwellCommand {
|
|
|
113
208
|
if (!confirmCreateApp) {
|
|
114
209
|
return;
|
|
115
210
|
}
|
|
116
|
-
|
|
117
|
-
const spinner = ora();
|
|
118
|
-
spinner.start('Creating app...');
|
|
211
|
+
const config = newConfig(nestedPath ? appId : '');
|
|
119
212
|
config.clear();
|
|
120
|
-
config.set(
|
|
121
|
-
|
|
122
|
-
await this.tryPackageSetup(appId, config, pkg);
|
|
123
|
-
}
|
|
124
|
-
await this.createAppConfigFolders(config);
|
|
125
|
-
spinner.succeed(`${style.appConfigValue(name)} app created.`);
|
|
126
|
-
this.log('\nNext steps:');
|
|
127
|
-
this.log(`Run ${style.command('swell app push')} to push configurations to your test store.`);
|
|
128
|
-
this.log(`Run ${style.command('swell app install')} to install the app in another store or environment.`);
|
|
129
|
-
}
|
|
130
|
-
async tryPackageSetup(name, config, pkg) {
|
|
131
|
-
try {
|
|
132
|
-
await this.setupPackage(name, config, pkg);
|
|
133
|
-
}
|
|
134
|
-
catch (err) {
|
|
135
|
-
this.log(`There was an error setting up the package manager: ${err.message}`);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
async setupPackage(name, config, pkg) {
|
|
139
|
-
const execAsync = promisify(exec);
|
|
140
|
-
const packageJson = {
|
|
141
|
-
name,
|
|
142
|
-
version: config.get('version'),
|
|
143
|
-
description: config.get('description'),
|
|
144
|
-
scripts: {},
|
|
145
|
-
devDependencies: {
|
|
146
|
-
'@swell/app-types': '^1.0.5',
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
const tsConfig = {
|
|
150
|
-
compilerOptions: {
|
|
151
|
-
target: 'esnext',
|
|
152
|
-
module: 'esnext',
|
|
153
|
-
lib: ['esnext', 'webworker'],
|
|
154
|
-
types: ['@swell/app-types'],
|
|
155
|
-
},
|
|
156
|
-
include: ['**/*.ts'],
|
|
157
|
-
exclude: ['node_modules'],
|
|
158
|
-
};
|
|
159
|
-
await writeJsonFile(path.join(path.dirname(config.path), 'package.json'), packageJson);
|
|
160
|
-
await writeJsonFile(path.join(path.dirname(config.path), 'tsconfig.json'), tsConfig);
|
|
161
|
-
try {
|
|
162
|
-
const packageManager = await this.findPackageManager(pkg);
|
|
163
|
-
await execAsync(`${packageManager} install`, {
|
|
164
|
-
cwd: path.dirname(config.path),
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
catch (err) {
|
|
168
|
-
this.error(err.message);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
async findPackageManager(pkg) {
|
|
172
|
-
let packageManager = pkg ? pkg : '';
|
|
173
|
-
// Determine if system has yarn or npm install
|
|
174
|
-
if (packageManager) {
|
|
175
|
-
if (await this.doesPackageManagerExist(packageManager)) {
|
|
176
|
-
return packageManager;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
if (await this.doesPackageManagerExist('npm')) {
|
|
181
|
-
return 'npm';
|
|
182
|
-
}
|
|
183
|
-
else if (await this.doesPackageManagerExist('yarn')) {
|
|
184
|
-
return 'yarn';
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
async doesPackageManagerExist(packageManager) {
|
|
189
|
-
try {
|
|
190
|
-
await execAsync(`${packageManager} --version`);
|
|
191
|
-
return true;
|
|
192
|
-
}
|
|
193
|
-
catch (err) {
|
|
194
|
-
this.debug(`Could not find ${packageManager} on your system. Please install ${packageManager} and try again.`);
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
async createAppConfigFolders(config) {
|
|
199
|
-
for (const type of getAllConfigPaths()) {
|
|
200
|
-
// Create a config folder
|
|
201
|
-
await execAsync(`mkdir -p ${type}`, {
|
|
202
|
-
cwd: path.dirname(config.path),
|
|
203
|
-
});
|
|
204
|
-
// Create gitkeep file
|
|
205
|
-
await execAsync(`touch ${path.join(type, '.gitkeep')}`, {
|
|
206
|
-
cwd: path.dirname(config.path),
|
|
207
|
-
});
|
|
208
|
-
}
|
|
213
|
+
config.set(swellConfigJson);
|
|
214
|
+
return { appId, swellConfigJson, config, installedStorefrontApp };
|
|
209
215
|
}
|
|
210
216
|
}
|
|
@@ -7,11 +7,11 @@ export default class CreateContent extends CreateCollectionCommand {
|
|
|
7
7
|
description: string;
|
|
8
8
|
}[];
|
|
9
9
|
static flags: {
|
|
10
|
-
label: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
11
10
|
description: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
12
11
|
fields: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
13
|
-
|
|
12
|
+
label: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
14
13
|
overwrite: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
14
|
+
views: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
15
15
|
};
|
|
16
16
|
static summary: string;
|
|
17
17
|
createType: ConfigType;
|
|
@@ -25,11 +25,6 @@ export default class CreateContent extends CreateCollectionCommand {
|
|
|
25
25
|
},
|
|
26
26
|
];
|
|
27
27
|
static flags = {
|
|
28
|
-
label: Flags.string({
|
|
29
|
-
char: 'l',
|
|
30
|
-
default: '',
|
|
31
|
-
description: 'content model label',
|
|
32
|
-
}),
|
|
33
28
|
description: Flags.string({
|
|
34
29
|
char: 'd',
|
|
35
30
|
default: '',
|
|
@@ -40,21 +35,26 @@ export default class CreateContent extends CreateCollectionCommand {
|
|
|
40
35
|
default: '',
|
|
41
36
|
description: 'list of content model fields delimited by commas',
|
|
42
37
|
}),
|
|
43
|
-
|
|
44
|
-
char: '
|
|
38
|
+
label: Flags.string({
|
|
39
|
+
char: 'l',
|
|
45
40
|
default: '',
|
|
46
|
-
description: '
|
|
41
|
+
description: 'content model label',
|
|
47
42
|
}),
|
|
48
43
|
overwrite: Flags.boolean({
|
|
49
44
|
default: false,
|
|
50
45
|
description: 'overwrite existing content model configuration file',
|
|
51
46
|
}),
|
|
47
|
+
views: Flags.string({
|
|
48
|
+
char: 'v',
|
|
49
|
+
default: '',
|
|
50
|
+
description: 'list of content model views delimited by commas, i.e. list,edit,new',
|
|
51
|
+
}),
|
|
52
52
|
};
|
|
53
53
|
static summary = 'Initialize a content UI model config file with properties in the content folder.';
|
|
54
54
|
createType = ConfigType.CONTENT;
|
|
55
55
|
async run() {
|
|
56
56
|
const { flags } = await this.parse(CreateContent);
|
|
57
|
-
const {
|
|
57
|
+
const { collection, description, label } = await this.promptCollection();
|
|
58
58
|
const fileName = toFileName(collection);
|
|
59
59
|
const fileBody = {
|
|
60
60
|
collection,
|
|
@@ -70,12 +70,12 @@ export default class CreateContent extends CreateCollectionCommand {
|
|
|
70
70
|
}
|
|
71
71
|
else {
|
|
72
72
|
const viewsInput = await checkbox({
|
|
73
|
-
message: 'Which views does your content have?',
|
|
74
73
|
choices: [
|
|
75
74
|
{ name: 'List view', value: 'list' },
|
|
76
75
|
{ name: 'Edit view', value: 'edit' },
|
|
77
76
|
{ name: 'New view', value: 'new' },
|
|
78
77
|
],
|
|
78
|
+
message: 'Which views does your content have?',
|
|
79
79
|
});
|
|
80
80
|
fileBody.views = parseViews(viewsInput);
|
|
81
81
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CreateAppCommand } from '../../create-app-command.js';
|
|
2
|
+
export default class CreateFrontend extends CreateAppCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: {
|
|
5
|
+
command: string;
|
|
6
|
+
description: string;
|
|
7
|
+
}[];
|
|
8
|
+
static flags: {
|
|
9
|
+
pkg: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import swellConfig from '../../lib/app-config.js';
|
|
4
|
+
import { CreateAppCommand } from '../../create-app-command.js';
|
|
5
|
+
export default class CreateFrontend extends CreateAppCommand {
|
|
6
|
+
static description = 'Initialize a frontend app framework and folder structure.';
|
|
7
|
+
static examples = [
|
|
8
|
+
{
|
|
9
|
+
command: 'swell create frontend',
|
|
10
|
+
description: 'Create frontend app following command prompts.',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
command: 'swell create frontend -y',
|
|
14
|
+
description: 'Create frontend app and accept all default values.',
|
|
15
|
+
},
|
|
16
|
+
];
|
|
17
|
+
static flags = {
|
|
18
|
+
pkg: Flags.string({
|
|
19
|
+
char: 'p',
|
|
20
|
+
default: 'npm',
|
|
21
|
+
description: `use npm or yarn to install default dependencies, or none to disable`,
|
|
22
|
+
options: ['npm', 'yarn', 'none'],
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
async run() {
|
|
26
|
+
const { flags } = await this.parse(CreateFrontend);
|
|
27
|
+
const newSwellConfig = swellConfig();
|
|
28
|
+
const appType = newSwellConfig?.get('type');
|
|
29
|
+
const spinner = ora();
|
|
30
|
+
if (appType === 'theme') {
|
|
31
|
+
spinner.fail(`You can't create app frontend in a theme.`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (appType === 'storefront') {
|
|
35
|
+
await this.createStorefrontApp(newSwellConfig, flags, true);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
await this.createFrontendApp(newSwellConfig, flags, true);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CreateConfigCommand } from '../../create-config-command.js';
|
|
2
2
|
import { ConfigType } from '../../lib/apps/index.js';
|
|
3
|
-
export default class CreateFunction extends
|
|
3
|
+
export default class CreateFunction extends CreateConfigCommand {
|
|
4
4
|
static args: {
|
|
5
5
|
functionName: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
|
|
6
6
|
trigger: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
|
|
@@ -13,9 +13,9 @@ export default class CreateFunction extends CreateCommand {
|
|
|
13
13
|
static flags: {
|
|
14
14
|
description: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
15
15
|
events: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
16
|
+
overwrite: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
16
17
|
route: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
17
18
|
schedule: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
18
|
-
overwrite: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
19
19
|
};
|
|
20
20
|
static summary: string;
|
|
21
21
|
createType: ConfigType;
|