Skip to content

Commit 207b6a5

Browse files
committed
feat: merged SDK CLI to the original CLI
1 parent dc4572d commit 207b6a5

40 files changed

+1075
-18
lines changed

packages/cli/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
"os-locale": "^5.0.0",
3535
"picocolors": "^1.0.0",
3636
"reasonable-filename": "^1.2.0",
37-
"rimraf": "^3.0.2"
37+
"rimraf": "^3.0.2",
38+
"ts-morph": "^18.0.0"
3839
},
3940
"devDependencies": {
4041
"@types/i18next-fs-backend": "^1.1.2",
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Command } from '@oclif/core';
2+
import { existsDirectory } from '../../utils';
3+
import { makeMethod } from '../../domains/add/endpoint';
4+
import { endpointName } from '../../domains/add/endpoint/helpers';
5+
import { note } from '@clack/prompts';
6+
7+
export default class AddEndpoint extends Command {
8+
static override description = 'Create new endpoint boilerplate code';
9+
static override examples = ['<%= config.bin %> <%= command.id %>'];
10+
static override flags = {};
11+
static override args = [
12+
{
13+
name: 'name',
14+
description: 'Name of the endpoint',
15+
}
16+
];
17+
18+
async run(): Promise<void> {
19+
const { args } = await this.parse(AddEndpoint);
20+
let { name } = args;
21+
22+
if (!name) {
23+
name = await endpointName();
24+
}
25+
26+
// check if folder packages and playground exists in the current directory
27+
const isPackagesDirExists = await existsDirectory('packages');
28+
const isPlaygroundDirExists = await existsDirectory('playground');
29+
30+
if (isPackagesDirExists && isPlaygroundDirExists) {
31+
await makeMethod(name);
32+
} else {
33+
note('Please run this command in the root directory of the SDK Integration Boilerplate!');
34+
}
35+
36+
process.exit(0);
37+
}
38+
}
+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { Command } from '@oclif/core';
2+
import AddEndpoint from './endpoint';
3+
import { checkCommandAndSuggest, log } from '../../utils';
4+
import picocolors from 'picocolors';
5+
6+
const EXISTING_COMMANDS = [
7+
{
8+
command: 'endpoint',
9+
Func: AddEndpoint
10+
}
11+
];
12+
13+
export default class Add extends Command {
14+
static override description = 'Create new endpoint boilerplate code';
15+
static override examples = ['@vue-storefront/cli add <command> <endpoint>'];
16+
static override flags = {};
17+
static override args = [
18+
{
19+
name: 'commandArg',
20+
description: 'Name of the command'
21+
},
22+
{
23+
name: 'endpoint',
24+
description: 'Name of the endpoint'
25+
}
26+
];
27+
28+
async run(): Promise<void> {
29+
const { args } = await this.parse(Add);
30+
const { commandArg, endpoint } = args;
31+
32+
await checkCommandAndSuggest({
33+
commands: EXISTING_COMMANDS,
34+
commandArg,
35+
endpoint,
36+
self: this
37+
});
38+
39+
log(
40+
`Command ${picocolors.green(
41+
'add'
42+
)} require additional arguments. Please run ${picocolors.green(
43+
'@vue-storefront/cli add --help'
44+
)} to see available options.\n`
45+
);
46+
47+
process.exit(0);
48+
}
49+
}
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Command, Flags } from '@oclif/core';
2+
import { checkCommandAndQuit, log } from '../../utils';
3+
import picocolors from 'picocolors';
4+
5+
const EXISTING_COMMANDS = ['integration'];
6+
7+
export default class Create extends Command {
8+
static override description = 'Generate integration boilerplate';
9+
static override examples = ['<%= config.bin %> <%= command.id %>'];
10+
static override flags = {
11+
framework: Flags.string({
12+
char: 't',
13+
description: 'Framework to use',
14+
options: ['nuxt', 'next'],
15+
aliases: ['template']
16+
})
17+
};
18+
19+
static override args = [
20+
{
21+
name: 'commandName'
22+
},
23+
{
24+
name: 'integrationName'
25+
}
26+
];
27+
28+
async run(): Promise<void> {
29+
const { args } = await this.parse(Create);
30+
const { commandName } = args;
31+
32+
checkCommandAndQuit({
33+
commands: EXISTING_COMMANDS,
34+
commandName
35+
});
36+
37+
log(
38+
`Command ${picocolors.green(
39+
'create'
40+
)} require additional arguments. Please run ${picocolors.green(
41+
'@vue-storefront/cli create --help'
42+
)} to see available options.\n`
43+
);
44+
45+
process.exit(0);
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { Command, Flags } from '@oclif/core';
2+
import { createIntegrationBoilerplate } from '../../domains/create/integration';
3+
import { getPkgManager, log } from '../../utils';
4+
import {
5+
handleDirectoryName,
6+
handleFrameworkName,
7+
installAppSdkDependencies,
8+
cleanUpRepositories
9+
} from '../../domains/create/integration/helpers';
10+
11+
import { intro, spinner } from '@clack/prompts';
12+
import execa from 'execa';
13+
import picocolors from 'picocolors';
14+
15+
export default class GenerateSDK extends Command {
16+
static override description = 'Generate integration boilerplate';
17+
static override examples = ['<%= config.bin %> <%= command.id %>'];
18+
static override flags = {
19+
framework: Flags.string({
20+
char: 't',
21+
description: 'Framework to use',
22+
options: ['nuxt', 'next'],
23+
aliases: ['template']
24+
})
25+
};
26+
27+
static override args = [
28+
{
29+
name: 'name'
30+
}
31+
];
32+
33+
async run(): Promise<void> {
34+
let projectDir = '';
35+
let framework = '';
36+
const sp = spinner();
37+
38+
const { flags } = await this.parse(GenerateSDK);
39+
if (flags.framework) {
40+
framework = flags.framework;
41+
}
42+
const { args } = await this.parse(GenerateSDK);
43+
// eslint-disable-next-line dot-notation
44+
if (args['name']) {
45+
// eslint-disable-next-line dot-notation
46+
projectDir = args['name'];
47+
}
48+
// greet the user
49+
intro('Welcome to Vue Storefront SDK Integration Boilerplate Generator!');
50+
51+
projectDir = await handleDirectoryName(projectDir);
52+
framework = await handleFrameworkName(framework);
53+
const packageManager = await getPkgManager();
54+
55+
await createIntegrationBoilerplate({ projectDir, framework });
56+
await installAppSdkDependencies(projectDir, packageManager);
57+
58+
// build the boilerplate
59+
sp.start('Building the boilerplate');
60+
await execa(packageManager, ['run', 'build'], { cwd: projectDir });
61+
sp.stop('Boilerplate has been built successfully!');
62+
// clean up the git repository
63+
await cleanUpRepositories(projectDir);
64+
65+
// exit the generator
66+
log('SDK integration boilerplate has been generated successfully!');
67+
log('To start the development, run the following commands:');
68+
log(picocolors.green(`cd ${projectDir}`));
69+
log(
70+
picocolors.green(
71+
`${packageManager === 'yarn' ? 'yarn dev' : 'npm run dev'}`
72+
)
73+
);
74+
process.exit(0);
75+
}
76+
}

packages/cli/src/commands/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { run } from '@oclif/core';

packages/cli/src/commands/init.ts

-17
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import fs from 'fs'
2+
import { existsDirectory } from '../../../../../utils';
3+
import { getNextPageCode } from '..';
4+
5+
export const writeNextPageMethod = async (endpoint: string) => {
6+
const nextPagesPath = './playground/app/src/pages/methods';
7+
8+
const folderExists = await existsDirectory(nextPagesPath);
9+
10+
if (!folderExists) {
11+
fs.mkdirSync(nextPagesPath, { recursive: true });
12+
}
13+
14+
const ifPageExists = fs.existsSync(`${nextPagesPath}/${endpoint}.tsx`);
15+
16+
if (ifPageExists) {
17+
fs.rmSync(`${nextPagesPath}/${endpoint}.tsx`, { recursive: true });
18+
}
19+
20+
fs.writeFileSync(`${nextPagesPath}/${endpoint}.tsx`, getNextPageCode(endpoint));
21+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import fs from 'fs'
2+
import { existsDirectory } from '../../../../../utils';
3+
import { getNuxtPageCode } from '..';
4+
5+
export const writeNuxtPageMethod = async (endpoint: string) => {
6+
const nuxtPagesPath = './playground/app/pages';
7+
8+
const folderExists = await existsDirectory(nuxtPagesPath);
9+
10+
if (!folderExists) {
11+
fs.mkdirSync(nuxtPagesPath, { recursive: true });
12+
}
13+
14+
const ifPageExists = fs.existsSync(`${nuxtPagesPath}/${endpoint}.tsx`);
15+
16+
if (ifPageExists) {
17+
fs.rmSync(`${nuxtPagesPath}/${endpoint}.tsx`, { recursive: true });
18+
}
19+
20+
fs.writeFileSync(`${nuxtPagesPath}/${endpoint}.vue`, getNuxtPageCode(endpoint));
21+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export const getApiMethodCode = (endpoint: string) => `import { Endpoints } from '../../types';
2+
3+
export const ${endpoint}: Endpoints['${endpoint}'] = async (
4+
context,
5+
params
6+
) => {
7+
console.log('${endpoint} has been called');
8+
9+
return { data: 'Hello from ${endpoint} endpoint!' };
10+
};
11+
`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { capitalizeFirst } from '../../../../../utils/capitalizeFirst';
2+
3+
export const getNextPageCode = (endpoint: string) => `import { useState } from 'react';
4+
import { sdk } from '@/pages/_app';
5+
import { SfButton } from '@storefront-ui/react';
6+
import { RenderJson } from '@/components/RenderJson';
7+
8+
export default function Page${capitalizeFirst(endpoint)}() {
9+
const [data, setData] = useState<null | Object>(null);
10+
11+
const hitExampleMethodApi = async () => {
12+
const data = await sdk.boilerplate.${endpoint}('test');
13+
14+
setData(data);
15+
};
16+
17+
return (
18+
<>
19+
<main className="flex flex-col items-center py-24 gap-12 text-white">
20+
<SfButton type="button" onClick={hitExampleMethodApi}>
21+
Call ${endpoint}
22+
</SfButton>
23+
24+
<div className="w-[500px] h-min-12 h-auto p-4 bg-gray-900 rounded-md flex items-center justify-center">
25+
{!data ? 'Click the button' : <RenderJson json={data} />}
26+
</div>
27+
</main>
28+
</>
29+
);
30+
}
31+
32+
`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
export const getNuxtPageCode = (endpoint: string) => `
2+
<template>
3+
<div class="flex justify-center items-center h-screen">
4+
<div class="p-5 w-96">
5+
<p class="typography-text-xs md:typography-text-sm font-bold tracking-widest text-neutral-500 uppercase">
6+
Let's go
7+
</p>
8+
<h1 class="typography-headline-2 md:typography-headline-1 md:leading-[67.5px] font-bold mt-2 mb-4">
9+
Build something amazing
10+
</h1>
11+
<p>
12+
${endpoint}()
13+
</p>
14+
<div class="box">
15+
<!-- <JsonViewer :value="jsonData" copyable boxed sort theme="light" @onKeyClick="keyClick"/> -->
16+
<h4>Response</h4>
17+
<JsonViewer class="min-h-[800px] min-w-[500px]" :value="res" expandDepth="5" expanded copyable boxed sort
18+
theme="dark" />
19+
</div>
20+
<div class="flex flex-col md:flex-row gap-4 mt-6">
21+
<SfButton @click="callEndpoint" size="lg"> call </SfButton>
22+
<SfButton @click="reset" size="lg" variant="secondary" class="bg-white"> reset </SfButton>
23+
</div>
24+
</div>
25+
</div>
26+
</template>
27+
28+
<script lang="ts" setup>
29+
import { SfButton } from '@storefront-ui/vue';
30+
import { sdk } from '~/sdk.config';
31+
import { JsonViewer } from "vue3-json-viewer"
32+
import "vue3-json-viewer/dist/index.css";
33+
34+
const res = useState('waiting to call ${endpoint}() ...');
35+
36+
async function callEndpoint() {
37+
const { data } = await sdk.boilerplate.${endpoint}('test');
38+
res.value = data
39+
}
40+
41+
function reset() {
42+
res.value = 'waiting to call ${endpoint}() ...'
43+
}
44+
</script>
45+
`

0 commit comments

Comments
 (0)