zero-to-app 1.1.0
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/README.md +115 -0
- package/bin/zero-to-app +4 -0
- package/package.json +38 -0
- package/src/index.js +337 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# zero-to-app CLI
|
|
2
|
+
|
|
3
|
+
CLI tool to install the zero-to-app design system package into your project.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
You can use the CLI directly with npx (no installation needed):
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx zero-to-app
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or install it globally:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g zero-to-app
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Then run:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
zero-to-app
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
zero-to-app [options]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Options
|
|
32
|
+
|
|
33
|
+
- `-f, --force` - Overwrite existing directory if it exists
|
|
34
|
+
- `--skip-install` - Skip dependency installation
|
|
35
|
+
- `-p, --package-manager <manager>` - Specify package manager (npm, yarn, pnpm). Default: auto-detect
|
|
36
|
+
- `-h, --help` - Display help
|
|
37
|
+
- `-V, --version` - Display version
|
|
38
|
+
|
|
39
|
+
### Examples
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Install to ./zero-to-app directory
|
|
43
|
+
npx zero-to-app
|
|
44
|
+
|
|
45
|
+
# Force overwrite existing directory
|
|
46
|
+
npx zero-to-app --force
|
|
47
|
+
|
|
48
|
+
# Skip dependency installation
|
|
49
|
+
npx zero-to-app --skip-install
|
|
50
|
+
|
|
51
|
+
# Use specific package manager
|
|
52
|
+
npx zero-to-app --package-manager yarn
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## What it does
|
|
56
|
+
|
|
57
|
+
1. Downloads the `package/` directory from [https://github.com/Alex-Amayo/zero-to-app](https://github.com/Alex-Amayo/zero-to-app) (master branch)
|
|
58
|
+
2. Copies all files from the downloaded package to `./zero-to-app` in your current directory
|
|
59
|
+
3. Checks your project's `package.json` for required dependencies
|
|
60
|
+
4. Installs only missing dependencies in your project root (not in zero-to-app/)
|
|
61
|
+
5. Uses `npx expo install` for Expo packages and npm/yarn/pnpm for regular packages
|
|
62
|
+
|
|
63
|
+
### How it gets the package files
|
|
64
|
+
|
|
65
|
+
The CLI always downloads from GitHub:
|
|
66
|
+
- **GitHub source**: Always fetches from the official repository at `Alex-Amayo/zero-to-app` on the `master` branch
|
|
67
|
+
- **Caching**: Downloads are cached locally for faster subsequent runs
|
|
68
|
+
- **Requirements**: Requires git and internet connection
|
|
69
|
+
|
|
70
|
+
### Required Dependencies
|
|
71
|
+
|
|
72
|
+
The CLI checks for and installs these dependencies if missing:
|
|
73
|
+
- `react-hook-form` - Form validation
|
|
74
|
+
- `@hookform/resolvers` - Form validation resolvers
|
|
75
|
+
- `zod` - Schema validation
|
|
76
|
+
- `react-native-reanimated-carousel` - Carousel component
|
|
77
|
+
- `expo-blur` - Blur effects
|
|
78
|
+
- `expo-glass-effect` - Glass effect
|
|
79
|
+
|
|
80
|
+
**Note:** If all dependencies are already present in your `package.json`, the CLI will skip installation.
|
|
81
|
+
|
|
82
|
+
## Development
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Install dependencies
|
|
86
|
+
npm install
|
|
87
|
+
|
|
88
|
+
# Build (bundles package files)
|
|
89
|
+
npm run build
|
|
90
|
+
|
|
91
|
+
# Run tests
|
|
92
|
+
npm test
|
|
93
|
+
|
|
94
|
+
# Link locally for testing
|
|
95
|
+
npm link
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
## Testing
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npm test
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Publishing
|
|
106
|
+
|
|
107
|
+
The CLI automatically downloads package files from GitHub when used. No build step is required before publishing.
|
|
108
|
+
|
|
109
|
+
Simply publish to npm:
|
|
110
|
+
```bash
|
|
111
|
+
npm publish
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The CLI will fetch the latest package files from GitHub when users run it.
|
|
115
|
+
|
package/bin/zero-to-app
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "zero-to-app",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "CLI tool to install the zero-to-app design system package",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"zero-to-app": "./bin/zero-to-app"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "jest",
|
|
11
|
+
"test:watch": "jest --watch"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"react-native",
|
|
15
|
+
"design-system",
|
|
16
|
+
"cli",
|
|
17
|
+
"zero-to-app"
|
|
18
|
+
],
|
|
19
|
+
"author": "",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"chalk": "^4.1.2",
|
|
23
|
+
"commander": "^11.1.0",
|
|
24
|
+
"fs-extra": "^11.2.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"jest": "^29.7.0"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=14.0.0"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"bin",
|
|
34
|
+
"src",
|
|
35
|
+
"package.json",
|
|
36
|
+
"README.md"
|
|
37
|
+
]
|
|
38
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
const { program } = require('commander');
|
|
8
|
+
const readline = require('readline');
|
|
9
|
+
|
|
10
|
+
// Get the directory where the CLI package is installed
|
|
11
|
+
const getCliPackagePath = () => {
|
|
12
|
+
// When installed via npm/npx, __dirname will be in node_modules/zero-to-app/src
|
|
13
|
+
// We need to find the root of this CLI package
|
|
14
|
+
let currentDir = __dirname;
|
|
15
|
+
const rootDir = path.parse(currentDir).root;
|
|
16
|
+
|
|
17
|
+
// Go up from src/ to find the package root
|
|
18
|
+
while (currentDir !== rootDir) {
|
|
19
|
+
const packageJsonPath = path.join(currentDir, 'package.json');
|
|
20
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
21
|
+
try {
|
|
22
|
+
const pkg = require(packageJsonPath);
|
|
23
|
+
if (pkg.name === 'zero-to-app' && pkg.bin && pkg.bin['zero-to-app']) {
|
|
24
|
+
return currentDir;
|
|
25
|
+
}
|
|
26
|
+
} catch (e) {
|
|
27
|
+
// Continue searching if package.json is invalid
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const parentDir = path.dirname(currentDir);
|
|
31
|
+
if (parentDir === currentDir) break;
|
|
32
|
+
currentDir = parentDir;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Fallback: assume we're in development
|
|
36
|
+
return path.resolve(__dirname, '..');
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Get the source package directory
|
|
40
|
+
const getSourcePackagePath = async () => {
|
|
41
|
+
// Always download from GitHub
|
|
42
|
+
return await downloadFromGitHub();
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Download package files from GitHub
|
|
46
|
+
const downloadFromGitHub = async () => {
|
|
47
|
+
const { execSync } = require('child_process');
|
|
48
|
+
const GITHUB_REPO = 'Alex-Amayo/zero-to-app';
|
|
49
|
+
const GITHUB_BRANCH = 'master'; // Default branch per GitHub repo
|
|
50
|
+
const GITHUB_URL = `https://github.com/${GITHUB_REPO}.git`;
|
|
51
|
+
|
|
52
|
+
const tempDir = path.join(require('os').tmpdir(), 'zero-to-app-cli');
|
|
53
|
+
const repoDir = path.join(tempDir, 'zero-to-app');
|
|
54
|
+
const packageDir = path.join(repoDir, 'package');
|
|
55
|
+
|
|
56
|
+
// Check if already cloned and up to date
|
|
57
|
+
if (fs.existsSync(packageDir)) {
|
|
58
|
+
try {
|
|
59
|
+
// Try to update if it's a git repo
|
|
60
|
+
if (fs.existsSync(path.join(repoDir, '.git'))) {
|
|
61
|
+
console.log(chalk.gray('Updating package files from GitHub...'));
|
|
62
|
+
execSync('git pull', { cwd: repoDir, stdio: 'ignore' });
|
|
63
|
+
console.log(chalk.gray('Using cached package files from GitHub...'));
|
|
64
|
+
return packageDir;
|
|
65
|
+
}
|
|
66
|
+
} catch (e) {
|
|
67
|
+
// If update fails, continue with existing files
|
|
68
|
+
console.log(chalk.gray('Using cached package files from GitHub...'));
|
|
69
|
+
return packageDir;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log(chalk.blue('Downloading package files from GitHub...'));
|
|
74
|
+
console.log(chalk.gray(`Repository: ${GITHUB_REPO}`));
|
|
75
|
+
console.log(chalk.gray(`Branch: ${GITHUB_BRANCH}`));
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
await fs.ensureDir(tempDir);
|
|
79
|
+
|
|
80
|
+
// Try git clone first (fastest and most reliable)
|
|
81
|
+
try {
|
|
82
|
+
if (fs.existsSync(repoDir)) {
|
|
83
|
+
await fs.remove(repoDir);
|
|
84
|
+
}
|
|
85
|
+
execSync(`git clone --depth 1 --branch ${GITHUB_BRANCH} ${GITHUB_URL} "${repoDir}"`, {
|
|
86
|
+
stdio: 'inherit',
|
|
87
|
+
});
|
|
88
|
+
console.log(chalk.green('✓ Package files downloaded successfully'));
|
|
89
|
+
return packageDir;
|
|
90
|
+
} catch (gitError) {
|
|
91
|
+
// If git is not available, try downloading zip
|
|
92
|
+
console.log(chalk.yellow('Git not available, trying alternative download method...'));
|
|
93
|
+
throw gitError;
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error(chalk.red(`Failed to download from GitHub: ${error.message}`));
|
|
97
|
+
throw new Error(`Could not download package files from GitHub. Please ensure git is installed or check your internet connection. Error: ${error.message}`);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Copy directory recursively, excluding node_modules and other ignored files
|
|
102
|
+
const copyDirectory = async (src, dest, excludes = []) => {
|
|
103
|
+
await fs.ensureDir(dest);
|
|
104
|
+
|
|
105
|
+
const items = await fs.readdir(src);
|
|
106
|
+
|
|
107
|
+
for (const item of items) {
|
|
108
|
+
const srcPath = path.join(src, item);
|
|
109
|
+
const destPath = path.join(dest, item);
|
|
110
|
+
|
|
111
|
+
// Skip excluded items
|
|
112
|
+
if (excludes.includes(item)) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const stat = await fs.stat(srcPath);
|
|
117
|
+
|
|
118
|
+
if (stat.isDirectory()) {
|
|
119
|
+
await copyDirectory(srcPath, destPath, excludes);
|
|
120
|
+
} else {
|
|
121
|
+
await fs.copy(srcPath, destPath);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Get required dependencies that are not included with Expo by default
|
|
127
|
+
const getRequiredDependencies = () => {
|
|
128
|
+
return {
|
|
129
|
+
// Regular npm packages
|
|
130
|
+
regular: [
|
|
131
|
+
'react-hook-form',
|
|
132
|
+
'@hookform/resolvers',
|
|
133
|
+
'zod',
|
|
134
|
+
'react-native-reanimated-carousel',
|
|
135
|
+
],
|
|
136
|
+
// Expo packages (should use expo install)
|
|
137
|
+
expo: [
|
|
138
|
+
'expo-blur',
|
|
139
|
+
'expo-glass-effect',
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// Check user's package.json for missing dependencies
|
|
145
|
+
const checkDependencies = (packageJsonPath) => {
|
|
146
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
147
|
+
return { missing: getRequiredDependencies(), allPresent: false };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
const packageJson = fs.readJsonSync(packageJsonPath);
|
|
152
|
+
const allDeps = {
|
|
153
|
+
...(packageJson.dependencies || {}),
|
|
154
|
+
...(packageJson.devDependencies || {}),
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const required = getRequiredDependencies();
|
|
158
|
+
const missing = {
|
|
159
|
+
regular: [],
|
|
160
|
+
expo: [],
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// Check regular dependencies
|
|
164
|
+
for (const dep of required.regular) {
|
|
165
|
+
if (!allDeps[dep]) {
|
|
166
|
+
missing.regular.push(dep);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Check Expo dependencies
|
|
171
|
+
for (const dep of required.expo) {
|
|
172
|
+
if (!allDeps[dep]) {
|
|
173
|
+
missing.expo.push(dep);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const allPresent = missing.regular.length === 0 && missing.expo.length === 0;
|
|
178
|
+
|
|
179
|
+
return { missing, allPresent };
|
|
180
|
+
} catch (error) {
|
|
181
|
+
console.warn(chalk.yellow(`Warning: Could not read package.json: ${error.message}`));
|
|
182
|
+
return { missing: getRequiredDependencies(), allPresent: false };
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Install missing dependencies
|
|
187
|
+
const installMissingDependencies = async (missing, packageManager = 'npm', projectRoot) => {
|
|
188
|
+
if (missing.regular.length === 0 && missing.expo.length === 0) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
// Install Expo packages first using expo install
|
|
194
|
+
if (missing.expo.length > 0) {
|
|
195
|
+
console.log(chalk.blue(`Installing Expo packages: ${missing.expo.join(', ')}...`));
|
|
196
|
+
const expoPackages = missing.expo.join(' ');
|
|
197
|
+
execSync(`npx expo install ${expoPackages}`, {
|
|
198
|
+
cwd: projectRoot,
|
|
199
|
+
stdio: 'inherit',
|
|
200
|
+
});
|
|
201
|
+
console.log(chalk.green('✓ Expo packages installed successfully'));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Install regular packages using detected package manager
|
|
205
|
+
if (missing.regular.length > 0) {
|
|
206
|
+
console.log(chalk.blue(`Installing packages: ${missing.regular.join(', ')}...`));
|
|
207
|
+
|
|
208
|
+
let command;
|
|
209
|
+
if (packageManager === 'yarn') {
|
|
210
|
+
command = `yarn add ${missing.regular.join(' ')}`;
|
|
211
|
+
} else if (packageManager === 'pnpm') {
|
|
212
|
+
command = `pnpm add ${missing.regular.join(' ')}`;
|
|
213
|
+
} else {
|
|
214
|
+
command = `npm install ${missing.regular.join(' ')}`;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
execSync(command, {
|
|
218
|
+
cwd: projectRoot,
|
|
219
|
+
stdio: 'inherit',
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
console.log(chalk.green('✓ Packages installed successfully'));
|
|
223
|
+
}
|
|
224
|
+
} catch (error) {
|
|
225
|
+
console.error(chalk.red('✗ Failed to install dependencies'));
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Prompt user for confirmation
|
|
231
|
+
const promptOverwrite = (targetDir) => {
|
|
232
|
+
return new Promise((resolve) => {
|
|
233
|
+
const rl = readline.createInterface({
|
|
234
|
+
input: process.stdin,
|
|
235
|
+
output: process.stdout,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
rl.question(chalk.yellow(`Directory ${targetDir} already exists. Overwrite? (y/N): `), (answer) => {
|
|
239
|
+
rl.close();
|
|
240
|
+
const shouldOverwrite = answer.toLowerCase().trim() === 'y' || answer.toLowerCase().trim() === 'yes';
|
|
241
|
+
resolve(shouldOverwrite);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// Main install function
|
|
247
|
+
const install = async (options) => {
|
|
248
|
+
const targetDir = path.resolve(process.cwd(), 'zero-to-app');
|
|
249
|
+
|
|
250
|
+
console.log(chalk.blue('Installing zero-to-app design system...'));
|
|
251
|
+
console.log(chalk.gray(`Target directory: ${targetDir}`));
|
|
252
|
+
|
|
253
|
+
// Check if target directory already exists
|
|
254
|
+
let shouldOverwrite = options.force;
|
|
255
|
+
if (fs.existsSync(targetDir) && !options.force) {
|
|
256
|
+
shouldOverwrite = await promptOverwrite(targetDir);
|
|
257
|
+
if (!shouldOverwrite) {
|
|
258
|
+
console.log(chalk.gray('Installation cancelled.'));
|
|
259
|
+
process.exit(0);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
try {
|
|
264
|
+
// Get source package path (may download from GitHub if not found locally)
|
|
265
|
+
const sourcePath = await getSourcePackagePath();
|
|
266
|
+
console.log(chalk.gray(`Source directory: ${sourcePath}`));
|
|
267
|
+
|
|
268
|
+
if (!fs.existsSync(sourcePath)) {
|
|
269
|
+
throw new Error(`Source package directory not found: ${sourcePath}`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Remove existing directory if force is used or user confirmed
|
|
273
|
+
if (shouldOverwrite && fs.existsSync(targetDir)) {
|
|
274
|
+
console.log(chalk.yellow('Removing existing directory...'));
|
|
275
|
+
await fs.remove(targetDir);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Copy package files
|
|
279
|
+
console.log(chalk.blue('Copying package files...'));
|
|
280
|
+
const excludes = ['node_modules', '.git', 'package-lock.json', 'pnpm-lock.yaml', 'yarn.lock'];
|
|
281
|
+
await copyDirectory(sourcePath, targetDir, excludes);
|
|
282
|
+
console.log(chalk.green('✓ Files copied successfully'));
|
|
283
|
+
|
|
284
|
+
// Check and install dependencies in user's project root
|
|
285
|
+
if (!options.skipInstall) {
|
|
286
|
+
const projectRoot = process.cwd();
|
|
287
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
288
|
+
|
|
289
|
+
console.log(chalk.blue('Checking dependencies...'));
|
|
290
|
+
const { missing, allPresent } = checkDependencies(packageJsonPath);
|
|
291
|
+
|
|
292
|
+
if (allPresent) {
|
|
293
|
+
console.log(chalk.green('✓ All required dependencies are already installed'));
|
|
294
|
+
} else {
|
|
295
|
+
const packageManager = options.packageManager || detectPackageManager();
|
|
296
|
+
await installMissingDependencies(missing, packageManager, projectRoot);
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
console.log(chalk.yellow('Skipping dependency installation (--skip-install)'));
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
console.log(chalk.green('\n✓ zero-to-app installed successfully!'));
|
|
303
|
+
console.log(chalk.blue(`\nNext steps:`));
|
|
304
|
+
console.log(chalk.gray(` Import components: import { Button, Card } from './zero-to-app'`));
|
|
305
|
+
|
|
306
|
+
} catch (error) {
|
|
307
|
+
console.error(chalk.red(`\n✗ Installation failed: ${error.message}`));
|
|
308
|
+
if (error.stack) {
|
|
309
|
+
console.error(chalk.gray(error.stack));
|
|
310
|
+
}
|
|
311
|
+
process.exit(1);
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
// Detect package manager from current directory
|
|
316
|
+
const detectPackageManager = () => {
|
|
317
|
+
if (fs.existsSync(path.join(process.cwd(), 'yarn.lock'))) {
|
|
318
|
+
return 'yarn';
|
|
319
|
+
}
|
|
320
|
+
if (fs.existsSync(path.join(process.cwd(), 'pnpm-lock.yaml'))) {
|
|
321
|
+
return 'pnpm';
|
|
322
|
+
}
|
|
323
|
+
return 'npm';
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
// CLI setup
|
|
327
|
+
program
|
|
328
|
+
.name('zero-to-app')
|
|
329
|
+
.description('Install the zero-to-app design system package')
|
|
330
|
+
.version('1.0.0')
|
|
331
|
+
.option('-f, --force', 'Overwrite existing directory', false)
|
|
332
|
+
.option('--skip-install', 'Skip dependency installation', false)
|
|
333
|
+
.option('-p, --package-manager <manager>', 'Package manager to use (npm, yarn, pnpm)', 'npm')
|
|
334
|
+
.action(install);
|
|
335
|
+
|
|
336
|
+
program.parse();
|
|
337
|
+
|