@rollipop/init 1.0.0-beta.0 → 1.0.0-beta.2
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 +12 -0
- package/dist/index.js +107 -15
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1 +1,13 @@
|
|
|
1
1
|
# @rollipop/init
|
|
2
|
+
|
|
3
|
+
Run from a React Native or Expo project root:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
yarn dlx @rollipop/init@beta
|
|
7
|
+
yarn install
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
- Bare projects: logs `bare project detected`, adds the matching `rollipop` version, and configures `react-native.config.js`.
|
|
11
|
+
- Expo projects: logs `expo project detected`, adds matching `rollipop` and `@rollipop/expo` versions, and registers the config plugin in `app.json` or `app.config.json` while preserving existing plugins. Dynamic JS/TS configuration is left unchanged with manual setup instructions.
|
|
12
|
+
|
|
13
|
+
Expo detection uses the `expo` dependency in `package.json`, including prebuilt projects with native directories. See [Quick Start](https://rollipop.dev/docs/get-started/quick-start) or the [Expo guide](https://rollipop.dev/docs/experimental/expo) for setup and limitations.
|
package/dist/index.js
CHANGED
|
@@ -2,12 +2,80 @@ import pc from "picocolors";
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { Visitor, parseSync } from "oxc-parser";
|
|
5
|
-
//#region package.json
|
|
6
|
-
var version = "1.0.0-beta.0";
|
|
7
5
|
//#endregion
|
|
8
6
|
//#region src/init.ts
|
|
7
|
+
const { version } = {
|
|
8
|
+
name: "@rollipop/init",
|
|
9
|
+
version: "1.0.0-beta.2",
|
|
10
|
+
homepage: "https://github.com/rollipop-dev/rollipop#readme",
|
|
11
|
+
bugs: { "url": "https://github.com/rollipop-dev/rollipop/issues" },
|
|
12
|
+
license: "MIT",
|
|
13
|
+
author: "leegeunhyeok <dev.ghlee@gmail.com> (https://github.com/leegeunhyeok)",
|
|
14
|
+
repository: {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/rollipop-dev/rollipop.git",
|
|
17
|
+
"directory": "packages/core"
|
|
18
|
+
},
|
|
19
|
+
bin: "./bin/index.js",
|
|
20
|
+
files: ["bin", "dist"],
|
|
21
|
+
type: "module",
|
|
22
|
+
scripts: {
|
|
23
|
+
"execute": "node --import @oxc-node/core/register src/index.ts",
|
|
24
|
+
"prepack": "yarn build",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"test": "vp test --run --passWithNoTests",
|
|
27
|
+
"build": "vp pack"
|
|
28
|
+
},
|
|
29
|
+
dependencies: {
|
|
30
|
+
"oxc-parser": "0.151.0",
|
|
31
|
+
"picocolors": "1.1.1"
|
|
32
|
+
},
|
|
33
|
+
devDependencies: {
|
|
34
|
+
"@oxc-node/core": "^0.1.3",
|
|
35
|
+
"typescript": "catalog:",
|
|
36
|
+
"vite-plus": "catalog:vp"
|
|
37
|
+
},
|
|
38
|
+
installConfig: { "hoistingLimits": "none" }
|
|
39
|
+
};
|
|
9
40
|
const RN_CONFIG_FILE = "react-native.config.js";
|
|
10
41
|
const COMMANDS_REQUIRE = "require('rollipop/commands')";
|
|
42
|
+
function detectProject(cwd) {
|
|
43
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf8"));
|
|
44
|
+
return packageJson.dependencies?.expo || packageJson.devDependencies?.expo ? "expo" : "bare";
|
|
45
|
+
}
|
|
46
|
+
function setupExpoConfig(cwd) {
|
|
47
|
+
const dynamicConfig = [
|
|
48
|
+
"ts",
|
|
49
|
+
"mts",
|
|
50
|
+
"cts",
|
|
51
|
+
"mjs",
|
|
52
|
+
"cjs",
|
|
53
|
+
"js"
|
|
54
|
+
].map((extension) => `app.config.${extension}`).find((filename) => fs.existsSync(path.join(cwd, filename)));
|
|
55
|
+
if (dynamicConfig) return {
|
|
56
|
+
status: "manual-required",
|
|
57
|
+
filename: dynamicConfig
|
|
58
|
+
};
|
|
59
|
+
const filename = ["app.config.json", "app.json"].find((name) => fs.existsSync(path.join(cwd, name))) ?? "app.json";
|
|
60
|
+
const configPath = path.join(cwd, filename);
|
|
61
|
+
const exists = fs.existsSync(configPath);
|
|
62
|
+
const root = exists ? JSON.parse(fs.readFileSync(configPath, "utf8")) : { expo: {} };
|
|
63
|
+
if (!root || typeof root !== "object" || Array.isArray(root)) throw new Error(`${filename} must contain an Expo configuration object`);
|
|
64
|
+
const config = "expo" in root ? root.expo : root;
|
|
65
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) throw new Error(`${filename}: 'expo' must be an object`);
|
|
66
|
+
const plugins = config.plugins ?? [];
|
|
67
|
+
if (!Array.isArray(plugins)) throw new Error(`${filename}: 'plugins' must be an array`);
|
|
68
|
+
if (plugins.some((plugin) => (Array.isArray(plugin) ? plugin[0] : plugin) === "@rollipop/expo")) return {
|
|
69
|
+
status: "already-configured",
|
|
70
|
+
filename
|
|
71
|
+
};
|
|
72
|
+
config.plugins = [...plugins, "@rollipop/expo"];
|
|
73
|
+
fs.writeFileSync(configPath, JSON.stringify(root, null, 2) + "\n");
|
|
74
|
+
return {
|
|
75
|
+
status: exists ? "updated" : "created",
|
|
76
|
+
filename
|
|
77
|
+
};
|
|
78
|
+
}
|
|
11
79
|
function setupReactNativeConfig(cwd) {
|
|
12
80
|
const configPath = path.join(cwd, RN_CONFIG_FILE);
|
|
13
81
|
if (!fs.existsSync(configPath)) {
|
|
@@ -90,11 +158,16 @@ function applyInjection(content, insertOffset, needsComma) {
|
|
|
90
158
|
function setupPackage(cwd) {
|
|
91
159
|
const packageJsonPath = path.join(cwd, "package.json");
|
|
92
160
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
161
|
+
const dependencies = {
|
|
162
|
+
rollipop: version,
|
|
163
|
+
...detectProject(cwd) === "expo" ? { "@rollipop/expo": version } : {}
|
|
164
|
+
};
|
|
93
165
|
packageJson.devDependencies = {
|
|
94
166
|
...packageJson.devDependencies,
|
|
95
|
-
|
|
167
|
+
...dependencies
|
|
96
168
|
};
|
|
97
169
|
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n");
|
|
170
|
+
return Object.keys(dependencies);
|
|
98
171
|
}
|
|
99
172
|
//#endregion
|
|
100
173
|
//#region src/index.ts
|
|
@@ -114,43 +187,62 @@ const logger = {
|
|
|
114
187
|
};
|
|
115
188
|
console.log(`\n${pc.bold(pc.cyan("rollipop"))} ${pc.dim("— Modern build toolkit for React Native")}\n`);
|
|
116
189
|
const cwd = process.cwd();
|
|
190
|
+
let projectType;
|
|
191
|
+
try {
|
|
192
|
+
projectType = detectProject(cwd);
|
|
193
|
+
} catch (error) {
|
|
194
|
+
logger.error("Project detection failed", error);
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
logger.info(`${projectType} project detected`);
|
|
117
198
|
let failed = false;
|
|
118
199
|
let hasWarning = false;
|
|
200
|
+
const guideUrl = projectType === "expo" ? "https://rollipop.dev/docs/experimental/expo" : "https://rollipop.dev/docs/get-started/quick-start";
|
|
119
201
|
try {
|
|
120
|
-
|
|
202
|
+
const { status, filename } = projectType === "expo" ? setupExpoConfig(cwd) : {
|
|
203
|
+
status: setupReactNativeConfig(cwd),
|
|
204
|
+
filename: "react-native.config.js"
|
|
205
|
+
};
|
|
206
|
+
switch (status) {
|
|
121
207
|
case "created":
|
|
122
|
-
logger.success(`Created ${pc.bold(
|
|
208
|
+
logger.success(`Created ${pc.bold(filename)}`);
|
|
123
209
|
break;
|
|
124
210
|
case "updated":
|
|
125
|
-
logger.success(`Updated ${pc.bold(
|
|
211
|
+
logger.success(`Updated ${pc.bold(filename)}`);
|
|
126
212
|
break;
|
|
127
213
|
case "already-configured":
|
|
128
|
-
logger.info(`${pc.bold(
|
|
214
|
+
logger.info(`${pc.bold(filename)} already configured`);
|
|
129
215
|
break;
|
|
130
216
|
case "manual-required":
|
|
131
217
|
hasWarning = true;
|
|
132
|
-
|
|
133
|
-
|
|
218
|
+
if (projectType === "expo") {
|
|
219
|
+
logger.warn(`Could not auto-configure dynamic Expo config: ${pc.bold(filename)}`);
|
|
220
|
+
console.log(` Add ${pc.green("'@rollipop/expo'")} to the exported config's ${pc.bold("plugins")} array, keeping existing entries.`);
|
|
221
|
+
} else {
|
|
222
|
+
logger.warn(`Could not auto-configure: ${pc.bold("module.exports")} is not a plain object`);
|
|
223
|
+
console.log(` ${pc.dim("Add the following to your")} ${pc.bold(filename)}${pc.dim(":")}\n ${pc.green("commands: require('rollipop/commands')")}`);
|
|
224
|
+
}
|
|
134
225
|
}
|
|
135
226
|
} catch (error) {
|
|
136
|
-
logger.error("React Native CLI setup failed", error);
|
|
227
|
+
logger.error(projectType === "expo" ? "Expo setup failed" : "React Native CLI setup failed", error);
|
|
137
228
|
failed ||= true;
|
|
138
229
|
}
|
|
139
230
|
if (hasWarning || failed) console.log();
|
|
140
231
|
try {
|
|
141
|
-
setupPackage(cwd);
|
|
142
|
-
logger.success(`Added ${pc.bold("
|
|
232
|
+
const dependencies = setupPackage(cwd);
|
|
233
|
+
logger.success(`Added ${dependencies.map((dependency) => pc.bold(dependency)).join(", ")} to ${pc.bold("devDependencies")}`);
|
|
143
234
|
} catch (error) {
|
|
144
235
|
logger.error("Package setup failed", error);
|
|
145
236
|
failed ||= true;
|
|
146
237
|
}
|
|
147
238
|
if (failed) {
|
|
148
|
-
console.log("\n" + pc.red("Setup failed.") + ` Follow the manual guide: ${pc.underline(pc.cyan(
|
|
239
|
+
console.log("\n" + pc.red("Setup failed.") + ` Follow the manual guide: ${pc.underline(pc.cyan(guideUrl))}`);
|
|
149
240
|
process.exit(1);
|
|
150
241
|
}
|
|
151
|
-
logger.
|
|
242
|
+
if (hasWarning) logger.warn("Manual configuration is required to finish setup.");
|
|
243
|
+
else logger.success(pc.bold("Setup completed!"));
|
|
152
244
|
console.log();
|
|
153
245
|
console.log(` ${pc.dim("Install dependencies manually to finish setup.")}`);
|
|
154
|
-
console.log(` ${pc.dim("See")} ${pc.underline(pc.cyan(
|
|
246
|
+
console.log(` ${pc.dim("See")} ${pc.underline(pc.cyan(guideUrl))} ${pc.dim("for configuration details.")}`);
|
|
155
247
|
//#endregion
|
|
156
248
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rollipop/init",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.2",
|
|
4
4
|
"homepage": "https://github.com/rollipop-dev/rollipop#readme",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/rollipop-dev/rollipop/issues"
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@oxc-node/core": "^0.1.3",
|
|
34
34
|
"typescript": "7.0.2",
|
|
35
|
-
"vite-plus": "
|
|
35
|
+
"vite-plus": "1.3.0"
|
|
36
36
|
},
|
|
37
37
|
"installConfig": {
|
|
38
38
|
"hoistingLimits": "none"
|