@rollipop/init 0.1.0-dev.20260118071417 → 0.1.0-dev.20260424074146
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/CHANGELOG.md +20 -0
- package/dist/index.js +120 -89
- package/package.json +21 -24
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @rollipop/init
|
|
2
2
|
|
|
3
|
+
## 0.1.0-alpha.17
|
|
4
|
+
|
|
5
|
+
## 0.1.0-alpha.16
|
|
6
|
+
|
|
7
|
+
## 0.1.0-alpha.15
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 922142f: update `commands` instead of patching script
|
|
12
|
+
|
|
13
|
+
## 0.1.0-alpha.14
|
|
14
|
+
|
|
15
|
+
## 0.1.0-alpha.13
|
|
16
|
+
|
|
17
|
+
## 0.1.0-alpha.12
|
|
18
|
+
|
|
19
|
+
## 0.1.0-alpha.11
|
|
20
|
+
|
|
21
|
+
## 0.1.0-alpha.10
|
|
22
|
+
|
|
3
23
|
## 0.1.0-alpha.9
|
|
4
24
|
|
|
5
25
|
## 0.1.0-alpha.8
|
package/dist/index.js
CHANGED
|
@@ -1,120 +1,151 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
1
2
|
import fs from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
4
|
+
import { Visitor, parseSync } from "oxc-parser";
|
|
5
|
+
//#region src/init.ts
|
|
6
|
+
const RN_CONFIG_FILE = "react-native.config.js";
|
|
7
|
+
const COMMANDS_REQUIRE = "require('rollipop/commands')";
|
|
8
|
+
function setupReactNativeConfig(cwd) {
|
|
9
|
+
const configPath = path.join(cwd, RN_CONFIG_FILE);
|
|
10
|
+
if (!fs.existsSync(configPath)) {
|
|
11
|
+
fs.writeFileSync(configPath, `module.exports = {\n commands: ${COMMANDS_REQUIRE},\n};\n`);
|
|
12
|
+
return "created";
|
|
13
|
+
}
|
|
14
|
+
const content = fs.readFileSync(configPath, "utf8");
|
|
15
|
+
const result = analyzeConfig(content);
|
|
16
|
+
switch (result.status) {
|
|
17
|
+
case "already-configured": return "already-configured";
|
|
18
|
+
case "has-other-commands": throw new Error(`'commands' property already exists with a different value`);
|
|
19
|
+
case "not-object-export": return "manual-required";
|
|
20
|
+
case "injectable": {
|
|
21
|
+
const updated = applyInjection(content, result.insertOffset, result.needsComma);
|
|
22
|
+
fs.writeFileSync(configPath, updated);
|
|
23
|
+
return "updated";
|
|
24
|
+
}
|
|
17
25
|
}
|
|
18
|
-
};
|
|
19
|
-
async function findAppBuildGradle(cwd$1) {
|
|
20
|
-
const files = await glob("**/android/app/build.gradle", { cwd: cwd$1 });
|
|
21
|
-
if (files.length === 0) throw new Error("No Android build.gradle found");
|
|
22
|
-
if (files.length > 1) throw new Error("Multiple Android build.gradle found:\n" + files.join("\n"));
|
|
23
|
-
return path.join(cwd$1, files[0]);
|
|
24
26
|
}
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
function analyzeConfig(content) {
|
|
28
|
+
const { program } = parseSync("react-native.config.js", content);
|
|
29
|
+
let moduleExportsAssignment = null;
|
|
30
|
+
new Visitor({ AssignmentExpression(node) {
|
|
31
|
+
if (isModuleExports(node)) moduleExportsAssignment = node;
|
|
32
|
+
} }).visit(program);
|
|
33
|
+
if (!moduleExportsAssignment) return { status: "not-object-export" };
|
|
34
|
+
const assignment = moduleExportsAssignment;
|
|
35
|
+
if (assignment.right.type !== "ObjectExpression") return { status: "not-object-export" };
|
|
36
|
+
const objectExpr = assignment.right;
|
|
37
|
+
const commandsProp = findCommandsProperty(objectExpr);
|
|
38
|
+
if (commandsProp) {
|
|
39
|
+
if (isRollipopCommandsRequire(commandsProp, content)) return { status: "already-configured" };
|
|
40
|
+
return { status: "has-other-commands" };
|
|
41
|
+
}
|
|
42
|
+
const properties = objectExpr.properties;
|
|
43
|
+
const lastProp = properties[properties.length - 1];
|
|
44
|
+
const closingBrace = objectExpr.end - 1;
|
|
45
|
+
if (lastProp) {
|
|
46
|
+
const commaIndex = content.substring(lastProp.end, closingBrace).indexOf(",");
|
|
47
|
+
if (commaIndex !== -1) return {
|
|
48
|
+
status: "injectable",
|
|
49
|
+
insertOffset: lastProp.end + commaIndex + 1,
|
|
50
|
+
needsComma: false
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
status: "injectable",
|
|
54
|
+
insertOffset: lastProp.end,
|
|
55
|
+
needsComma: true
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
status: "injectable",
|
|
60
|
+
insertOffset: closingBrace,
|
|
61
|
+
needsComma: false
|
|
62
|
+
};
|
|
35
63
|
}
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
cwd: basePath,
|
|
40
|
-
ignore: ["Pods/**"]
|
|
41
|
-
});
|
|
42
|
-
if (files.length === 0) throw new Error("No Xcode project found");
|
|
43
|
-
if (files.length > 1) throw new Error("Multiple Xcode projects found:\n" + files.join("\n"));
|
|
44
|
-
return path.join(basePath, files[0]);
|
|
64
|
+
function isModuleExports(node) {
|
|
65
|
+
const left = node.left;
|
|
66
|
+
return left.type === "MemberExpression" && left.object.type === "Identifier" && left.object.name === "module" && left.property.type === "Identifier" && left.property.name === "exports";
|
|
45
67
|
}
|
|
46
|
-
function
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const index = originShellScriptLines.findIndex((line) => line.trim().startsWith("set -"));
|
|
54
|
-
let newShellScript = "";
|
|
55
|
-
if (index === -1) newShellScript = `${EXPORT_CLI_PATH}\n${originShellScript}`;
|
|
56
|
-
else newShellScript = [
|
|
57
|
-
...originShellScriptLines.slice(0, index + 1),
|
|
58
|
-
EXPORT_CLI_PATH,
|
|
59
|
-
...originShellScriptLines.slice(index + 1)
|
|
60
|
-
].join("\n");
|
|
61
|
-
buildPhase[1].shellScript = JSON.stringify(newShellScript);
|
|
62
|
-
fs.writeFileSync(project.filepath, project.writeSync());
|
|
68
|
+
function findCommandsProperty(obj) {
|
|
69
|
+
for (const prop of obj.properties) {
|
|
70
|
+
if (prop.type !== "Property") continue;
|
|
71
|
+
const p = prop;
|
|
72
|
+
if (p.key.type === "Identifier" && p.key.name === "commands" || p.key.type === "Literal" && p.key.value === "commands") return p;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
63
75
|
}
|
|
64
|
-
|
|
65
|
-
|
|
76
|
+
function isRollipopCommandsRequire(prop, content) {
|
|
77
|
+
return content.substring(prop.value.start, prop.value.end).includes("rollipop/commands");
|
|
66
78
|
}
|
|
67
|
-
|
|
68
|
-
|
|
79
|
+
function applyInjection(content, insertOffset, needsComma) {
|
|
80
|
+
const before = content.substring(0, insertOffset);
|
|
81
|
+
const after = content.substring(insertOffset);
|
|
82
|
+
return `${before}${needsComma ? "," : ""}\n commands: ${COMMANDS_REQUIRE},${after}`;
|
|
69
83
|
}
|
|
70
|
-
function setupPackage(cwd
|
|
71
|
-
const packageJsonPath = path.join(cwd
|
|
84
|
+
function setupPackage(cwd) {
|
|
85
|
+
const packageJsonPath = path.join(cwd, "package.json");
|
|
72
86
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
73
87
|
packageJson.devDependencies = {
|
|
74
88
|
...packageJson.devDependencies,
|
|
75
89
|
rollipop: "latest"
|
|
76
90
|
};
|
|
77
|
-
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
91
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n");
|
|
78
92
|
}
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region src/index.ts
|
|
95
|
+
const logger = {
|
|
96
|
+
success(message) {
|
|
97
|
+
console.log(pc.green("✓"), message);
|
|
98
|
+
},
|
|
99
|
+
info(message) {
|
|
100
|
+
console.log(pc.cyan("ℹ"), message);
|
|
101
|
+
},
|
|
102
|
+
warn(message) {
|
|
103
|
+
console.log(pc.yellow("⚠"), message);
|
|
104
|
+
},
|
|
105
|
+
error(message, reason) {
|
|
106
|
+
console.error(pc.red("✗"), `${message}: ${reason instanceof Error ? reason.message : String(reason)}`);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
console.log(`\n${pc.bold(pc.cyan("rollipop"))} ${pc.dim("— Modern build toolkit for React Native")}\n`);
|
|
79
110
|
const cwd = process.cwd();
|
|
80
111
|
let failed = false;
|
|
112
|
+
let hasWarning = false;
|
|
81
113
|
try {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
114
|
+
switch (setupReactNativeConfig(cwd)) {
|
|
115
|
+
case "created":
|
|
116
|
+
logger.success(`Created ${pc.bold("react-native.config.js")}`);
|
|
117
|
+
break;
|
|
118
|
+
case "updated":
|
|
119
|
+
logger.success(`Updated ${pc.bold("react-native.config.js")}`);
|
|
120
|
+
break;
|
|
121
|
+
case "already-configured":
|
|
122
|
+
logger.info(`${pc.bold("react-native.config.js")} already configured`);
|
|
123
|
+
break;
|
|
124
|
+
case "manual-required":
|
|
125
|
+
hasWarning = true;
|
|
126
|
+
logger.warn(`Could not auto-configure: ${pc.bold("module.exports")} is not a plain object`);
|
|
127
|
+
console.log(` ${pc.dim("Add the following to your")} ${pc.bold("react-native.config.js")}${pc.dim(":")}\n ${pc.green("commands: require('rollipop/commands'")})`);
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
91
130
|
} catch (error) {
|
|
92
|
-
logger.error("
|
|
131
|
+
logger.error("React Native CLI setup failed", error);
|
|
93
132
|
failed ||= true;
|
|
94
133
|
}
|
|
95
|
-
|
|
134
|
+
if (hasWarning || failed) console.log();
|
|
96
135
|
try {
|
|
97
|
-
packageManager = (await whichPm(cwd))?.name ?? null;
|
|
98
136
|
setupPackage(cwd);
|
|
99
|
-
logger.success("
|
|
137
|
+
logger.success(`Added ${pc.bold("rollipop")} to ${pc.bold("devDependencies")}`);
|
|
100
138
|
} catch (error) {
|
|
101
139
|
logger.error("Package setup failed", error);
|
|
102
140
|
failed ||= true;
|
|
103
141
|
}
|
|
104
142
|
if (failed) {
|
|
105
|
-
console.
|
|
106
|
-
Failed to setup project automatically
|
|
107
|
-
|
|
108
|
-
Please follow the manual setup guide: ${pc.underline("https://rollipop.dev/docs/get-started/quick-start")}`);
|
|
143
|
+
console.log("\n" + pc.red("Setup failed.") + ` Follow the manual guide: ${pc.underline(pc.cyan("https://rollipop.dev/docs/get-started/quick-start"))}`);
|
|
109
144
|
process.exit(1);
|
|
110
|
-
} else {
|
|
111
|
-
logger.success("Project setup completed");
|
|
112
|
-
if (packageManager == null) console.log("No package manager found, please install dependencies manually");
|
|
113
|
-
else {
|
|
114
|
-
const command = pc.bold(`${packageManager} install`);
|
|
115
|
-
console.log(`Run ${command} to install dependencies`);
|
|
116
|
-
}
|
|
117
145
|
}
|
|
118
|
-
|
|
146
|
+
logger.success(pc.bold("Setup completed!"));
|
|
147
|
+
console.log();
|
|
148
|
+
console.log(` ${pc.dim("Install dependencies manually to finish setup.")}`);
|
|
149
|
+
console.log(` ${pc.dim("See")} ${pc.underline(pc.cyan("https://rollipop.dev"))} ${pc.dim("for configuration details.")}`);
|
|
119
150
|
//#endregion
|
|
120
|
-
export {
|
|
151
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,41 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rollipop/init",
|
|
3
|
-
"version": "0.1.0-dev.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
"version": "0.1.0-dev.20260424074146",
|
|
4
|
+
"homepage": "https://github.com/leegeunhyeok/rollipop#readme",
|
|
5
|
+
"bugs": {
|
|
6
|
+
"url": "https://github.com/leegeunhyeok/rollipop/issues"
|
|
7
|
+
},
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"author": "leegeunhyeok <dev.ghlee@gmail.com> (https://github.com/leegeunhyeok)",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "git+https://github.com/leegeunhyeok/rollipop.git",
|
|
13
13
|
"directory": "packages/core"
|
|
14
14
|
},
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
"
|
|
15
|
+
"bin": "./bin/index.js",
|
|
16
|
+
"files": [
|
|
17
|
+
"bin",
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"type": "module",
|
|
21
21
|
"scripts": {
|
|
22
|
-
"execute": "
|
|
22
|
+
"execute": "node --import @oxc-node/core/register src/index.ts",
|
|
23
23
|
"prepack": "yarn build",
|
|
24
24
|
"typecheck": "tsc --noEmit",
|
|
25
|
-
"test": "
|
|
26
|
-
"build": "
|
|
25
|
+
"test": "vp test --run --passWithNoTests",
|
|
26
|
+
"build": "vp pack"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"
|
|
30
|
-
"picocolors": "^1.1.1"
|
|
31
|
-
"which-pm": "^3.0.1",
|
|
32
|
-
"xcode": "^3.0.1"
|
|
29
|
+
"oxc-parser": "^0.121.0",
|
|
30
|
+
"picocolors": "^1.1.1"
|
|
33
31
|
},
|
|
34
32
|
"devDependencies": {
|
|
35
|
-
"
|
|
36
|
-
"tsx": "^4.21.0",
|
|
33
|
+
"@oxc-node/core": "^0.0.35",
|
|
37
34
|
"typescript": "5.9.3",
|
|
38
|
-
"
|
|
35
|
+
"vite-plus": "latest"
|
|
39
36
|
},
|
|
40
|
-
"stableVersion": "0.1.0-alpha.
|
|
37
|
+
"stableVersion": "0.1.0-alpha.17"
|
|
41
38
|
}
|