create-ollie-shop 0.1.1
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/.turbo/turbo-build.log +13 -0
- package/CHANGELOG.md +9 -0
- package/README.md +129 -0
- package/dist/index.js +211 -0
- package/dist/template/.vscode/extensions.json +3 -0
- package/dist/template/.vscode/settings.json +26 -0
- package/dist/template/components/HelloWorld/index.tsx +10 -0
- package/dist/template/components/HelloWorld/styles.module.css +7 -0
- package/dist/template/package.json +17 -0
- package/dist/template/preview.config.ts +3 -0
- package/dist/template/tsconfig.json +18 -0
- package/dist/template/types/index.d.ts +4 -0
- package/package.json +34 -0
- package/src/commands/create-project.ts +114 -0
- package/src/index.ts +130 -0
- package/src/types/index.ts +17 -0
- package/src/utils/prompts.ts +85 -0
- package/template/.vscode/extensions.json +3 -0
- package/template/.vscode/settings.json +26 -0
- package/template/components/HelloWorld/index.tsx +10 -0
- package/template/components/HelloWorld/meta.json +6 -0
- package/template/components/HelloWorld/styles.module.css +7 -0
- package/template/ollie.json +9 -0
- package/template/package.json +17 -0
- package/template/preview.config.ts +3 -0
- package/template/tsconfig.json +18 -0
- package/template/types/index.d.ts +4 -0
- package/tsconfig.json +21 -0
- package/tsup.config.ts +43 -0
- package/vitest.config.ts +7 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
> create-ollie-shop@0.1.1 build /home/runner/work/ollie-shop/ollie-shop/packages/create-ollie-shop
|
|
3
|
+
> tsup
|
|
4
|
+
|
|
5
|
+
[34mCLI[39m Building entry: src/index.ts
|
|
6
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
|
+
[34mCLI[39m tsup v8.5.0
|
|
8
|
+
[34mCLI[39m Using tsup config: /home/runner/work/ollie-shop/ollie-shop/packages/create-ollie-shop/tsup.config.ts
|
|
9
|
+
[34mCLI[39m Target: es2022
|
|
10
|
+
[34mCLI[39m Cleaning output folder
|
|
11
|
+
[34mESM[39m Build start
|
|
12
|
+
[32mESM[39m [1mdist/index.js [22m[32m6.28 KB[39m
|
|
13
|
+
[32mESM[39m ⚡️ Build success in 90ms
|
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# create-ollie-shop
|
|
2
|
+
|
|
3
|
+
A CLI tool to create a new Ollie Shop e-commerce project with a modern tech stack and pre-built components.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`create-ollie-shop` is a scaffolding tool that helps you quickly set up a new e-commerce project using the Ollie Shop framework. It provides a selection of templates, components, and configurations to kickstart your online store development.
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- Node.js 20.x or higher
|
|
12
|
+
- pnpm 7.x or higher (recommended package manager)
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### Using pnpm create
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm create ollie-shop [project-name]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Or use directly with npx
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx create-ollie-shop [project-name]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Options
|
|
29
|
+
|
|
30
|
+
- `--store-id <id>` - Specify an Ollie store ID
|
|
31
|
+
- `--version-id <id>` - Specify an Ollie store version ID
|
|
32
|
+
- `--help` - Display help information
|
|
33
|
+
- `--version` - Display version information
|
|
34
|
+
|
|
35
|
+
### Examples
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Start interactive project bootstrapping
|
|
39
|
+
npx create-ollie-shop
|
|
40
|
+
|
|
41
|
+
# Create a new project with a custom name
|
|
42
|
+
npx create-ollie-shop my-awesome-store
|
|
43
|
+
|
|
44
|
+
# Create a new project with store configuration
|
|
45
|
+
npx create-ollie-shop my-store --store-id 7217542a-d7c6-40d3-a20e-db13b310a781 --version-id 882c8c18-550c-4ac5-9d3b-015d7dd25741
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Preview.js Plugin
|
|
49
|
+
|
|
50
|
+
Ollie Shop projects were designed to be previewed using the Preview.js plugin for VS Code. This tool allows developers to visualize and interact with components in isolation during development.
|
|
51
|
+
|
|
52
|
+
### Installation
|
|
53
|
+
|
|
54
|
+
Simply install the Preview.js extension from the VS Code marketplace:
|
|
55
|
+
[VS Code Extension](https://marketplace.visualstudio.com/items?itemName=zenclabs.previewjs)
|
|
56
|
+
|
|
57
|
+
### Usage
|
|
58
|
+
|
|
59
|
+
Preview.js works seamlessly with properly bootstrapped Ollie Shop projects. After creating your project with `create-ollie-shop`, the Preview.js server will automatically read the Ollie configurations and set up accordingly.
|
|
60
|
+
|
|
61
|
+
To use Preview.js:
|
|
62
|
+
1. Open any component file in your Ollie Shop project
|
|
63
|
+
2. Click the Preview.js icon in the editor or press the keyboard shortcut
|
|
64
|
+
3. A live preview of your component will appear, reflecting any changes you make in real-time
|
|
65
|
+
|
|
66
|
+
This integration allows you to develop and test components without needing to set up a separate development environment or manually configure Preview.js.
|
|
67
|
+
|
|
68
|
+
## Development
|
|
69
|
+
|
|
70
|
+
To work on `create-ollie-shop` locally:
|
|
71
|
+
|
|
72
|
+
1. Clone the repository
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
git clone git@github.com:ollie-shop/ollie-shop.git
|
|
76
|
+
cd ollie-shop
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
2. Install dependencies
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pnpm install
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
3. Link local packages
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Navigate to the create-ollie-shop package directory
|
|
89
|
+
cd packages/create-ollie-shop
|
|
90
|
+
|
|
91
|
+
# Create a global link
|
|
92
|
+
pnpm link --global
|
|
93
|
+
|
|
94
|
+
# For working with other local packages, use pnpm link inside each package directory
|
|
95
|
+
# For example, to link the ollie-shop library:
|
|
96
|
+
cd ../ollie-shop
|
|
97
|
+
pnpm link --global
|
|
98
|
+
|
|
99
|
+
# Then, in the create-ollie-shop directory:
|
|
100
|
+
pnpm link --global ollie-shop
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
> **Note**: When using `pnpm link`, make sure all linked packages have their dependencies installed. The link creates a symlink to your local package, allowing you to make changes and immediately see them reflected in projects that use the linked package.
|
|
104
|
+
|
|
105
|
+
4. Build the package
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
pnpm build
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
5. Test your changes
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
pnpm test
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Contributing
|
|
118
|
+
|
|
119
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
120
|
+
|
|
121
|
+
1. Fork the repository
|
|
122
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
123
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
124
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
125
|
+
5. Open a Pull Request
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import path2 from "path";
|
|
5
|
+
import chalk3 from "chalk";
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
import fs2 from "fs-extra";
|
|
8
|
+
|
|
9
|
+
// src/commands/create-project.ts
|
|
10
|
+
import child_process from "child_process";
|
|
11
|
+
import path from "path";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
13
|
+
import { promisify } from "util";
|
|
14
|
+
import chalk from "chalk";
|
|
15
|
+
import fs from "fs-extra";
|
|
16
|
+
var exec = promisify(child_process.exec);
|
|
17
|
+
var BASE_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
async function createProject(config) {
|
|
19
|
+
const {
|
|
20
|
+
projectName,
|
|
21
|
+
storeId,
|
|
22
|
+
versionId,
|
|
23
|
+
platform,
|
|
24
|
+
platformStoreId,
|
|
25
|
+
targetDir
|
|
26
|
+
} = config;
|
|
27
|
+
console.log(
|
|
28
|
+
`
|
|
29
|
+
\u{1F680} Creating a new Ollie Shop project in ${chalk.green(`./${projectName}`)}...`
|
|
30
|
+
);
|
|
31
|
+
fs.ensureDirSync(targetDir);
|
|
32
|
+
const templateDir = path.join(BASE_DIR, "template");
|
|
33
|
+
await fs.copy(templateDir, targetDir, {
|
|
34
|
+
overwrite: true
|
|
35
|
+
});
|
|
36
|
+
const pkgPath = path.join(targetDir, "package.json");
|
|
37
|
+
const pkg = await fs.readJSON(path.join(targetDir, "package.json"));
|
|
38
|
+
pkg.name = projectName;
|
|
39
|
+
await fs.writeJSON(pkgPath, pkg, { spaces: 2 });
|
|
40
|
+
const ollieConfigPath = path.join(targetDir, "ollie.json");
|
|
41
|
+
await fs.writeJSON(
|
|
42
|
+
ollieConfigPath,
|
|
43
|
+
{
|
|
44
|
+
storeId: storeId || null,
|
|
45
|
+
versionId: versionId || null,
|
|
46
|
+
platform,
|
|
47
|
+
platformStoreId: platformStoreId || null
|
|
48
|
+
},
|
|
49
|
+
{ spaces: 2 }
|
|
50
|
+
);
|
|
51
|
+
try {
|
|
52
|
+
await exec("git init", { cwd: targetDir });
|
|
53
|
+
} catch (e) {
|
|
54
|
+
console.log("\n\u274C Error initializing git:", e);
|
|
55
|
+
}
|
|
56
|
+
printSuccessMessage(
|
|
57
|
+
projectName,
|
|
58
|
+
storeId,
|
|
59
|
+
versionId,
|
|
60
|
+
platform,
|
|
61
|
+
platformStoreId
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
function printSuccessMessage(projectName, storeId, versionId, platform, platformStoreId) {
|
|
65
|
+
console.log("\n\u2705 Project created successfully!");
|
|
66
|
+
console.log("\nNext steps:");
|
|
67
|
+
console.log(` cd ${chalk.cyan(projectName)}`);
|
|
68
|
+
console.log(
|
|
69
|
+
` npm install (or ${chalk.cyan("pnpm install")} or ${chalk.cyan("yarn")})`
|
|
70
|
+
);
|
|
71
|
+
console.log(
|
|
72
|
+
"\n The development environment leverages the Preview.js extension for VS Code:"
|
|
73
|
+
);
|
|
74
|
+
console.log(
|
|
75
|
+
` ${chalk.cyan("https://marketplace.visualstudio.com/items?itemName=zenclabs.previewjs")}
|
|
76
|
+
`
|
|
77
|
+
);
|
|
78
|
+
if (storeId) {
|
|
79
|
+
console.log(`Store ID: ${chalk.green(storeId)}`);
|
|
80
|
+
} else if (platform && platformStoreId) {
|
|
81
|
+
console.log(`Platform: ${chalk.green(platform)}`);
|
|
82
|
+
console.log(`Platform Store ID: ${chalk.green(platformStoreId)}`);
|
|
83
|
+
}
|
|
84
|
+
if (versionId) {
|
|
85
|
+
console.log(`Version ID: ${chalk.green(versionId)}`);
|
|
86
|
+
}
|
|
87
|
+
console.log("\n\u{1F6CD}\uFE0F Happy development with Ollie Shop! \u{1F6CD}\uFE0F\n");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/utils/prompts.ts
|
|
91
|
+
import chalk2 from "chalk";
|
|
92
|
+
import prompts from "prompts";
|
|
93
|
+
import { z } from "zod";
|
|
94
|
+
async function promptForProjectName(defaultValue = "my-ollie-shop") {
|
|
95
|
+
const { value } = await prompts({
|
|
96
|
+
type: "text",
|
|
97
|
+
name: "value",
|
|
98
|
+
message: "Project name:",
|
|
99
|
+
initial: defaultValue,
|
|
100
|
+
validate: (value2) => z.string().nonempty().safeParse(value2).success
|
|
101
|
+
});
|
|
102
|
+
return value || defaultValue;
|
|
103
|
+
}
|
|
104
|
+
async function promptForOverwrite(dirName) {
|
|
105
|
+
const { overwrite } = await prompts({
|
|
106
|
+
type: "confirm",
|
|
107
|
+
name: "overwrite",
|
|
108
|
+
message: `Directory ${chalk2.cyan(dirName)} already exists. Overwrite?`,
|
|
109
|
+
initial: false
|
|
110
|
+
});
|
|
111
|
+
return overwrite;
|
|
112
|
+
}
|
|
113
|
+
async function promptForStoreId() {
|
|
114
|
+
const { value } = await prompts({
|
|
115
|
+
type: "text",
|
|
116
|
+
name: "value",
|
|
117
|
+
message: "Store ID (optional):",
|
|
118
|
+
hint: "Leave empty if you want to set up the workspace manually",
|
|
119
|
+
validate: (value2) => z.string().uuid().or(z.literal("")).safeParse(value2).success || "Please enter a valid UUID or leave empty"
|
|
120
|
+
});
|
|
121
|
+
return value && value.trim() !== "" ? value : void 0;
|
|
122
|
+
}
|
|
123
|
+
async function promptForPlatformStoreId(platform) {
|
|
124
|
+
const { platformStoreId } = await prompts({
|
|
125
|
+
type: "text",
|
|
126
|
+
name: "platformStoreId",
|
|
127
|
+
message: `Enter your ${platform.toUpperCase()} account name:`,
|
|
128
|
+
validate: (value) => z.string().min(1).safeParse(value).success || "Account name cannot be empty"
|
|
129
|
+
});
|
|
130
|
+
return platformStoreId;
|
|
131
|
+
}
|
|
132
|
+
async function promptForVersionId() {
|
|
133
|
+
const { value } = await prompts({
|
|
134
|
+
type: "text",
|
|
135
|
+
name: "value",
|
|
136
|
+
message: "Version ID (optional):",
|
|
137
|
+
validate: (value2) => z.string().uuid().or(z.literal("")).safeParse(value2).success
|
|
138
|
+
});
|
|
139
|
+
return value && value.trim() !== "" ? value : void 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/index.ts
|
|
143
|
+
async function main() {
|
|
144
|
+
console.log(
|
|
145
|
+
chalk3.bold.blue(
|
|
146
|
+
"\u{1F6CD}\uFE0F Create Ollie Shop - Bootstrap a new Ollie Shop project"
|
|
147
|
+
)
|
|
148
|
+
);
|
|
149
|
+
const program = new Command().name("create-ollie-shop").description(
|
|
150
|
+
"Bootstrap a new Ollie Shop project with optional store configuration"
|
|
151
|
+
).version("0.1.0").argument("[project-name]", "Project folder name", "my-ollie-shop").option("--store-id <id>", "Specify an Ollie store ID").option("--version-id <id>", "Specify an Ollie store version ID").addHelpText(
|
|
152
|
+
"after",
|
|
153
|
+
`
|
|
154
|
+
Examples:
|
|
155
|
+
$ create-ollie-shop
|
|
156
|
+
$ create-ollie-shop my-awesome-store
|
|
157
|
+
$ create-ollie-shop my-store --store-id 7217542a-d7c6-40d3-a20e-db13b310a781 --version-id 882c8c18-550c-4ac5-9d3b-015d7dd25741
|
|
158
|
+
`
|
|
159
|
+
).parse(process.argv);
|
|
160
|
+
try {
|
|
161
|
+
await initializeProject(program);
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.error(chalk3.red("\n\u274C Error:"), error);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async function initializeProject(program) {
|
|
168
|
+
const options = program.opts();
|
|
169
|
+
let storeId = options.storeId;
|
|
170
|
+
let versionId = options.versionId;
|
|
171
|
+
const platform = "vtex";
|
|
172
|
+
let platformStoreId;
|
|
173
|
+
let projectName = program.args[0];
|
|
174
|
+
if (!projectName) {
|
|
175
|
+
projectName = await promptForProjectName();
|
|
176
|
+
}
|
|
177
|
+
const cwd = process.cwd();
|
|
178
|
+
const targetDir = path2.join(cwd, projectName);
|
|
179
|
+
if (fs2.existsSync(targetDir)) {
|
|
180
|
+
const shouldOverwrite = await promptForOverwrite(projectName);
|
|
181
|
+
if (!shouldOverwrite) {
|
|
182
|
+
console.log(chalk3.red("\u274C Operation cancelled"));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
await fs2.emptyDir(targetDir);
|
|
186
|
+
}
|
|
187
|
+
if (!storeId) {
|
|
188
|
+
storeId = await promptForStoreId();
|
|
189
|
+
if (!storeId) {
|
|
190
|
+
console.log(
|
|
191
|
+
chalk3.blue(
|
|
192
|
+
`Using ${chalk3.bold(platform.toUpperCase())} as the platform`
|
|
193
|
+
)
|
|
194
|
+
);
|
|
195
|
+
platformStoreId = await promptForPlatformStoreId(platform);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (!versionId) {
|
|
199
|
+
versionId = await promptForVersionId();
|
|
200
|
+
}
|
|
201
|
+
const config = {
|
|
202
|
+
projectName,
|
|
203
|
+
storeId,
|
|
204
|
+
versionId,
|
|
205
|
+
platform,
|
|
206
|
+
platformStoreId,
|
|
207
|
+
targetDir
|
|
208
|
+
};
|
|
209
|
+
await createProject(config);
|
|
210
|
+
}
|
|
211
|
+
main();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"editor.formatOnSave": true,
|
|
3
|
+
"editor.defaultFormatter": "biomejs.biome",
|
|
4
|
+
"editor.codeActionsOnSave": {
|
|
5
|
+
"source.fixAll.biome": "explicit",
|
|
6
|
+
"source.organizeImports.biome": "explicit"
|
|
7
|
+
},
|
|
8
|
+
"[typescript]": {
|
|
9
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
10
|
+
},
|
|
11
|
+
"[typescriptreact]": {
|
|
12
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
13
|
+
},
|
|
14
|
+
"[javascript]": {
|
|
15
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
16
|
+
},
|
|
17
|
+
"[javascriptreact]": {
|
|
18
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
19
|
+
},
|
|
20
|
+
"[json]": {
|
|
21
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
22
|
+
},
|
|
23
|
+
"[jsonc]": {
|
|
24
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dev",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"devDependencies": {
|
|
6
|
+
"@ollie-shop/sdk": "^0.1.0",
|
|
7
|
+
"@ollie-shop/previewjs": "^0.1.0",
|
|
8
|
+
"@types/node": "^22.14.0",
|
|
9
|
+
"@types/react": "^19.1.0",
|
|
10
|
+
"@types/react-dom": "^19.1.1",
|
|
11
|
+
"next": "^15.3.1",
|
|
12
|
+
"react": "^19.0.0",
|
|
13
|
+
"react-dom": "^19.0.0",
|
|
14
|
+
"typescript": "^5.7.3",
|
|
15
|
+
"vite": "^6.2.5"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": ["ES2022"],
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"target": "ES2022",
|
|
6
|
+
"moduleResolution": "Bundler",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"noUncheckedIndexedAccess": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"typeRoots": ["./node_modules/@types", "./types"],
|
|
15
|
+
"types": ["node"]
|
|
16
|
+
},
|
|
17
|
+
"exclude": ["node_modules", "dist"]
|
|
18
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-ollie-shop",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"create-ollie-shop": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@types/fs-extra": "^11.0.4",
|
|
12
|
+
"@types/node": "^22.14.0",
|
|
13
|
+
"@types/prompts": "^2.4.9",
|
|
14
|
+
"tsup": "^8.4.0",
|
|
15
|
+
"typescript": "^5.7.3",
|
|
16
|
+
"vitest": "^3.0.4"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"chalk": "^5.4.1",
|
|
20
|
+
"commander": "^11.1.0",
|
|
21
|
+
"fs-extra": "^11.3.0",
|
|
22
|
+
"prompts": "^2.4.2",
|
|
23
|
+
"zod": "^3.24.2",
|
|
24
|
+
"@ollie-shop/previewjs": "^0.1.1"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"registry": "https://registry.npmjs.org/"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsup",
|
|
32
|
+
"test": "vitest"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import child_process from "node:child_process";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
import type { OllieShopConfig } from "../types";
|
|
8
|
+
|
|
9
|
+
const exec = promisify(child_process.exec);
|
|
10
|
+
|
|
11
|
+
const BASE_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
/**
|
|
13
|
+
* Create a new Ollie Shop project
|
|
14
|
+
*/
|
|
15
|
+
export async function createProject(config: OllieShopConfig): Promise<void> {
|
|
16
|
+
const {
|
|
17
|
+
projectName,
|
|
18
|
+
storeId,
|
|
19
|
+
versionId,
|
|
20
|
+
platform,
|
|
21
|
+
platformStoreId,
|
|
22
|
+
targetDir,
|
|
23
|
+
} = config;
|
|
24
|
+
|
|
25
|
+
console.log(
|
|
26
|
+
`\n🚀 Creating a new Ollie Shop project in ${chalk.green(`./${projectName}`)}...`,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
// Ensure target directory exists
|
|
30
|
+
fs.ensureDirSync(targetDir);
|
|
31
|
+
|
|
32
|
+
// Get template directory path
|
|
33
|
+
const templateDir = path.join(BASE_DIR, "template");
|
|
34
|
+
|
|
35
|
+
// Copy template files to target directory
|
|
36
|
+
await fs.copy(templateDir, targetDir, {
|
|
37
|
+
overwrite: true,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Update package.json with project name
|
|
41
|
+
const pkgPath = path.join(targetDir, "package.json");
|
|
42
|
+
const pkg = await fs.readJSON(path.join(targetDir, "package.json"));
|
|
43
|
+
pkg.name = projectName;
|
|
44
|
+
await fs.writeJSON(pkgPath, pkg, { spaces: 2 });
|
|
45
|
+
|
|
46
|
+
// Update ollie.json with config values
|
|
47
|
+
const ollieConfigPath = path.join(targetDir, "ollie.json");
|
|
48
|
+
|
|
49
|
+
await fs.writeJSON(
|
|
50
|
+
ollieConfigPath,
|
|
51
|
+
{
|
|
52
|
+
storeId: storeId || null,
|
|
53
|
+
versionId: versionId || null,
|
|
54
|
+
platform,
|
|
55
|
+
platformStoreId: platformStoreId || null,
|
|
56
|
+
},
|
|
57
|
+
{ spaces: 2 },
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Initialize git in the folder
|
|
61
|
+
try {
|
|
62
|
+
await exec("git init", { cwd: targetDir });
|
|
63
|
+
} catch (e) {
|
|
64
|
+
console.log("\n❌ Error initializing git:", e);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Print success message and next steps
|
|
68
|
+
printSuccessMessage(
|
|
69
|
+
projectName,
|
|
70
|
+
storeId,
|
|
71
|
+
versionId,
|
|
72
|
+
platform,
|
|
73
|
+
platformStoreId,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Print success message with next steps
|
|
79
|
+
*/
|
|
80
|
+
function printSuccessMessage(
|
|
81
|
+
projectName: string,
|
|
82
|
+
storeId?: string,
|
|
83
|
+
versionId?: string,
|
|
84
|
+
platform?: string,
|
|
85
|
+
platformStoreId?: string,
|
|
86
|
+
): void {
|
|
87
|
+
console.log("\n✅ Project created successfully!");
|
|
88
|
+
console.log("\nNext steps:");
|
|
89
|
+
console.log(` cd ${chalk.cyan(projectName)}`);
|
|
90
|
+
console.log(
|
|
91
|
+
` npm install (or ${chalk.cyan("pnpm install")} or ${chalk.cyan("yarn")})`,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
console.log(
|
|
95
|
+
"\n The development environment leverages the Preview.js extension for VS Code:",
|
|
96
|
+
);
|
|
97
|
+
console.log(
|
|
98
|
+
` ${chalk.cyan("https://marketplace.visualstudio.com/items?itemName=zenclabs.previewjs")}\n`,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// Display configuration information
|
|
102
|
+
if (storeId) {
|
|
103
|
+
console.log(`Store ID: ${chalk.green(storeId)}`);
|
|
104
|
+
} else if (platform && platformStoreId) {
|
|
105
|
+
console.log(`Platform: ${chalk.green(platform)}`);
|
|
106
|
+
console.log(`Platform Store ID: ${chalk.green(platformStoreId)}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (versionId) {
|
|
110
|
+
console.log(`Version ID: ${chalk.green(versionId)}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.log("\n🛍️ Happy development with Ollie Shop! 🛍️\n");
|
|
114
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import fs from "fs-extra";
|
|
5
|
+
|
|
6
|
+
import { createProject } from "./commands/create-project";
|
|
7
|
+
import type { OllieShopConfig } from "./types";
|
|
8
|
+
import {
|
|
9
|
+
promptForOverwrite,
|
|
10
|
+
promptForPlatformStoreId,
|
|
11
|
+
promptForProjectName,
|
|
12
|
+
promptForStoreId,
|
|
13
|
+
promptForVersionId,
|
|
14
|
+
} from "./utils/prompts";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Main CLI entry point
|
|
18
|
+
*/
|
|
19
|
+
async function main(): Promise<void> {
|
|
20
|
+
console.log(
|
|
21
|
+
chalk.bold.blue(
|
|
22
|
+
"🛍️ Create Ollie Shop - Bootstrap a new Ollie Shop project",
|
|
23
|
+
),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
// Set up Commander for argument parsing
|
|
27
|
+
const program = new Command()
|
|
28
|
+
.name("create-ollie-shop")
|
|
29
|
+
.description(
|
|
30
|
+
"Bootstrap a new Ollie Shop project with optional store configuration",
|
|
31
|
+
)
|
|
32
|
+
.version("0.1.0")
|
|
33
|
+
.argument("[project-name]", "Project folder name", "my-ollie-shop")
|
|
34
|
+
.option("--store-id <id>", "Specify an Ollie store ID")
|
|
35
|
+
.option("--version-id <id>", "Specify an Ollie store version ID")
|
|
36
|
+
.addHelpText(
|
|
37
|
+
"after",
|
|
38
|
+
`
|
|
39
|
+
Examples:
|
|
40
|
+
$ create-ollie-shop
|
|
41
|
+
$ create-ollie-shop my-awesome-store
|
|
42
|
+
$ create-ollie-shop my-store --store-id 7217542a-d7c6-40d3-a20e-db13b310a781 --version-id 882c8c18-550c-4ac5-9d3b-015d7dd25741
|
|
43
|
+
`,
|
|
44
|
+
)
|
|
45
|
+
.parse(process.argv);
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
await initializeProject(program);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error(chalk.red("\n❌ Error:"), error);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Process command line arguments and initialize the project
|
|
57
|
+
*/
|
|
58
|
+
async function initializeProject(program: Command): Promise<void> {
|
|
59
|
+
// Get options from Commander
|
|
60
|
+
const options = program.opts();
|
|
61
|
+
|
|
62
|
+
// Extract CLI options
|
|
63
|
+
let storeId = options.storeId as string | undefined;
|
|
64
|
+
let versionId = options.versionId as string | undefined;
|
|
65
|
+
|
|
66
|
+
// For platform, we only support VTEX currently
|
|
67
|
+
const platform = "vtex";
|
|
68
|
+
let platformStoreId: string | undefined;
|
|
69
|
+
|
|
70
|
+
// Get or prompt for project name
|
|
71
|
+
let projectName = program.args[0];
|
|
72
|
+
if (!projectName) {
|
|
73
|
+
projectName = await promptForProjectName();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Handle target directory
|
|
77
|
+
const cwd = process.cwd();
|
|
78
|
+
const targetDir = path.join(cwd, projectName);
|
|
79
|
+
|
|
80
|
+
// Check if target directory exists and confirm overwrite
|
|
81
|
+
if (fs.existsSync(targetDir)) {
|
|
82
|
+
const shouldOverwrite = await promptForOverwrite(projectName);
|
|
83
|
+
|
|
84
|
+
if (!shouldOverwrite) {
|
|
85
|
+
console.log(chalk.red("❌ Operation cancelled"));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Clean existing directory
|
|
90
|
+
await fs.emptyDir(targetDir);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Handle store identification
|
|
94
|
+
if (!storeId) {
|
|
95
|
+
// First ask for a direct store ID
|
|
96
|
+
storeId = await promptForStoreId();
|
|
97
|
+
|
|
98
|
+
// If no store ID is provided, get platform store ID
|
|
99
|
+
if (!storeId) {
|
|
100
|
+
console.log(
|
|
101
|
+
chalk.blue(
|
|
102
|
+
`Using ${chalk.bold(platform.toUpperCase())} as the platform`,
|
|
103
|
+
),
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
platformStoreId = await promptForPlatformStoreId(platform);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Get version ID if not provided
|
|
111
|
+
if (!versionId) {
|
|
112
|
+
versionId = await promptForVersionId();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Create configuration object
|
|
116
|
+
const config: OllieShopConfig = {
|
|
117
|
+
projectName,
|
|
118
|
+
storeId,
|
|
119
|
+
versionId,
|
|
120
|
+
platform,
|
|
121
|
+
platformStoreId,
|
|
122
|
+
targetDir,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Create the project
|
|
126
|
+
await createProject(config);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Start the CLI
|
|
130
|
+
main();
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration options for creating a new Ollie Shop project
|
|
3
|
+
*/
|
|
4
|
+
export type OllieShopConfig = {
|
|
5
|
+
/** The name of the project */
|
|
6
|
+
projectName: string;
|
|
7
|
+
/** Optional Ollie store ID */
|
|
8
|
+
storeId?: string;
|
|
9
|
+
/** Optional version ID */
|
|
10
|
+
versionId?: string;
|
|
11
|
+
/** E-commerce platform (e.g., "vtex") */
|
|
12
|
+
platform?: string;
|
|
13
|
+
/** Store/Account ID from the platform */
|
|
14
|
+
platformStoreId?: string;
|
|
15
|
+
/** Target directory path */
|
|
16
|
+
targetDir: string;
|
|
17
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import prompts from "prompts";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Prompt for project name
|
|
7
|
+
*/
|
|
8
|
+
export async function promptForProjectName(
|
|
9
|
+
defaultValue = "my-ollie-shop",
|
|
10
|
+
): Promise<string> {
|
|
11
|
+
const { value } = await prompts({
|
|
12
|
+
type: "text",
|
|
13
|
+
name: "value",
|
|
14
|
+
message: "Project name:",
|
|
15
|
+
initial: defaultValue,
|
|
16
|
+
validate: (value) => z.string().nonempty().safeParse(value).success,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return value || defaultValue;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Prompt for directory overwrite confirmation
|
|
24
|
+
*/
|
|
25
|
+
export async function promptForOverwrite(dirName: string): Promise<boolean> {
|
|
26
|
+
const { overwrite } = await prompts({
|
|
27
|
+
type: "confirm",
|
|
28
|
+
name: "overwrite",
|
|
29
|
+
message: `Directory ${chalk.cyan(dirName)} already exists. Overwrite?`,
|
|
30
|
+
initial: false,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return overwrite;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Prompt for store ID
|
|
38
|
+
*/
|
|
39
|
+
export async function promptForStoreId(): Promise<string | undefined> {
|
|
40
|
+
const { value } = await prompts({
|
|
41
|
+
type: "text",
|
|
42
|
+
name: "value",
|
|
43
|
+
message: "Store ID (optional):",
|
|
44
|
+
hint: "Leave empty if you want to set up the workspace manually",
|
|
45
|
+
validate: (value) =>
|
|
46
|
+
z.string().uuid().or(z.literal("")).safeParse(value).success ||
|
|
47
|
+
"Please enter a valid UUID or leave empty",
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Return undefined if empty string
|
|
51
|
+
return value && value.trim() !== "" ? value : undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Prompt for platform store ID
|
|
56
|
+
*/
|
|
57
|
+
export async function promptForPlatformStoreId(
|
|
58
|
+
platform: string,
|
|
59
|
+
): Promise<string> {
|
|
60
|
+
const { platformStoreId } = await prompts({
|
|
61
|
+
type: "text",
|
|
62
|
+
name: "platformStoreId",
|
|
63
|
+
message: `Enter your ${platform.toUpperCase()} account name:`,
|
|
64
|
+
validate: (value) =>
|
|
65
|
+
z.string().min(1).safeParse(value).success ||
|
|
66
|
+
"Account name cannot be empty",
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return platformStoreId;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Prompt for version ID
|
|
74
|
+
*/
|
|
75
|
+
export async function promptForVersionId(): Promise<string | undefined> {
|
|
76
|
+
const { value } = await prompts({
|
|
77
|
+
type: "text",
|
|
78
|
+
name: "value",
|
|
79
|
+
message: "Version ID (optional):",
|
|
80
|
+
validate: (value) =>
|
|
81
|
+
z.string().uuid().or(z.literal("")).safeParse(value).success,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return value && value.trim() !== "" ? value : undefined;
|
|
85
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"editor.formatOnSave": true,
|
|
3
|
+
"editor.defaultFormatter": "biomejs.biome",
|
|
4
|
+
"editor.codeActionsOnSave": {
|
|
5
|
+
"source.fixAll.biome": "explicit",
|
|
6
|
+
"source.organizeImports.biome": "explicit"
|
|
7
|
+
},
|
|
8
|
+
"[typescript]": {
|
|
9
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
10
|
+
},
|
|
11
|
+
"[typescriptreact]": {
|
|
12
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
13
|
+
},
|
|
14
|
+
"[javascript]": {
|
|
15
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
16
|
+
},
|
|
17
|
+
"[javascriptreact]": {
|
|
18
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
19
|
+
},
|
|
20
|
+
"[json]": {
|
|
21
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
22
|
+
},
|
|
23
|
+
"[jsonc]": {
|
|
24
|
+
"editor.defaultFormatter": "biomejs.biome"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dev",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"devDependencies": {
|
|
6
|
+
"@ollie-shop/sdk": "^0.1.0",
|
|
7
|
+
"@ollie-shop/previewjs": "^0.1.0",
|
|
8
|
+
"@types/node": "^22.14.0",
|
|
9
|
+
"@types/react": "^19.1.0",
|
|
10
|
+
"@types/react-dom": "^19.1.1",
|
|
11
|
+
"next": "^15.3.1",
|
|
12
|
+
"react": "^19.0.0",
|
|
13
|
+
"react-dom": "^19.0.0",
|
|
14
|
+
"typescript": "^5.7.3",
|
|
15
|
+
"vite": "^6.2.5"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": ["ES2022"],
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"target": "ES2022",
|
|
6
|
+
"moduleResolution": "Bundler",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"noUncheckedIndexedAccess": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"typeRoots": ["./node_modules/@types", "./types"],
|
|
15
|
+
"types": ["node"]
|
|
16
|
+
},
|
|
17
|
+
"exclude": ["node_modules", "dist"]
|
|
18
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": ["ES2022"],
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"target": "ES2022",
|
|
6
|
+
"moduleResolution": "Bundler",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"noUncheckedIndexedAccess": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"composite": true,
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"types": ["node", "vitest/globals"],
|
|
16
|
+
"paths": {
|
|
17
|
+
"@/*": ["./src/*"]
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"exclude": ["node_modules", "dist"]
|
|
21
|
+
}
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { defineConfig } from "tsup";
|
|
4
|
+
|
|
5
|
+
const EXCLUDED = [
|
|
6
|
+
// Node files
|
|
7
|
+
"node_modules",
|
|
8
|
+
"dist",
|
|
9
|
+
// Config files
|
|
10
|
+
"ollie.json",
|
|
11
|
+
"meta.json",
|
|
12
|
+
// Lock files
|
|
13
|
+
"pnpm-lock.yaml",
|
|
14
|
+
"package-lock.json",
|
|
15
|
+
"yarn.lock",
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const REGEX_EXCLUDED = new RegExp(EXCLUDED.join("|"));
|
|
19
|
+
|
|
20
|
+
export default defineConfig({
|
|
21
|
+
entry: ["src/index.ts"],
|
|
22
|
+
format: "esm",
|
|
23
|
+
sourcemap: false,
|
|
24
|
+
bundle: true,
|
|
25
|
+
clean: true,
|
|
26
|
+
banner: {
|
|
27
|
+
js: "#!/usr/bin/env node",
|
|
28
|
+
},
|
|
29
|
+
plugins: [
|
|
30
|
+
{
|
|
31
|
+
name: "copy-template",
|
|
32
|
+
buildEnd: async () => {
|
|
33
|
+
const templateDir = path.resolve("template");
|
|
34
|
+
const destDir = path.resolve("dist/template");
|
|
35
|
+
|
|
36
|
+
await fs.cp(templateDir, destDir, {
|
|
37
|
+
recursive: true,
|
|
38
|
+
filter: (src: string) => !REGEX_EXCLUDED.test(path.basename(src)),
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
});
|