@tamer4lynx/cli 0.0.2 → 0.0.3
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/dist/index.js +203 -234
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7,12 +7,12 @@ process.on("warning", (w) => {
|
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
// index.ts
|
|
10
|
-
import
|
|
10
|
+
import fs24 from "fs";
|
|
11
11
|
import path25 from "path";
|
|
12
12
|
import { program } from "commander";
|
|
13
13
|
|
|
14
14
|
// package.json
|
|
15
|
-
var version = "0.0.
|
|
15
|
+
var version = "0.0.3";
|
|
16
16
|
|
|
17
17
|
// src/android/create.ts
|
|
18
18
|
import fs3 from "fs";
|
|
@@ -213,6 +213,7 @@ function findRepoRoot(start2) {
|
|
|
213
213
|
}
|
|
214
214
|
function findDevAppPackage(projectRoot) {
|
|
215
215
|
const candidates = [
|
|
216
|
+
path2.join(projectRoot, "node_modules", "@tamer4lynx", "tamer-dev-app"),
|
|
216
217
|
path2.join(projectRoot, "node_modules", "tamer-dev-app"),
|
|
217
218
|
path2.join(projectRoot, "packages", "tamer-dev-app"),
|
|
218
219
|
path2.join(path2.dirname(projectRoot), "tamer-dev-app")
|
|
@@ -226,6 +227,7 @@ function findDevAppPackage(projectRoot) {
|
|
|
226
227
|
}
|
|
227
228
|
function findDevClientPackage(projectRoot) {
|
|
228
229
|
const candidates = [
|
|
230
|
+
path2.join(projectRoot, "node_modules", "@tamer4lynx", "tamer-dev-client"),
|
|
229
231
|
path2.join(projectRoot, "node_modules", "tamer-dev-client"),
|
|
230
232
|
path2.join(projectRoot, "packages", "tamer-dev-client"),
|
|
231
233
|
path2.join(path2.dirname(projectRoot), "tamer-dev-client")
|
|
@@ -321,17 +323,25 @@ function resolveIconPaths(projectRoot, config) {
|
|
|
321
323
|
}
|
|
322
324
|
return Object.keys(out).length ? out : null;
|
|
323
325
|
}
|
|
324
|
-
function resolveDevAppPaths(
|
|
325
|
-
const devAppDir =
|
|
326
|
+
function resolveDevAppPaths(searchRoot) {
|
|
327
|
+
const devAppDir = findDevAppPackage(searchRoot) ?? findDevAppPackage(findRepoRoot(searchRoot));
|
|
328
|
+
if (!devAppDir) {
|
|
329
|
+
throw new Error("tamer-dev-app not found. Add @tamer4lynx/tamer-dev-app to dependencies, or run from the tamer4lynx monorepo.");
|
|
330
|
+
}
|
|
326
331
|
const configPath = path2.join(devAppDir, "tamer.config.json");
|
|
327
332
|
if (!fs2.existsSync(configPath)) {
|
|
328
|
-
throw new Error(
|
|
333
|
+
throw new Error(`tamer.config.json not found in ${devAppDir}`);
|
|
329
334
|
}
|
|
330
335
|
const config = JSON.parse(fs2.readFileSync(configPath, "utf8"));
|
|
331
336
|
const packageName = config.android?.packageName ?? "com.nanofuxion.tamerdevapp";
|
|
332
337
|
const androidDirRel = config.paths?.androidDir ?? "android";
|
|
333
338
|
const androidDir = path2.join(devAppDir, androidDirRel);
|
|
334
|
-
const
|
|
339
|
+
const inDevAppScoped = path2.join(devAppDir, "node_modules", "@tamer4lynx", "tamer-dev-client");
|
|
340
|
+
const inDevAppFlat = path2.join(devAppDir, "node_modules", "tamer-dev-client");
|
|
341
|
+
const devClientDir = findDevClientPackage(searchRoot) ?? findDevClientPackage(findRepoRoot(searchRoot)) ?? (fs2.existsSync(path2.join(inDevAppScoped, "package.json")) ? inDevAppScoped : null) ?? (fs2.existsSync(path2.join(inDevAppFlat, "package.json")) ? inDevAppFlat : null);
|
|
342
|
+
if (!devClientDir || !fs2.existsSync(devClientDir)) {
|
|
343
|
+
throw new Error("tamer-dev-client not found. Add @tamer4lynx/tamer-dev-client (or tamer-dev-app pulls it in).");
|
|
344
|
+
}
|
|
335
345
|
const lynxBundlePath = path2.join(devClientDir, DEFAULT_BUNDLE_ROOT, "dev-client.lynx.bundle");
|
|
336
346
|
return {
|
|
337
347
|
projectRoot: devAppDir,
|
|
@@ -919,30 +929,13 @@ function readAndSubstituteTemplate(templatePath, vars) {
|
|
|
919
929
|
raw
|
|
920
930
|
);
|
|
921
931
|
}
|
|
922
|
-
function findRepoRoot2(start2) {
|
|
923
|
-
let dir = path3.resolve(start2);
|
|
924
|
-
const root = path3.parse(dir).root;
|
|
925
|
-
while (dir !== root) {
|
|
926
|
-
const pkgPath = path3.join(dir, "package.json");
|
|
927
|
-
if (fs3.existsSync(pkgPath)) {
|
|
928
|
-
try {
|
|
929
|
-
const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf8"));
|
|
930
|
-
if (pkg.workspaces) return dir;
|
|
931
|
-
} catch {
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
dir = path3.dirname(dir);
|
|
935
|
-
}
|
|
936
|
-
return start2;
|
|
937
|
-
}
|
|
938
932
|
var create = async (opts = {}) => {
|
|
939
933
|
const target = opts.target ?? "host";
|
|
940
934
|
const origCwd = process.cwd();
|
|
941
935
|
if (target === "dev-app") {
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
console.error("\u274C packages/tamer-dev-app/tamer.config.json not found.");
|
|
936
|
+
const devAppDir = findDevAppPackage(origCwd) ?? findDevAppPackage(findRepoRoot(origCwd));
|
|
937
|
+
if (!devAppDir || !fs3.existsSync(path3.join(devAppDir, "tamer.config.json"))) {
|
|
938
|
+
console.error("\u274C tamer-dev-app not found. Add @tamer4lynx/tamer-dev-app to dependencies.");
|
|
946
939
|
process.exit(1);
|
|
947
940
|
}
|
|
948
941
|
process.chdir(devAppDir);
|
|
@@ -2093,22 +2086,6 @@ $1$2`);
|
|
|
2093
2086
|
var syncDevClient_default = syncDevClient;
|
|
2094
2087
|
|
|
2095
2088
|
// src/android/bundle.ts
|
|
2096
|
-
function findRepoRoot3(start2) {
|
|
2097
|
-
let dir = path9.resolve(start2);
|
|
2098
|
-
const root = path9.parse(dir).root;
|
|
2099
|
-
while (dir !== root) {
|
|
2100
|
-
const pkgPath = path9.join(dir, "package.json");
|
|
2101
|
-
if (fs9.existsSync(pkgPath)) {
|
|
2102
|
-
try {
|
|
2103
|
-
const pkg = JSON.parse(fs9.readFileSync(pkgPath, "utf8"));
|
|
2104
|
-
if (pkg.workspaces) return dir;
|
|
2105
|
-
} catch {
|
|
2106
|
-
}
|
|
2107
|
-
}
|
|
2108
|
-
dir = path9.dirname(dir);
|
|
2109
|
-
}
|
|
2110
|
-
return start2;
|
|
2111
|
-
}
|
|
2112
2089
|
async function bundleAndDeploy(opts = {}) {
|
|
2113
2090
|
const target = opts.target ?? "host";
|
|
2114
2091
|
const release = opts.release === true;
|
|
@@ -2116,8 +2093,7 @@ async function bundleAndDeploy(opts = {}) {
|
|
|
2116
2093
|
let resolved;
|
|
2117
2094
|
try {
|
|
2118
2095
|
if (target === "dev-app") {
|
|
2119
|
-
|
|
2120
|
-
resolved = resolveDevAppPaths(repoRoot);
|
|
2096
|
+
resolved = resolveDevAppPaths(origCwd);
|
|
2121
2097
|
const devAppDir = resolved.projectRoot;
|
|
2122
2098
|
const androidDir = resolved.androidDir;
|
|
2123
2099
|
if (!fs9.existsSync(androidDir)) {
|
|
@@ -2189,28 +2165,22 @@ async function bundleAndDeploy(opts = {}) {
|
|
|
2189
2165
|
var bundle_default = bundleAndDeploy;
|
|
2190
2166
|
|
|
2191
2167
|
// src/android/build.ts
|
|
2192
|
-
import fs10 from "fs";
|
|
2193
2168
|
import path10 from "path";
|
|
2194
2169
|
import { execSync as execSync3 } from "child_process";
|
|
2195
|
-
function findRepoRoot4(start2) {
|
|
2196
|
-
let dir = path10.resolve(start2);
|
|
2197
|
-
const root = path10.parse(dir).root;
|
|
2198
|
-
while (dir !== root) {
|
|
2199
|
-
const pkgPath = path10.join(dir, "package.json");
|
|
2200
|
-
if (fs10.existsSync(pkgPath)) {
|
|
2201
|
-
try {
|
|
2202
|
-
const pkg = JSON.parse(fs10.readFileSync(pkgPath, "utf8"));
|
|
2203
|
-
if (pkg.workspaces) return dir;
|
|
2204
|
-
} catch {
|
|
2205
|
-
}
|
|
2206
|
-
}
|
|
2207
|
-
dir = path10.dirname(dir);
|
|
2208
|
-
}
|
|
2209
|
-
return start2;
|
|
2210
|
-
}
|
|
2211
2170
|
async function buildApk(opts = {}) {
|
|
2212
2171
|
const target = opts.target ?? "host";
|
|
2213
|
-
|
|
2172
|
+
let resolved;
|
|
2173
|
+
try {
|
|
2174
|
+
resolved = target === "dev-app" ? resolveDevAppPaths(process.cwd()) : resolveHostPaths();
|
|
2175
|
+
} catch (error) {
|
|
2176
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
2177
|
+
if (target === "dev-app") {
|
|
2178
|
+
console.error(`\u274C ${msg}`);
|
|
2179
|
+
console.error(" Add @tamer4lynx/tamer-dev-app to dependencies, or use -t host to build your app.");
|
|
2180
|
+
process.exit(1);
|
|
2181
|
+
}
|
|
2182
|
+
throw error;
|
|
2183
|
+
}
|
|
2214
2184
|
await bundle_default({ target, release: opts.release });
|
|
2215
2185
|
const androidDir = resolved.androidDir;
|
|
2216
2186
|
const gradlew = path10.join(androidDir, process.platform === "win32" ? "gradlew.bat" : "gradlew");
|
|
@@ -2238,12 +2208,12 @@ async function buildApk(opts = {}) {
|
|
|
2238
2208
|
var build_default = buildApk;
|
|
2239
2209
|
|
|
2240
2210
|
// src/ios/create.ts
|
|
2241
|
-
import
|
|
2211
|
+
import fs11 from "fs";
|
|
2242
2212
|
import path12 from "path";
|
|
2243
2213
|
|
|
2244
2214
|
// src/ios/getPod.ts
|
|
2245
2215
|
import { execSync as execSync4 } from "child_process";
|
|
2246
|
-
import
|
|
2216
|
+
import fs10 from "fs";
|
|
2247
2217
|
import path11 from "path";
|
|
2248
2218
|
function isCocoaPodsInstalled() {
|
|
2249
2219
|
try {
|
|
@@ -2267,7 +2237,7 @@ async function setupCocoaPods(rootDir) {
|
|
|
2267
2237
|
try {
|
|
2268
2238
|
console.log("\u{1F4E6} CocoaPods is installed. Proceeding with dependency installation...");
|
|
2269
2239
|
const podfilePath = path11.join(rootDir, "Podfile");
|
|
2270
|
-
if (!
|
|
2240
|
+
if (!fs10.existsSync(podfilePath)) {
|
|
2271
2241
|
throw new Error(`Podfile not found at ${podfilePath}`);
|
|
2272
2242
|
}
|
|
2273
2243
|
console.log(`\u{1F680} Executing pod install in: ${rootDir}`);
|
|
@@ -2285,7 +2255,7 @@ async function setupCocoaPods(rootDir) {
|
|
|
2285
2255
|
// src/ios/create.ts
|
|
2286
2256
|
import { randomBytes } from "crypto";
|
|
2287
2257
|
function readAndSubstituteTemplate3(templatePath, vars) {
|
|
2288
|
-
const raw =
|
|
2258
|
+
const raw = fs11.readFileSync(templatePath, "utf-8");
|
|
2289
2259
|
return Object.entries(vars).reduce(
|
|
2290
2260
|
(s, [k, v]) => s.replace(new RegExp(`\\{\\{${k}\\}\\}`, "g"), v),
|
|
2291
2261
|
raw
|
|
@@ -2313,12 +2283,12 @@ var create2 = () => {
|
|
|
2313
2283
|
const xcodeprojDir = path12.join(rootDir, `${appName}.xcodeproj`);
|
|
2314
2284
|
const bridgingHeader = `${appName}-Bridging-Header.h`;
|
|
2315
2285
|
function writeFile3(filePath, content) {
|
|
2316
|
-
|
|
2317
|
-
|
|
2286
|
+
fs11.mkdirSync(path12.dirname(filePath), { recursive: true });
|
|
2287
|
+
fs11.writeFileSync(filePath, content.trimStart(), "utf8");
|
|
2318
2288
|
}
|
|
2319
|
-
if (
|
|
2289
|
+
if (fs11.existsSync(rootDir)) {
|
|
2320
2290
|
console.log(`\u{1F9F9} Removing existing directory: ${rootDir}`);
|
|
2321
|
-
|
|
2291
|
+
fs11.rmSync(rootDir, { recursive: true, force: true });
|
|
2322
2292
|
}
|
|
2323
2293
|
console.log(`\u{1F680} Creating a new Tamer4Lynx project in: ${rootDir}`);
|
|
2324
2294
|
const ids = {
|
|
@@ -2417,7 +2387,7 @@ end
|
|
|
2417
2387
|
const templateDir = path12.join(hostPkg, "ios", "templates");
|
|
2418
2388
|
for (const f of ["AppDelegate.swift", "SceneDelegate.swift", "ViewController.swift", "LynxProvider.swift", "LynxInitProcessor.swift"]) {
|
|
2419
2389
|
const srcPath = path12.join(templateDir, f);
|
|
2420
|
-
if (
|
|
2390
|
+
if (fs11.existsSync(srcPath)) {
|
|
2421
2391
|
writeFile3(path12.join(projectDir, f), readAndSubstituteTemplate3(srcPath, templateVars));
|
|
2422
2392
|
}
|
|
2423
2393
|
}
|
|
@@ -2648,23 +2618,23 @@ final class LynxInitProcessor {
|
|
|
2648
2618
|
</plist>
|
|
2649
2619
|
`);
|
|
2650
2620
|
const appIconDir = path12.join(projectDir, "Assets.xcassets", "AppIcon.appiconset");
|
|
2651
|
-
|
|
2621
|
+
fs11.mkdirSync(appIconDir, { recursive: true });
|
|
2652
2622
|
const iconPaths = resolveIconPaths(process.cwd(), config);
|
|
2653
2623
|
if (iconPaths?.ios) {
|
|
2654
|
-
const entries =
|
|
2624
|
+
const entries = fs11.readdirSync(iconPaths.ios, { withFileTypes: true });
|
|
2655
2625
|
for (const e of entries) {
|
|
2656
2626
|
const dest = path12.join(appIconDir, e.name);
|
|
2657
2627
|
if (e.isDirectory()) {
|
|
2658
|
-
|
|
2628
|
+
fs11.cpSync(path12.join(iconPaths.ios, e.name), dest, { recursive: true });
|
|
2659
2629
|
} else {
|
|
2660
|
-
|
|
2630
|
+
fs11.copyFileSync(path12.join(iconPaths.ios, e.name), dest);
|
|
2661
2631
|
}
|
|
2662
2632
|
}
|
|
2663
2633
|
console.log("\u2705 Copied iOS icon from tamer.config.json icon.ios");
|
|
2664
2634
|
} else if (iconPaths?.source) {
|
|
2665
2635
|
const ext = path12.extname(iconPaths.source) || ".png";
|
|
2666
2636
|
const icon1024 = `Icon-1024${ext}`;
|
|
2667
|
-
|
|
2637
|
+
fs11.copyFileSync(iconPaths.source, path12.join(appIconDir, icon1024));
|
|
2668
2638
|
writeFile3(path12.join(appIconDir, "Contents.json"), JSON.stringify({
|
|
2669
2639
|
images: [{ filename: icon1024, idiom: "universal", platform: "ios", size: "1024x1024" }],
|
|
2670
2640
|
info: { author: "xcode", version: 1 }
|
|
@@ -2678,7 +2648,7 @@ final class LynxInitProcessor {
|
|
|
2678
2648
|
}
|
|
2679
2649
|
`);
|
|
2680
2650
|
}
|
|
2681
|
-
|
|
2651
|
+
fs11.mkdirSync(xcodeprojDir, { recursive: true });
|
|
2682
2652
|
writeFile3(path12.join(xcodeprojDir, "project.pbxproj"), `
|
|
2683
2653
|
// !$*UTF8*$!
|
|
2684
2654
|
{
|
|
@@ -2965,7 +2935,7 @@ final class LynxInitProcessor {
|
|
|
2965
2935
|
var create_default2 = create2;
|
|
2966
2936
|
|
|
2967
2937
|
// src/ios/autolink.ts
|
|
2968
|
-
import
|
|
2938
|
+
import fs12 from "fs";
|
|
2969
2939
|
import path13 from "path";
|
|
2970
2940
|
import { execSync as execSync5 } from "child_process";
|
|
2971
2941
|
var autolink2 = () => {
|
|
@@ -2979,11 +2949,11 @@ var autolink2 = () => {
|
|
|
2979
2949
|
const projectRoot = resolved.projectRoot;
|
|
2980
2950
|
const iosProjectPath = resolved.iosDir;
|
|
2981
2951
|
function updateGeneratedSection(filePath, newContent, startMarker, endMarker) {
|
|
2982
|
-
if (!
|
|
2952
|
+
if (!fs12.existsSync(filePath)) {
|
|
2983
2953
|
console.warn(`\u26A0\uFE0F File not found, skipping update: ${filePath}`);
|
|
2984
2954
|
return;
|
|
2985
2955
|
}
|
|
2986
|
-
let fileContent =
|
|
2956
|
+
let fileContent = fs12.readFileSync(filePath, "utf8");
|
|
2987
2957
|
const escapedStartMarker = startMarker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2988
2958
|
const escapedEndMarker = endMarker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2989
2959
|
const regex = new RegExp(`${escapedStartMarker}[\\s\\S]*?${escapedEndMarker}`, "g");
|
|
@@ -3008,15 +2978,15 @@ ${replacementBlock}
|
|
|
3008
2978
|
${replacementBlock}
|
|
3009
2979
|
`;
|
|
3010
2980
|
}
|
|
3011
|
-
|
|
2981
|
+
fs12.writeFileSync(filePath, fileContent, "utf8");
|
|
3012
2982
|
console.log(`\u2705 Updated autolinked section in ${path13.basename(filePath)}`);
|
|
3013
2983
|
}
|
|
3014
2984
|
function resolvePodName(pkg) {
|
|
3015
2985
|
const podspecDir = pkg.config.ios?.podspecPath || ".";
|
|
3016
2986
|
const fullPodspecDir = path13.join(pkg.packagePath, podspecDir);
|
|
3017
|
-
if (
|
|
2987
|
+
if (fs12.existsSync(fullPodspecDir)) {
|
|
3018
2988
|
try {
|
|
3019
|
-
const files =
|
|
2989
|
+
const files = fs12.readdirSync(fullPodspecDir);
|
|
3020
2990
|
const podspecFile = files.find((f) => f.endsWith(".podspec"));
|
|
3021
2991
|
if (podspecFile) return podspecFile.replace(".podspec", "");
|
|
3022
2992
|
} catch {
|
|
@@ -3050,7 +3020,7 @@ ${replacementBlock}
|
|
|
3050
3020
|
candidatePaths.push(path13.join(iosProjectPath, appNameFromConfig, "LynxInitProcessor.swift"));
|
|
3051
3021
|
}
|
|
3052
3022
|
candidatePaths.push(path13.join(iosProjectPath, "LynxInitProcessor.swift"));
|
|
3053
|
-
const found = candidatePaths.find((p) =>
|
|
3023
|
+
const found = candidatePaths.find((p) => fs12.existsSync(p));
|
|
3054
3024
|
const lynxInitPath = found ?? candidatePaths[0];
|
|
3055
3025
|
const iosPackages = packages.filter((p) => getIosModuleClassNames(p.config.ios).length > 0 || Object.keys(getIosElements(p.config.ios)).length > 0);
|
|
3056
3026
|
function updateImportsSection(filePath, pkgs) {
|
|
@@ -3065,7 +3035,7 @@ ${replacementBlock}
|
|
|
3065
3035
|
const podName = resolvePodName(pkg);
|
|
3066
3036
|
return `import ${podName}`;
|
|
3067
3037
|
}).join("\n");
|
|
3068
|
-
const fileContent =
|
|
3038
|
+
const fileContent = fs12.readFileSync(filePath, "utf8");
|
|
3069
3039
|
if (fileContent.indexOf(startMarker) !== -1) {
|
|
3070
3040
|
updateGeneratedSection(filePath, imports, startMarker, endMarker);
|
|
3071
3041
|
return;
|
|
@@ -3102,7 +3072,7 @@ ${after}`;
|
|
|
3102
3072
|
${fileContent}`;
|
|
3103
3073
|
}
|
|
3104
3074
|
}
|
|
3105
|
-
|
|
3075
|
+
fs12.writeFileSync(filePath, newContent, "utf8");
|
|
3106
3076
|
console.log(`\u2705 Updated imports in ${path13.basename(filePath)}`);
|
|
3107
3077
|
}
|
|
3108
3078
|
updateImportsSection(lynxInitPath, iosPackages);
|
|
@@ -3133,10 +3103,10 @@ ${fileContent}`;
|
|
|
3133
3103
|
candidates.push(path13.join(iosProjectPath, appNameFromConfig, "Info.plist"));
|
|
3134
3104
|
}
|
|
3135
3105
|
candidates.push(path13.join(iosProjectPath, "Info.plist"));
|
|
3136
|
-
return candidates.find((p) =>
|
|
3106
|
+
return candidates.find((p) => fs12.existsSync(p)) ?? null;
|
|
3137
3107
|
}
|
|
3138
3108
|
function readPlistXml(plistPath) {
|
|
3139
|
-
return
|
|
3109
|
+
return fs12.readFileSync(plistPath, "utf8");
|
|
3140
3110
|
}
|
|
3141
3111
|
function syncInfoPlistPermissions(packages) {
|
|
3142
3112
|
const plistPath = findInfoPlist();
|
|
@@ -3167,7 +3137,7 @@ ${fileContent}`;
|
|
|
3167
3137
|
added++;
|
|
3168
3138
|
}
|
|
3169
3139
|
if (added > 0) {
|
|
3170
|
-
|
|
3140
|
+
fs12.writeFileSync(plistPath, plist, "utf8");
|
|
3171
3141
|
console.log(`\u2705 Synced ${added} Info.plist permission description(s)`);
|
|
3172
3142
|
}
|
|
3173
3143
|
}
|
|
@@ -3214,12 +3184,12 @@ ${schemesXml}
|
|
|
3214
3184
|
$1`
|
|
3215
3185
|
);
|
|
3216
3186
|
}
|
|
3217
|
-
|
|
3187
|
+
fs12.writeFileSync(plistPath, plist, "utf8");
|
|
3218
3188
|
console.log(`\u2705 Synced ${urlSchemes.length} iOS URL scheme(s) into Info.plist`);
|
|
3219
3189
|
}
|
|
3220
3190
|
function runPodInstall(forcePath) {
|
|
3221
3191
|
const podfilePath = forcePath ?? path13.join(iosProjectPath, "Podfile");
|
|
3222
|
-
if (!
|
|
3192
|
+
if (!fs12.existsSync(podfilePath)) {
|
|
3223
3193
|
console.log("\u2139\uFE0F No Podfile found in ios directory; skipping `pod install`.");
|
|
3224
3194
|
return;
|
|
3225
3195
|
}
|
|
@@ -3248,7 +3218,7 @@ $1`
|
|
|
3248
3218
|
const appNameFromConfig = resolved.config.ios?.appName;
|
|
3249
3219
|
if (appNameFromConfig) {
|
|
3250
3220
|
const appPodfile = path13.join(iosProjectPath, appNameFromConfig, "Podfile");
|
|
3251
|
-
if (
|
|
3221
|
+
if (fs12.existsSync(appPodfile)) {
|
|
3252
3222
|
runPodInstall(appPodfile);
|
|
3253
3223
|
console.log("\u2728 Autolinking complete for iOS.");
|
|
3254
3224
|
return;
|
|
@@ -3262,12 +3232,12 @@ $1`
|
|
|
3262
3232
|
var autolink_default2 = autolink2;
|
|
3263
3233
|
|
|
3264
3234
|
// src/ios/bundle.ts
|
|
3265
|
-
import
|
|
3235
|
+
import fs14 from "fs";
|
|
3266
3236
|
import path15 from "path";
|
|
3267
3237
|
import { execSync as execSync6 } from "child_process";
|
|
3268
3238
|
|
|
3269
3239
|
// src/ios/syncHost.ts
|
|
3270
|
-
import
|
|
3240
|
+
import fs13 from "fs";
|
|
3271
3241
|
import path14 from "path";
|
|
3272
3242
|
import crypto from "crypto";
|
|
3273
3243
|
function deterministicUUID(seed) {
|
|
@@ -3316,7 +3286,7 @@ function getLaunchScreenStoryboard() {
|
|
|
3316
3286
|
`;
|
|
3317
3287
|
}
|
|
3318
3288
|
function addLaunchScreenToXcodeProject(pbxprojPath, appName) {
|
|
3319
|
-
let content =
|
|
3289
|
+
let content = fs13.readFileSync(pbxprojPath, "utf8");
|
|
3320
3290
|
if (content.includes("LaunchScreen.storyboard")) return;
|
|
3321
3291
|
const baseFileRefUUID = deterministicUUID(`launchScreenBase:${appName}`);
|
|
3322
3292
|
const variantGroupUUID = deterministicUUID(`launchScreenGroup:${appName}`);
|
|
@@ -3353,11 +3323,11 @@ function addLaunchScreenToXcodeProject(pbxprojPath, appName) {
|
|
|
3353
3323
|
);
|
|
3354
3324
|
content = content.replace(groupPattern, `$1
|
|
3355
3325
|
${variantGroupUUID} /* LaunchScreen.storyboard */,`);
|
|
3356
|
-
|
|
3326
|
+
fs13.writeFileSync(pbxprojPath, content, "utf8");
|
|
3357
3327
|
console.log("\u2705 Registered LaunchScreen.storyboard in Xcode project");
|
|
3358
3328
|
}
|
|
3359
3329
|
function addSwiftSourceToXcodeProject(pbxprojPath, appName, filename) {
|
|
3360
|
-
let content =
|
|
3330
|
+
let content = fs13.readFileSync(pbxprojPath, "utf8");
|
|
3361
3331
|
const escaped = filename.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3362
3332
|
if (new RegExp(`path = ${escaped};`).test(content)) return;
|
|
3363
3333
|
const fileRefUUID = deterministicUUID(`fileRef:${appName}:${filename}`);
|
|
@@ -3382,11 +3352,11 @@ function addSwiftSourceToXcodeProject(pbxprojPath, appName, filename) {
|
|
|
3382
3352
|
);
|
|
3383
3353
|
content = content.replace(groupPattern, `$1
|
|
3384
3354
|
${fileRefUUID} /* ${filename} */,`);
|
|
3385
|
-
|
|
3355
|
+
fs13.writeFileSync(pbxprojPath, content, "utf8");
|
|
3386
3356
|
console.log(`\u2705 Registered ${filename} in Xcode project sources`);
|
|
3387
3357
|
}
|
|
3388
3358
|
function addResourceToXcodeProject(pbxprojPath, appName, filename) {
|
|
3389
|
-
let content =
|
|
3359
|
+
let content = fs13.readFileSync(pbxprojPath, "utf8");
|
|
3390
3360
|
const escaped = filename.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3391
3361
|
if (new RegExp(`path = ${escaped};`).test(content)) return;
|
|
3392
3362
|
const fileRefUUID = deterministicUUID(`fileRef:${appName}:${filename}`);
|
|
@@ -3411,12 +3381,12 @@ function addResourceToXcodeProject(pbxprojPath, appName, filename) {
|
|
|
3411
3381
|
);
|
|
3412
3382
|
content = content.replace(groupPattern, `$1
|
|
3413
3383
|
${fileRefUUID} /* ${filename} */,`);
|
|
3414
|
-
|
|
3384
|
+
fs13.writeFileSync(pbxprojPath, content, "utf8");
|
|
3415
3385
|
console.log(`\u2705 Registered ${filename} in Xcode project resources`);
|
|
3416
3386
|
}
|
|
3417
3387
|
function writeFile(filePath, content) {
|
|
3418
|
-
|
|
3419
|
-
|
|
3388
|
+
fs13.mkdirSync(path14.dirname(filePath), { recursive: true });
|
|
3389
|
+
fs13.writeFileSync(filePath, content, "utf8");
|
|
3420
3390
|
}
|
|
3421
3391
|
function getAppDelegateSwift() {
|
|
3422
3392
|
return `import UIKit
|
|
@@ -3626,8 +3596,8 @@ class ViewController: UIViewController {
|
|
|
3626
3596
|
`;
|
|
3627
3597
|
}
|
|
3628
3598
|
function patchInfoPlist(infoPlistPath) {
|
|
3629
|
-
if (!
|
|
3630
|
-
let content =
|
|
3599
|
+
if (!fs13.existsSync(infoPlistPath)) return;
|
|
3600
|
+
let content = fs13.readFileSync(infoPlistPath, "utf8");
|
|
3631
3601
|
content = content.replace(/\s*<key>UIMainStoryboardFile<\/key>\s*<string>[^<]*<\/string>/g, "");
|
|
3632
3602
|
if (!content.includes("UILaunchStoryboardName")) {
|
|
3633
3603
|
content = content.replace("</dict>\n</plist>", ` <key>UILaunchStoryboardName</key>
|
|
@@ -3659,7 +3629,7 @@ function patchInfoPlist(infoPlistPath) {
|
|
|
3659
3629
|
</plist>`);
|
|
3660
3630
|
console.log("\u2705 Added UIApplicationSceneManifest to Info.plist");
|
|
3661
3631
|
}
|
|
3662
|
-
|
|
3632
|
+
fs13.writeFileSync(infoPlistPath, content, "utf8");
|
|
3663
3633
|
}
|
|
3664
3634
|
function getSimpleLynxProviderSwift() {
|
|
3665
3635
|
return `import Foundation
|
|
@@ -3685,8 +3655,8 @@ class LynxProvider: NSObject, LynxTemplateProvider {
|
|
|
3685
3655
|
function readTemplateOrFallback(devClientPkg, templateName, fallback, vars = {}) {
|
|
3686
3656
|
if (devClientPkg) {
|
|
3687
3657
|
const tplPath = path14.join(devClientPkg, "ios", "templates", templateName);
|
|
3688
|
-
if (
|
|
3689
|
-
let content =
|
|
3658
|
+
if (fs13.existsSync(tplPath)) {
|
|
3659
|
+
let content = fs13.readFileSync(tplPath, "utf8");
|
|
3690
3660
|
for (const [k, v] of Object.entries(vars)) {
|
|
3691
3661
|
content = content.replace(new RegExp(`\\{\\{${k}\\}\\}`, "g"), v);
|
|
3692
3662
|
}
|
|
@@ -3706,7 +3676,7 @@ function syncHostIos(opts) {
|
|
|
3706
3676
|
}
|
|
3707
3677
|
const projectDir = path14.join(resolved.iosDir, appName);
|
|
3708
3678
|
const infoPlistPath = path14.join(projectDir, "Info.plist");
|
|
3709
|
-
if (!
|
|
3679
|
+
if (!fs13.existsSync(projectDir)) {
|
|
3710
3680
|
throw new Error(`iOS project not found at ${projectDir}. Run \`tamer ios create\` first.`);
|
|
3711
3681
|
}
|
|
3712
3682
|
const pbxprojPath = path14.join(resolved.iosDir, `${appName}.xcodeproj`, "project.pbxproj");
|
|
@@ -3715,8 +3685,8 @@ function syncHostIos(opts) {
|
|
|
3715
3685
|
patchInfoPlist(infoPlistPath);
|
|
3716
3686
|
writeFile(path14.join(projectDir, "AppDelegate.swift"), getAppDelegateSwift());
|
|
3717
3687
|
writeFile(path14.join(projectDir, "SceneDelegate.swift"), getSceneDelegateSwift());
|
|
3718
|
-
if (!
|
|
3719
|
-
|
|
3688
|
+
if (!fs13.existsSync(launchScreenPath)) {
|
|
3689
|
+
fs13.mkdirSync(baseLprojDir, { recursive: true });
|
|
3720
3690
|
writeFile(launchScreenPath, getLaunchScreenStoryboard());
|
|
3721
3691
|
addLaunchScreenToXcodeProject(pbxprojPath, appName);
|
|
3722
3692
|
}
|
|
@@ -3792,11 +3762,11 @@ function bundleAndDeploy2(opts = {}) {
|
|
|
3792
3762
|
process.exit(1);
|
|
3793
3763
|
}
|
|
3794
3764
|
try {
|
|
3795
|
-
if (!
|
|
3765
|
+
if (!fs14.existsSync(sourceBundlePath)) {
|
|
3796
3766
|
console.error(`\u274C Build output not found at: ${sourceBundlePath}`);
|
|
3797
3767
|
process.exit(1);
|
|
3798
3768
|
}
|
|
3799
|
-
if (!
|
|
3769
|
+
if (!fs14.existsSync(destinationDir)) {
|
|
3800
3770
|
console.error(`Destination directory not found at: ${destinationDir}`);
|
|
3801
3771
|
process.exit(1);
|
|
3802
3772
|
}
|
|
@@ -3805,10 +3775,10 @@ function bundleAndDeploy2(opts = {}) {
|
|
|
3805
3775
|
copyDistAssets(distDir, destinationDir, resolved.lynxBundleFile);
|
|
3806
3776
|
console.log(`\u2728 Successfully copied bundle to: ${destinationBundlePath}`);
|
|
3807
3777
|
const pbxprojPath = path15.join(resolved.iosDir, `${appName}.xcodeproj`, "project.pbxproj");
|
|
3808
|
-
if (
|
|
3778
|
+
if (fs14.existsSync(pbxprojPath)) {
|
|
3809
3779
|
const skip = /* @__PURE__ */ new Set([".rspeedy", "stats.json"]);
|
|
3810
|
-
for (const entry of
|
|
3811
|
-
if (skip.has(entry) ||
|
|
3780
|
+
for (const entry of fs14.readdirSync(distDir)) {
|
|
3781
|
+
if (skip.has(entry) || fs14.statSync(path15.join(distDir, entry)).isDirectory()) continue;
|
|
3812
3782
|
addResourceToXcodeProject(pbxprojPath, appName, entry);
|
|
3813
3783
|
}
|
|
3814
3784
|
}
|
|
@@ -3824,18 +3794,18 @@ function bundleAndDeploy2(opts = {}) {
|
|
|
3824
3794
|
console.warn("\u26A0\uFE0F dev-client build failed; skipping dev-client bundle");
|
|
3825
3795
|
}
|
|
3826
3796
|
const builtBundle = path15.join(devClientPkg, "dist", "dev-client.lynx.bundle");
|
|
3827
|
-
if (
|
|
3828
|
-
|
|
3797
|
+
if (fs14.existsSync(builtBundle)) {
|
|
3798
|
+
fs14.copyFileSync(builtBundle, devClientBundle);
|
|
3829
3799
|
console.log("\u2728 Copied dev-client.lynx.bundle to iOS project");
|
|
3830
3800
|
const pbxprojPath2 = path15.join(resolved.iosDir, `${appName}.xcodeproj`, "project.pbxproj");
|
|
3831
|
-
if (
|
|
3801
|
+
if (fs14.existsSync(pbxprojPath2)) {
|
|
3832
3802
|
addResourceToXcodeProject(pbxprojPath2, appName, "dev-client.lynx.bundle");
|
|
3833
3803
|
}
|
|
3834
3804
|
}
|
|
3835
3805
|
}
|
|
3836
3806
|
} else {
|
|
3837
|
-
if (!
|
|
3838
|
-
|
|
3807
|
+
if (!fs14.existsSync(devClientBundle)) {
|
|
3808
|
+
fs14.writeFileSync(devClientBundle, "");
|
|
3839
3809
|
}
|
|
3840
3810
|
console.log("\u2139\uFE0F Skipped dev-client bundle (release build)");
|
|
3841
3811
|
}
|
|
@@ -3849,17 +3819,17 @@ function bundleAndDeploy2(opts = {}) {
|
|
|
3849
3819
|
var bundle_default2 = bundleAndDeploy2;
|
|
3850
3820
|
|
|
3851
3821
|
// src/ios/build.ts
|
|
3852
|
-
import
|
|
3822
|
+
import fs16 from "fs";
|
|
3853
3823
|
import path17 from "path";
|
|
3854
3824
|
import { execSync as execSync8 } from "child_process";
|
|
3855
3825
|
|
|
3856
3826
|
// src/ios/syncDevClient.ts
|
|
3857
|
-
import
|
|
3827
|
+
import fs15 from "fs";
|
|
3858
3828
|
import path16 from "path";
|
|
3859
3829
|
import { execSync as execSync7 } from "child_process";
|
|
3860
3830
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
3861
3831
|
function readAndSubstituteTemplate4(templatePath, vars) {
|
|
3862
|
-
const raw =
|
|
3832
|
+
const raw = fs15.readFileSync(templatePath, "utf-8");
|
|
3863
3833
|
return Object.entries(vars).reduce(
|
|
3864
3834
|
(s, [k, v]) => s.replace(new RegExp(`\\{\\{${k}\\}\\}`, "g"), v),
|
|
3865
3835
|
raw
|
|
@@ -3872,8 +3842,8 @@ function generateId() {
|
|
|
3872
3842
|
return randomBytes2(12).toString("hex").toUpperCase();
|
|
3873
3843
|
}
|
|
3874
3844
|
function writeFile2(filePath, content) {
|
|
3875
|
-
|
|
3876
|
-
|
|
3845
|
+
fs15.mkdirSync(path16.dirname(filePath), { recursive: true });
|
|
3846
|
+
fs15.writeFileSync(filePath, content, "utf8");
|
|
3877
3847
|
}
|
|
3878
3848
|
function getAppDelegateSwift2() {
|
|
3879
3849
|
return `import UIKit
|
|
@@ -4886,8 +4856,8 @@ function generatePbxproj(ids) {
|
|
|
4886
4856
|
async function createDevAppProject(iosDir, repoRoot) {
|
|
4887
4857
|
const projectDir = path16.join(iosDir, APP_NAME);
|
|
4888
4858
|
const xcodeprojDir = path16.join(iosDir, `${APP_NAME}.xcodeproj`);
|
|
4889
|
-
if (
|
|
4890
|
-
|
|
4859
|
+
if (fs15.existsSync(iosDir)) {
|
|
4860
|
+
fs15.rmSync(iosDir, { recursive: true, force: true });
|
|
4891
4861
|
}
|
|
4892
4862
|
console.log(`\u{1F680} Creating TamerDevApp iOS project at: ${iosDir}`);
|
|
4893
4863
|
const ids = {};
|
|
@@ -4953,7 +4923,7 @@ async function createDevAppProject(iosDir, repoRoot) {
|
|
|
4953
4923
|
];
|
|
4954
4924
|
for (const f of templateFiles) {
|
|
4955
4925
|
const src = templateDir ? path16.join(templateDir, f) : null;
|
|
4956
|
-
if (src &&
|
|
4926
|
+
if (src && fs15.existsSync(src)) {
|
|
4957
4927
|
writeFile2(path16.join(projectDir, f), readAndSubstituteTemplate4(src, templateVars));
|
|
4958
4928
|
} else {
|
|
4959
4929
|
const fallback = (() => {
|
|
@@ -4990,7 +4960,7 @@ async function createDevAppProject(iosDir, repoRoot) {
|
|
|
4990
4960
|
JSON.stringify({ info: { author: "xcode", version: 1 } }, null, 2)
|
|
4991
4961
|
);
|
|
4992
4962
|
writeFile2(path16.join(projectDir, "dev-client.lynx.bundle"), "");
|
|
4993
|
-
|
|
4963
|
+
fs15.mkdirSync(xcodeprojDir, { recursive: true });
|
|
4994
4964
|
writeFile2(path16.join(xcodeprojDir, "project.pbxproj"), generatePbxproj(ids));
|
|
4995
4965
|
console.log(`\u2705 TamerDevApp iOS project created at ${iosDir}`);
|
|
4996
4966
|
await setupCocoaPods(iosDir);
|
|
@@ -4999,8 +4969,8 @@ async function syncDevClientIos() {
|
|
|
4999
4969
|
let resolved;
|
|
5000
4970
|
let repoRoot;
|
|
5001
4971
|
try {
|
|
5002
|
-
|
|
5003
|
-
|
|
4972
|
+
resolved = resolveDevAppPaths(process.cwd());
|
|
4973
|
+
repoRoot = resolved.projectRoot;
|
|
5004
4974
|
} catch (e) {
|
|
5005
4975
|
console.error(`\u274C ${e.message}`);
|
|
5006
4976
|
process.exit(1);
|
|
@@ -5008,10 +4978,10 @@ async function syncDevClientIos() {
|
|
|
5008
4978
|
const iosDir = resolved.iosDir;
|
|
5009
4979
|
const workspacePath = path16.join(iosDir, `${APP_NAME}.xcworkspace`);
|
|
5010
4980
|
const projectDir = path16.join(iosDir, APP_NAME);
|
|
5011
|
-
const hasCommittedSource =
|
|
4981
|
+
const hasCommittedSource = fs15.existsSync(path16.join(projectDir, "AppDelegate.swift"));
|
|
5012
4982
|
if (!hasCommittedSource) {
|
|
5013
4983
|
await createDevAppProject(iosDir, repoRoot);
|
|
5014
|
-
} else if (!
|
|
4984
|
+
} else if (!fs15.existsSync(workspacePath)) {
|
|
5015
4985
|
await setupCocoaPods(iosDir);
|
|
5016
4986
|
console.log(`\u2139\uFE0F iOS dev-app project exists; ran pod install`);
|
|
5017
4987
|
} else {
|
|
@@ -5029,8 +4999,8 @@ async function syncDevClientIos() {
|
|
|
5029
4999
|
execSync7("npm run build", { stdio: "inherit", cwd: devClientDir });
|
|
5030
5000
|
const bundleSrc = resolved.lynxBundlePath;
|
|
5031
5001
|
const bundleDst = path16.join(iosDir, APP_NAME, "dev-client.lynx.bundle");
|
|
5032
|
-
if (
|
|
5033
|
-
|
|
5002
|
+
if (fs15.existsSync(bundleSrc)) {
|
|
5003
|
+
fs15.copyFileSync(bundleSrc, bundleDst);
|
|
5034
5004
|
console.log(`\u2728 Copied dev-client.lynx.bundle to iOS project`);
|
|
5035
5005
|
} else {
|
|
5036
5006
|
console.warn(`\u26A0\uFE0F Bundle not found at ${bundleSrc}`);
|
|
@@ -5072,7 +5042,7 @@ async function buildIpa(opts = {}) {
|
|
|
5072
5042
|
const scheme = appName;
|
|
5073
5043
|
const workspacePath = path17.join(iosDir, `${appName}.xcworkspace`);
|
|
5074
5044
|
const projectPath = path17.join(iosDir, `${appName}.xcodeproj`);
|
|
5075
|
-
const xcproject =
|
|
5045
|
+
const xcproject = fs16.existsSync(workspacePath) ? workspacePath : projectPath;
|
|
5076
5046
|
const flag = xcproject.endsWith(".xcworkspace") ? "-workspace" : "-project";
|
|
5077
5047
|
const derivedDataPath = path17.join(iosDir, "build");
|
|
5078
5048
|
const sdk = opts.install ? "iphonesimulator" : "iphoneos";
|
|
@@ -5091,7 +5061,7 @@ async function buildIpa(opts = {}) {
|
|
|
5091
5061
|
`${configuration}-iphonesimulator`,
|
|
5092
5062
|
`${appName}.app`
|
|
5093
5063
|
);
|
|
5094
|
-
if (!
|
|
5064
|
+
if (!fs16.existsSync(appGlob)) {
|
|
5095
5065
|
console.error(`\u274C Built app not found at: ${appGlob}`);
|
|
5096
5066
|
process.exit(1);
|
|
5097
5067
|
}
|
|
@@ -5112,14 +5082,13 @@ async function buildIpa(opts = {}) {
|
|
|
5112
5082
|
}
|
|
5113
5083
|
}
|
|
5114
5084
|
async function buildIosDevApp(install, release) {
|
|
5115
|
-
const
|
|
5116
|
-
const resolved = resolveDevAppPaths(repoRoot);
|
|
5085
|
+
const resolved = resolveDevAppPaths(process.cwd());
|
|
5117
5086
|
const iosDir = resolved.iosDir;
|
|
5118
5087
|
const configuration = release ? "Release" : "Debug";
|
|
5119
5088
|
await syncDevClient_default2();
|
|
5120
5089
|
const workspacePath = path17.join(iosDir, `${DEV_APP_NAME}.xcworkspace`);
|
|
5121
5090
|
const projectPath = path17.join(iosDir, `${DEV_APP_NAME}.xcodeproj`);
|
|
5122
|
-
const xcproject =
|
|
5091
|
+
const xcproject = fs16.existsSync(workspacePath) ? workspacePath : projectPath;
|
|
5123
5092
|
const flag = xcproject.endsWith(".xcworkspace") ? "workspace" : "project";
|
|
5124
5093
|
console.log(`
|
|
5125
5094
|
\u{1F528} Building TamerDevApp for simulator (${configuration})...`);
|
|
@@ -5144,7 +5113,7 @@ async function buildIosDevApp(install, release) {
|
|
|
5144
5113
|
var build_default2 = buildIpa;
|
|
5145
5114
|
|
|
5146
5115
|
// src/common/init.ts
|
|
5147
|
-
import
|
|
5116
|
+
import fs17 from "fs";
|
|
5148
5117
|
import path18 from "path";
|
|
5149
5118
|
import readline from "readline";
|
|
5150
5119
|
var rl = readline.createInterface({
|
|
@@ -5197,7 +5166,7 @@ async function init() {
|
|
|
5197
5166
|
};
|
|
5198
5167
|
if (lynxProject) config.lynxProject = lynxProject;
|
|
5199
5168
|
const configPath = path18.join(process.cwd(), "tamer.config.json");
|
|
5200
|
-
|
|
5169
|
+
fs17.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
5201
5170
|
console.log(`
|
|
5202
5171
|
\u2705 Generated tamer.config.json at ${configPath}`);
|
|
5203
5172
|
rl.close();
|
|
@@ -5205,7 +5174,7 @@ async function init() {
|
|
|
5205
5174
|
var init_default = init;
|
|
5206
5175
|
|
|
5207
5176
|
// src/common/create.ts
|
|
5208
|
-
import
|
|
5177
|
+
import fs18 from "fs";
|
|
5209
5178
|
import path19 from "path";
|
|
5210
5179
|
import readline2 from "readline";
|
|
5211
5180
|
var rl2 = readline2.createInterface({ input: process.stdin, output: process.stdout, terminal: false });
|
|
@@ -5237,12 +5206,12 @@ async function create3() {
|
|
|
5237
5206
|
const fullModuleClassName = `${packageName}.${simpleModuleName}`;
|
|
5238
5207
|
const cwd = process.cwd();
|
|
5239
5208
|
const root = path19.join(cwd, extName);
|
|
5240
|
-
if (
|
|
5209
|
+
if (fs18.existsSync(root)) {
|
|
5241
5210
|
console.error(`\u274C Directory ${extName} already exists.`);
|
|
5242
5211
|
rl2.close();
|
|
5243
5212
|
process.exit(1);
|
|
5244
5213
|
}
|
|
5245
|
-
|
|
5214
|
+
fs18.mkdirSync(root, { recursive: true });
|
|
5246
5215
|
const lynxExt = {
|
|
5247
5216
|
platforms: {
|
|
5248
5217
|
android: {
|
|
@@ -5257,7 +5226,7 @@ async function create3() {
|
|
|
5257
5226
|
web: {}
|
|
5258
5227
|
}
|
|
5259
5228
|
};
|
|
5260
|
-
|
|
5229
|
+
fs18.writeFileSync(path19.join(root, "lynx.ext.json"), JSON.stringify(lynxExt, null, 2));
|
|
5261
5230
|
const pkg = {
|
|
5262
5231
|
name: extName,
|
|
5263
5232
|
version: "0.0.1",
|
|
@@ -5270,17 +5239,17 @@ async function create3() {
|
|
|
5270
5239
|
engines: { node: ">=18" }
|
|
5271
5240
|
};
|
|
5272
5241
|
if (includeModule) pkg.types = "src/index.d.ts";
|
|
5273
|
-
|
|
5242
|
+
fs18.writeFileSync(path19.join(root, "package.json"), JSON.stringify(pkg, null, 2));
|
|
5274
5243
|
const pkgPath = packageName.replace(/\./g, "/");
|
|
5275
5244
|
if (includeModule) {
|
|
5276
|
-
|
|
5277
|
-
|
|
5245
|
+
fs18.mkdirSync(path19.join(root, "src"), { recursive: true });
|
|
5246
|
+
fs18.writeFileSync(path19.join(root, "src", "index.d.ts"), `/** @lynxmodule */
|
|
5278
5247
|
export declare class ${simpleModuleName} {
|
|
5279
5248
|
// Add your module methods here
|
|
5280
5249
|
}
|
|
5281
5250
|
`);
|
|
5282
|
-
|
|
5283
|
-
|
|
5251
|
+
fs18.mkdirSync(path19.join(root, "android", "src", "main", "kotlin", pkgPath), { recursive: true });
|
|
5252
|
+
fs18.writeFileSync(path19.join(root, "android", "build.gradle.kts"), `plugins {
|
|
5284
5253
|
id("com.android.library")
|
|
5285
5254
|
id("org.jetbrains.kotlin.android")
|
|
5286
5255
|
}
|
|
@@ -5301,7 +5270,7 @@ dependencies {
|
|
|
5301
5270
|
implementation(libs.lynx.jssdk)
|
|
5302
5271
|
}
|
|
5303
5272
|
`);
|
|
5304
|
-
|
|
5273
|
+
fs18.writeFileSync(path19.join(root, "android", "src", "main", "AndroidManifest.xml"), `<?xml version="1.0" encoding="utf-8"?>
|
|
5305
5274
|
<manifest />
|
|
5306
5275
|
`);
|
|
5307
5276
|
const ktContent = `package ${packageName}
|
|
@@ -5318,8 +5287,8 @@ class ${simpleModuleName}(context: Context) : LynxModule(context) {
|
|
|
5318
5287
|
}
|
|
5319
5288
|
}
|
|
5320
5289
|
`;
|
|
5321
|
-
|
|
5322
|
-
|
|
5290
|
+
fs18.writeFileSync(path19.join(root, "android", "src", "main", "kotlin", pkgPath, `${simpleModuleName}.kt`), ktContent);
|
|
5291
|
+
fs18.mkdirSync(path19.join(root, "ios", extName, extName, "Classes"), { recursive: true });
|
|
5323
5292
|
const podspec = `Pod::Spec.new do |s|
|
|
5324
5293
|
s.name = '${extName}'
|
|
5325
5294
|
s.version = '0.0.1'
|
|
@@ -5333,7 +5302,7 @@ class ${simpleModuleName}(context: Context) : LynxModule(context) {
|
|
|
5333
5302
|
s.dependency 'Lynx'
|
|
5334
5303
|
end
|
|
5335
5304
|
`;
|
|
5336
|
-
|
|
5305
|
+
fs18.writeFileSync(path19.join(root, "ios", extName, `${extName}.podspec`), podspec);
|
|
5337
5306
|
const swiftContent = `import Foundation
|
|
5338
5307
|
|
|
5339
5308
|
@objc public class ${simpleModuleName}: NSObject {
|
|
@@ -5342,16 +5311,16 @@ end
|
|
|
5342
5311
|
}
|
|
5343
5312
|
}
|
|
5344
5313
|
`;
|
|
5345
|
-
|
|
5314
|
+
fs18.writeFileSync(path19.join(root, "ios", extName, extName, "Classes", `${simpleModuleName}.swift`), swiftContent);
|
|
5346
5315
|
}
|
|
5347
|
-
|
|
5316
|
+
fs18.writeFileSync(path19.join(root, "index.js"), `'use strict';
|
|
5348
5317
|
module.exports = {};
|
|
5349
5318
|
`);
|
|
5350
|
-
|
|
5319
|
+
fs18.writeFileSync(path19.join(root, "tsconfig.json"), JSON.stringify({
|
|
5351
5320
|
compilerOptions: { target: "ES2020", module: "ESNext", moduleResolution: "bundler", strict: true },
|
|
5352
5321
|
include: ["src"]
|
|
5353
5322
|
}, null, 2));
|
|
5354
|
-
|
|
5323
|
+
fs18.writeFileSync(path19.join(root, "README.md"), `# ${extName}
|
|
5355
5324
|
|
|
5356
5325
|
Lynx extension for ${extName}.
|
|
5357
5326
|
|
|
@@ -5376,7 +5345,7 @@ This package uses \`lynx.ext.json\` (RFC-compliant) for autolinking.
|
|
|
5376
5345
|
var create_default3 = create3;
|
|
5377
5346
|
|
|
5378
5347
|
// src/common/codegen.ts
|
|
5379
|
-
import
|
|
5348
|
+
import fs19 from "fs";
|
|
5380
5349
|
import path20 from "path";
|
|
5381
5350
|
function codegen() {
|
|
5382
5351
|
const cwd = process.cwd();
|
|
@@ -5387,7 +5356,7 @@ function codegen() {
|
|
|
5387
5356
|
}
|
|
5388
5357
|
const srcDir = path20.join(cwd, "src");
|
|
5389
5358
|
const generatedDir = path20.join(cwd, "generated");
|
|
5390
|
-
|
|
5359
|
+
fs19.mkdirSync(generatedDir, { recursive: true });
|
|
5391
5360
|
const dtsFiles = findDtsFiles(srcDir);
|
|
5392
5361
|
const modules = extractLynxModules(dtsFiles);
|
|
5393
5362
|
if (modules.length === 0) {
|
|
@@ -5398,25 +5367,25 @@ function codegen() {
|
|
|
5398
5367
|
const tsContent = `export type { ${mod} } from '../src/index.js';
|
|
5399
5368
|
`;
|
|
5400
5369
|
const outPath = path20.join(generatedDir, `${mod}.ts`);
|
|
5401
|
-
|
|
5370
|
+
fs19.writeFileSync(outPath, tsContent);
|
|
5402
5371
|
console.log(`\u2705 Generated ${outPath}`);
|
|
5403
5372
|
}
|
|
5404
5373
|
if (config.android) {
|
|
5405
5374
|
const androidGenerated = path20.join(cwd, "android", "src", "main", "kotlin", config.android.moduleClassName.replace(/\./g, "/").replace(/[^/]+$/, ""), "generated");
|
|
5406
|
-
|
|
5375
|
+
fs19.mkdirSync(androidGenerated, { recursive: true });
|
|
5407
5376
|
console.log(`\u2139\uFE0F Android generated dir: ${androidGenerated} (spec generation coming soon)`);
|
|
5408
5377
|
}
|
|
5409
5378
|
if (config.ios) {
|
|
5410
5379
|
const iosGenerated = path20.join(cwd, "ios", "generated");
|
|
5411
|
-
|
|
5380
|
+
fs19.mkdirSync(iosGenerated, { recursive: true });
|
|
5412
5381
|
console.log(`\u2139\uFE0F iOS generated dir: ${iosGenerated} (spec generation coming soon)`);
|
|
5413
5382
|
}
|
|
5414
5383
|
console.log("\u2728 Codegen complete.");
|
|
5415
5384
|
}
|
|
5416
5385
|
function findDtsFiles(dir) {
|
|
5417
5386
|
const result = [];
|
|
5418
|
-
if (!
|
|
5419
|
-
const entries =
|
|
5387
|
+
if (!fs19.existsSync(dir)) return result;
|
|
5388
|
+
const entries = fs19.readdirSync(dir, { withFileTypes: true });
|
|
5420
5389
|
for (const e of entries) {
|
|
5421
5390
|
const full = path20.join(dir, e.name);
|
|
5422
5391
|
if (e.isDirectory()) result.push(...findDtsFiles(full));
|
|
@@ -5428,7 +5397,7 @@ function extractLynxModules(files) {
|
|
|
5428
5397
|
const modules = [];
|
|
5429
5398
|
const seen = /* @__PURE__ */ new Set();
|
|
5430
5399
|
for (const file of files) {
|
|
5431
|
-
const content =
|
|
5400
|
+
const content = fs19.readFileSync(file, "utf8");
|
|
5432
5401
|
const regex = /\/\*\*\s*@lynxmodule\s*\*\/\s*export\s+declare\s+class\s+(\w+)/g;
|
|
5433
5402
|
let m;
|
|
5434
5403
|
while ((m = regex.exec(content)) !== null) {
|
|
@@ -5444,7 +5413,7 @@ var codegen_default = codegen;
|
|
|
5444
5413
|
|
|
5445
5414
|
// src/common/devServer.ts
|
|
5446
5415
|
import { spawn } from "child_process";
|
|
5447
|
-
import
|
|
5416
|
+
import fs20 from "fs";
|
|
5448
5417
|
import http from "http";
|
|
5449
5418
|
import os3 from "os";
|
|
5450
5419
|
import path21 from "path";
|
|
@@ -5470,8 +5439,8 @@ async function startDevServer(opts) {
|
|
|
5470
5439
|
let buildProcess = null;
|
|
5471
5440
|
function detectPackageManager2(cwd) {
|
|
5472
5441
|
const dir = path21.resolve(cwd);
|
|
5473
|
-
if (
|
|
5474
|
-
if (
|
|
5442
|
+
if (fs20.existsSync(path21.join(dir, "pnpm-lock.yaml"))) return { cmd: "pnpm", args: ["run", "build"] };
|
|
5443
|
+
if (fs20.existsSync(path21.join(dir, "bun.lockb")) || fs20.existsSync(path21.join(dir, "bun.lock"))) return { cmd: "bun", args: ["run", "build"] };
|
|
5475
5444
|
return { cmd: "npm", args: ["run", "build"] };
|
|
5476
5445
|
}
|
|
5477
5446
|
function runBuild() {
|
|
@@ -5497,14 +5466,14 @@ async function startDevServer(opts) {
|
|
|
5497
5466
|
const basePath = `/${projectName}`;
|
|
5498
5467
|
const iconPaths = resolveIconPaths(projectRoot, config);
|
|
5499
5468
|
let iconFilePath = null;
|
|
5500
|
-
if (iconPaths?.source &&
|
|
5469
|
+
if (iconPaths?.source && fs20.statSync(iconPaths.source).isFile()) {
|
|
5501
5470
|
iconFilePath = iconPaths.source;
|
|
5502
5471
|
} else if (iconPaths?.android) {
|
|
5503
5472
|
const androidIcon = path21.join(iconPaths.android, "mipmap-xxxhdpi", "ic_launcher.png");
|
|
5504
|
-
if (
|
|
5473
|
+
if (fs20.existsSync(androidIcon)) iconFilePath = androidIcon;
|
|
5505
5474
|
} else if (iconPaths?.ios) {
|
|
5506
5475
|
const iosIcon = path21.join(iconPaths.ios, "Icon-1024.png");
|
|
5507
|
-
if (
|
|
5476
|
+
if (fs20.existsSync(iosIcon)) iconFilePath = iosIcon;
|
|
5508
5477
|
}
|
|
5509
5478
|
const iconExt = iconFilePath ? path21.extname(iconFilePath) || ".png" : "";
|
|
5510
5479
|
const iconMime = {
|
|
@@ -5545,7 +5514,7 @@ async function startDevServer(opts) {
|
|
|
5545
5514
|
return;
|
|
5546
5515
|
}
|
|
5547
5516
|
if (iconFilePath && (reqPath === `${basePath}/icon` || reqPath === `${basePath}/icon${iconExt}`)) {
|
|
5548
|
-
|
|
5517
|
+
fs20.readFile(iconFilePath, (err, data) => {
|
|
5549
5518
|
if (err) {
|
|
5550
5519
|
res.writeHead(404);
|
|
5551
5520
|
res.end();
|
|
@@ -5570,7 +5539,7 @@ async function startDevServer(opts) {
|
|
|
5570
5539
|
res.end();
|
|
5571
5540
|
return;
|
|
5572
5541
|
}
|
|
5573
|
-
|
|
5542
|
+
fs20.readFile(filePath, (err, data) => {
|
|
5574
5543
|
if (err) {
|
|
5575
5544
|
res.writeHead(404);
|
|
5576
5545
|
res.end("Not found");
|
|
@@ -5627,7 +5596,7 @@ async function startDevServer(opts) {
|
|
|
5627
5596
|
path21.join(lynxProjectDir, "src"),
|
|
5628
5597
|
path21.join(lynxProjectDir, "lynx.config.ts"),
|
|
5629
5598
|
path21.join(lynxProjectDir, "lynx.config.js")
|
|
5630
|
-
].filter((p) =>
|
|
5599
|
+
].filter((p) => fs20.existsSync(p));
|
|
5631
5600
|
if (watchPaths.length > 0) {
|
|
5632
5601
|
const watcher = chokidar.watch(watchPaths, { ignoreInitial: true });
|
|
5633
5602
|
watcher.on("change", async () => {
|
|
@@ -5706,10 +5675,10 @@ async function start(opts) {
|
|
|
5706
5675
|
var start_default = start;
|
|
5707
5676
|
|
|
5708
5677
|
// src/common/injectHost.ts
|
|
5709
|
-
import
|
|
5678
|
+
import fs21 from "fs";
|
|
5710
5679
|
import path22 from "path";
|
|
5711
5680
|
function readAndSubstitute(templatePath, vars) {
|
|
5712
|
-
const raw =
|
|
5681
|
+
const raw = fs21.readFileSync(templatePath, "utf-8");
|
|
5713
5682
|
return Object.entries(vars).reduce(
|
|
5714
5683
|
(s, [k, v]) => s.replace(new RegExp(`\\{\\{${k}\\}\\}`, "g"), v),
|
|
5715
5684
|
raw
|
|
@@ -5734,7 +5703,7 @@ async function injectHostAndroid(opts) {
|
|
|
5734
5703
|
const packagePath = packageName.replace(/\./g, "/");
|
|
5735
5704
|
const javaDir = path22.join(rootDir, "app", "src", "main", "java", packagePath);
|
|
5736
5705
|
const kotlinDir = path22.join(rootDir, "app", "src", "main", "kotlin", packagePath);
|
|
5737
|
-
if (!
|
|
5706
|
+
if (!fs21.existsSync(javaDir) || !fs21.existsSync(kotlinDir)) {
|
|
5738
5707
|
console.error("\u274C Android project not found. Run `t4l android create` first or ensure android/ exists.");
|
|
5739
5708
|
process.exit(1);
|
|
5740
5709
|
}
|
|
@@ -5747,14 +5716,14 @@ async function injectHostAndroid(opts) {
|
|
|
5747
5716
|
];
|
|
5748
5717
|
for (const { src, dst } of files) {
|
|
5749
5718
|
const srcPath = path22.join(templateDir, src);
|
|
5750
|
-
if (!
|
|
5751
|
-
if (
|
|
5719
|
+
if (!fs21.existsSync(srcPath)) continue;
|
|
5720
|
+
if (fs21.existsSync(dst) && !opts?.force) {
|
|
5752
5721
|
console.log(`\u23ED\uFE0F Skipping ${path22.basename(dst)} (use --force to overwrite)`);
|
|
5753
5722
|
continue;
|
|
5754
5723
|
}
|
|
5755
5724
|
const content = readAndSubstitute(srcPath, vars);
|
|
5756
|
-
|
|
5757
|
-
|
|
5725
|
+
fs21.mkdirSync(path22.dirname(dst), { recursive: true });
|
|
5726
|
+
fs21.writeFileSync(dst, content);
|
|
5758
5727
|
console.log(`\u2705 Injected ${path22.basename(dst)}`);
|
|
5759
5728
|
}
|
|
5760
5729
|
}
|
|
@@ -5775,7 +5744,7 @@ async function injectHostIos(opts) {
|
|
|
5775
5744
|
const iosDir = config.paths?.iosDir ?? "ios";
|
|
5776
5745
|
const rootDir = path22.join(projectRoot, iosDir);
|
|
5777
5746
|
const projectDir = path22.join(rootDir, appName);
|
|
5778
|
-
if (!
|
|
5747
|
+
if (!fs21.existsSync(projectDir)) {
|
|
5779
5748
|
console.error("\u274C iOS project not found. Run `t4l ios create` first or ensure ios/ exists.");
|
|
5780
5749
|
process.exit(1);
|
|
5781
5750
|
}
|
|
@@ -5791,19 +5760,19 @@ async function injectHostIos(opts) {
|
|
|
5791
5760
|
for (const f of files) {
|
|
5792
5761
|
const srcPath = path22.join(templateDir, f);
|
|
5793
5762
|
const dstPath = path22.join(projectDir, f);
|
|
5794
|
-
if (!
|
|
5795
|
-
if (
|
|
5763
|
+
if (!fs21.existsSync(srcPath)) continue;
|
|
5764
|
+
if (fs21.existsSync(dstPath) && !opts?.force) {
|
|
5796
5765
|
console.log(`\u23ED\uFE0F Skipping ${f} (use --force to overwrite)`);
|
|
5797
5766
|
continue;
|
|
5798
5767
|
}
|
|
5799
5768
|
const content = readAndSubstitute(srcPath, vars);
|
|
5800
|
-
|
|
5769
|
+
fs21.writeFileSync(dstPath, content);
|
|
5801
5770
|
console.log(`\u2705 Injected ${f}`);
|
|
5802
5771
|
}
|
|
5803
5772
|
}
|
|
5804
5773
|
|
|
5805
5774
|
// src/common/buildEmbeddable.ts
|
|
5806
|
-
import
|
|
5775
|
+
import fs22 from "fs";
|
|
5807
5776
|
import path23 from "path";
|
|
5808
5777
|
import { execSync as execSync9 } from "child_process";
|
|
5809
5778
|
var EMBEDDABLE_DIR = "embeddable";
|
|
@@ -5884,9 +5853,9 @@ function generateAndroidLibrary(outDir, androidDir, projectRoot, lynxBundlePath,
|
|
|
5884
5853
|
const assetsDir = path23.join(libSrcMain, "assets");
|
|
5885
5854
|
const kotlinDir = path23.join(libSrcMain, "kotlin", LIB_PACKAGE.replace(/\./g, "/"));
|
|
5886
5855
|
const generatedDir = path23.join(kotlinDir, "generated");
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5856
|
+
fs22.mkdirSync(path23.join(androidDir, "gradle"), { recursive: true });
|
|
5857
|
+
fs22.mkdirSync(generatedDir, { recursive: true });
|
|
5858
|
+
fs22.mkdirSync(assetsDir, { recursive: true });
|
|
5890
5859
|
const androidModules = modules.filter((m) => m.config.android);
|
|
5891
5860
|
const abiList = abiFilters.map((a) => `"${a}"`).join(", ");
|
|
5892
5861
|
const settingsContent = `pluginManagement {
|
|
@@ -5953,9 +5922,9 @@ dependencies {
|
|
|
5953
5922
|
${libDeps}
|
|
5954
5923
|
}
|
|
5955
5924
|
`;
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5925
|
+
fs22.writeFileSync(path23.join(androidDir, "gradle", "libs.versions.toml"), LIBS_VERSIONS_TOML);
|
|
5926
|
+
fs22.writeFileSync(path23.join(androidDir, "settings.gradle.kts"), settingsContent);
|
|
5927
|
+
fs22.writeFileSync(
|
|
5959
5928
|
path23.join(androidDir, "build.gradle.kts"),
|
|
5960
5929
|
`plugins {
|
|
5961
5930
|
alias(libs.plugins.android.library) apply false
|
|
@@ -5964,25 +5933,25 @@ ${libDeps}
|
|
|
5964
5933
|
}
|
|
5965
5934
|
`
|
|
5966
5935
|
);
|
|
5967
|
-
|
|
5936
|
+
fs22.writeFileSync(
|
|
5968
5937
|
path23.join(androidDir, "gradle.properties"),
|
|
5969
5938
|
`org.gradle.jvmargs=-Xmx2048m
|
|
5970
5939
|
android.useAndroidX=true
|
|
5971
5940
|
kotlin.code.style=official
|
|
5972
5941
|
`
|
|
5973
5942
|
);
|
|
5974
|
-
|
|
5975
|
-
|
|
5943
|
+
fs22.writeFileSync(path23.join(libDir, "build.gradle.kts"), libBuildContent);
|
|
5944
|
+
fs22.writeFileSync(
|
|
5976
5945
|
path23.join(libSrcMain, "AndroidManifest.xml"),
|
|
5977
5946
|
'<?xml version="1.0" encoding="utf-8"?>\n<manifest />'
|
|
5978
5947
|
);
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5948
|
+
fs22.copyFileSync(lynxBundlePath, path23.join(assetsDir, lynxBundleFile));
|
|
5949
|
+
fs22.writeFileSync(path23.join(kotlinDir, "LynxEmbeddable.kt"), LYNX_EMBEDDABLE_KT);
|
|
5950
|
+
fs22.writeFileSync(
|
|
5982
5951
|
path23.join(generatedDir, "GeneratedLynxExtensions.kt"),
|
|
5983
5952
|
generateLynxExtensionsKotlin(modules, LIB_PACKAGE)
|
|
5984
5953
|
);
|
|
5985
|
-
|
|
5954
|
+
fs22.writeFileSync(
|
|
5986
5955
|
path23.join(generatedDir, "GeneratedActivityLifecycle.kt"),
|
|
5987
5956
|
generateActivityLifecycleKotlin(modules, LIB_PACKAGE)
|
|
5988
5957
|
);
|
|
@@ -5992,20 +5961,20 @@ async function buildEmbeddable(opts = {}) {
|
|
|
5992
5961
|
const { lynxProjectDir, lynxBundlePath, lynxBundleFile, projectRoot, config } = resolved;
|
|
5993
5962
|
console.log("\u{1F4E6} Building Lynx project (release)...");
|
|
5994
5963
|
execSync9("npm run build", { stdio: "inherit", cwd: lynxProjectDir });
|
|
5995
|
-
if (!
|
|
5964
|
+
if (!fs22.existsSync(lynxBundlePath)) {
|
|
5996
5965
|
console.error(`\u274C Bundle not found at ${lynxBundlePath}`);
|
|
5997
5966
|
process.exit(1);
|
|
5998
5967
|
}
|
|
5999
5968
|
const outDir = path23.join(projectRoot, EMBEDDABLE_DIR);
|
|
6000
|
-
|
|
5969
|
+
fs22.mkdirSync(outDir, { recursive: true });
|
|
6001
5970
|
const distDir = path23.dirname(lynxBundlePath);
|
|
6002
5971
|
copyDistAssets(distDir, outDir, lynxBundleFile);
|
|
6003
5972
|
const modules = discoverModules(projectRoot);
|
|
6004
5973
|
const androidModules = modules.filter((m) => m.config.android);
|
|
6005
5974
|
const abiFilters = resolveAbiFilters(config);
|
|
6006
5975
|
const androidDir = path23.join(outDir, "android");
|
|
6007
|
-
if (
|
|
6008
|
-
|
|
5976
|
+
if (fs22.existsSync(androidDir)) fs22.rmSync(androidDir, { recursive: true });
|
|
5977
|
+
fs22.mkdirSync(androidDir, { recursive: true });
|
|
6009
5978
|
generateAndroidLibrary(
|
|
6010
5979
|
outDir,
|
|
6011
5980
|
androidDir,
|
|
@@ -6023,15 +5992,15 @@ async function buildEmbeddable(opts = {}) {
|
|
|
6023
5992
|
].filter(Boolean);
|
|
6024
5993
|
let hasWrapper = false;
|
|
6025
5994
|
for (const d of existingGradleDirs) {
|
|
6026
|
-
if (
|
|
5995
|
+
if (fs22.existsSync(path23.join(d, "gradlew"))) {
|
|
6027
5996
|
for (const name of ["gradlew", "gradlew.bat", "gradle"]) {
|
|
6028
5997
|
const src = path23.join(d, name);
|
|
6029
|
-
if (
|
|
5998
|
+
if (fs22.existsSync(src)) {
|
|
6030
5999
|
const dest = path23.join(androidDir, name);
|
|
6031
|
-
if (
|
|
6032
|
-
|
|
6000
|
+
if (fs22.statSync(src).isDirectory()) {
|
|
6001
|
+
fs22.cpSync(src, dest, { recursive: true });
|
|
6033
6002
|
} else {
|
|
6034
|
-
|
|
6003
|
+
fs22.copyFileSync(src, dest);
|
|
6035
6004
|
}
|
|
6036
6005
|
}
|
|
6037
6006
|
}
|
|
@@ -6052,8 +6021,8 @@ async function buildEmbeddable(opts = {}) {
|
|
|
6052
6021
|
}
|
|
6053
6022
|
const aarSrc = path23.join(androidDir, "lib", "build", "outputs", "aar", "lib-release.aar");
|
|
6054
6023
|
const aarDest = path23.join(outDir, "tamer-embeddable.aar");
|
|
6055
|
-
if (
|
|
6056
|
-
|
|
6024
|
+
if (fs22.existsSync(aarSrc)) {
|
|
6025
|
+
fs22.copyFileSync(aarSrc, aarDest);
|
|
6057
6026
|
console.log(` - tamer-embeddable.aar`);
|
|
6058
6027
|
}
|
|
6059
6028
|
const snippetAndroid = `// Add to your app's build.gradle:
|
|
@@ -6064,7 +6033,7 @@ async function buildEmbeddable(opts = {}) {
|
|
|
6064
6033
|
// LynxEmbeddable.init(applicationContext)
|
|
6065
6034
|
// val lynxView = LynxEmbeddable.buildLynxView(containerViewGroup)
|
|
6066
6035
|
`;
|
|
6067
|
-
|
|
6036
|
+
fs22.writeFileSync(path23.join(outDir, "snippet-android.kt"), snippetAndroid);
|
|
6068
6037
|
generateIosPod(outDir, projectRoot, lynxBundlePath, lynxBundleFile, modules);
|
|
6069
6038
|
const readme = `# Embeddable Lynx Bundle
|
|
6070
6039
|
|
|
@@ -6095,7 +6064,7 @@ Add the \`Podfile.snippet\` entries to your Podfile (inside your app target), th
|
|
|
6095
6064
|
|
|
6096
6065
|
- [Embedding LynxView](https://lynxjs.org/guide/embed-lynx-to-native)
|
|
6097
6066
|
`;
|
|
6098
|
-
|
|
6067
|
+
fs22.writeFileSync(path23.join(outDir, "README.md"), readme);
|
|
6099
6068
|
console.log(`
|
|
6100
6069
|
\u2705 Embeddable output at ${outDir}/`);
|
|
6101
6070
|
console.log(" - main.lynx.bundle");
|
|
@@ -6110,14 +6079,14 @@ function generateIosPod(outDir, projectRoot, lynxBundlePath, lynxBundleFile, mod
|
|
|
6110
6079
|
const iosDir = path23.join(outDir, "ios");
|
|
6111
6080
|
const podDir = path23.join(iosDir, "TamerEmbeddable");
|
|
6112
6081
|
const resourcesDir = path23.join(podDir, "Resources");
|
|
6113
|
-
|
|
6114
|
-
|
|
6082
|
+
fs22.mkdirSync(resourcesDir, { recursive: true });
|
|
6083
|
+
fs22.copyFileSync(lynxBundlePath, path23.join(resourcesDir, lynxBundleFile));
|
|
6115
6084
|
const iosModules = modules.filter((m) => m.config.ios);
|
|
6116
6085
|
const podDeps = iosModules.map((p) => {
|
|
6117
6086
|
const podspecPath = p.config.ios?.podspecPath || ".";
|
|
6118
6087
|
const podspecDir = path23.join(p.packagePath, podspecPath);
|
|
6119
|
-
if (!
|
|
6120
|
-
const files =
|
|
6088
|
+
if (!fs22.existsSync(podspecDir)) return null;
|
|
6089
|
+
const files = fs22.readdirSync(podspecDir);
|
|
6121
6090
|
const podspecFile = files.find((f) => f.endsWith(".podspec"));
|
|
6122
6091
|
const podName = podspecFile ? podspecFile.replace(".podspec", "") : p.name.split("/").pop().replace(/-/g, "");
|
|
6123
6092
|
const absPath = path23.resolve(podspecDir);
|
|
@@ -6161,8 +6130,8 @@ end
|
|
|
6161
6130
|
const swiftImports = iosModules.map((p) => {
|
|
6162
6131
|
const podspecPath = p.config.ios?.podspecPath || ".";
|
|
6163
6132
|
const podspecDir = path23.join(p.packagePath, podspecPath);
|
|
6164
|
-
if (!
|
|
6165
|
-
const files =
|
|
6133
|
+
if (!fs22.existsSync(podspecDir)) return null;
|
|
6134
|
+
const files = fs22.readdirSync(podspecDir);
|
|
6166
6135
|
const podspecFile = files.find((f) => f.endsWith(".podspec"));
|
|
6167
6136
|
return podspecFile ? podspecFile.replace(".podspec", "") : null;
|
|
6168
6137
|
}).filter(Boolean);
|
|
@@ -6181,16 +6150,16 @@ ${regBlock}
|
|
|
6181
6150
|
}
|
|
6182
6151
|
}
|
|
6183
6152
|
`;
|
|
6184
|
-
|
|
6185
|
-
|
|
6153
|
+
fs22.writeFileSync(path23.join(iosDir, "TamerEmbeddable.podspec"), podspecContent);
|
|
6154
|
+
fs22.writeFileSync(path23.join(podDir, "LynxEmbeddable.swift"), lynxEmbeddableSwift);
|
|
6186
6155
|
const absIosDir = path23.resolve(iosDir);
|
|
6187
6156
|
const podfileSnippet = `# Paste into your app target in Podfile:
|
|
6188
6157
|
|
|
6189
6158
|
pod 'TamerEmbeddable', :path => '${absIosDir}'
|
|
6190
6159
|
${podDeps.map((d) => `pod '${d.podName}', :path => '${d.absPath}'`).join("\n")}
|
|
6191
6160
|
`;
|
|
6192
|
-
|
|
6193
|
-
|
|
6161
|
+
fs22.writeFileSync(path23.join(iosDir, "Podfile.snippet"), podfileSnippet);
|
|
6162
|
+
fs22.writeFileSync(
|
|
6194
6163
|
path23.join(outDir, "snippet-ios.swift"),
|
|
6195
6164
|
`// Add LynxEmbeddable.initEnvironment() in your AppDelegate/SceneDelegate before presenting LynxView.
|
|
6196
6165
|
// Then create LynxView with your bundle URL (main.lynx.bundle is in the pod resources).
|
|
@@ -6199,7 +6168,7 @@ ${podDeps.map((d) => `pod '${d.podName}', :path => '${d.absPath}'`).join("\n")}
|
|
|
6199
6168
|
}
|
|
6200
6169
|
|
|
6201
6170
|
// src/common/add.ts
|
|
6202
|
-
import
|
|
6171
|
+
import fs23 from "fs";
|
|
6203
6172
|
import path24 from "path";
|
|
6204
6173
|
import { execSync as execSync10 } from "child_process";
|
|
6205
6174
|
var CORE_PACKAGES = [
|
|
@@ -6214,8 +6183,8 @@ var CORE_PACKAGES = [
|
|
|
6214
6183
|
];
|
|
6215
6184
|
function detectPackageManager(cwd) {
|
|
6216
6185
|
const dir = path24.resolve(cwd);
|
|
6217
|
-
if (
|
|
6218
|
-
if (
|
|
6186
|
+
if (fs23.existsSync(path24.join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
6187
|
+
if (fs23.existsSync(path24.join(dir, "bun.lockb"))) return "bun";
|
|
6219
6188
|
return "npm";
|
|
6220
6189
|
}
|
|
6221
6190
|
function runInstall(cwd, packages, pm) {
|
|
@@ -6267,12 +6236,12 @@ android.command("create").option("-t, --target <target>", "Create target: host (
|
|
|
6267
6236
|
android.command("link").description("Link native modules to the Android project").action(() => {
|
|
6268
6237
|
autolink_default();
|
|
6269
6238
|
});
|
|
6270
|
-
android.command("bundle").option("-t, --target <target>", "Bundle target:
|
|
6239
|
+
android.command("bundle").option("-t, --target <target>", "Bundle target: dev-app (default) or host", "dev-app").option("-d, --debug", "Build debug (development) bundle").option("-r, --release", "Build release (production) bundle").description("Build Lynx bundle and copy to Android assets (runs autolink first)").action(async (opts) => {
|
|
6271
6240
|
validateDebugRelease(opts.debug, opts.release);
|
|
6272
6241
|
const release = opts.release === true;
|
|
6273
6242
|
await bundle_default({ target: opts.target, release });
|
|
6274
6243
|
});
|
|
6275
|
-
var androidBuildCmd = android.command("build").option("-i, --install", "Install APK to connected device and launch app after building").option("-t, --target <target>", "Build target:
|
|
6244
|
+
var androidBuildCmd = android.command("build").option("-i, --install", "Install APK to connected device and launch app after building").option("-t, --target <target>", "Build target: dev-app (default) or host", "dev-app").option("-e, --embeddable", "Build for embedding in existing app (host only). Use with --release for production-ready embeddable.").option("-d, --debug", "Build debug (development) APK").option("-r, --release", "Build release (production) APK").description("Build APK (autolink + bundle + gradle)").action(async () => {
|
|
6276
6245
|
const opts = androidBuildCmd.opts();
|
|
6277
6246
|
validateDebugRelease(opts.debug, opts.release);
|
|
6278
6247
|
const release = opts.release === true;
|
|
@@ -6298,12 +6267,12 @@ ios.command("inject").option("-f, --force", "Overwrite existing files").descript
|
|
|
6298
6267
|
ios.command("link").description("Link native modules to the iOS project").action(() => {
|
|
6299
6268
|
autolink_default2();
|
|
6300
6269
|
});
|
|
6301
|
-
ios.command("bundle").option("-t, --target <target>", "Bundle target:
|
|
6270
|
+
ios.command("bundle").option("-t, --target <target>", "Bundle target: dev-app (default) or host", "dev-app").option("-d, --debug", "Build debug (development) bundle").option("-r, --release", "Build release (production) bundle").description("Build Lynx bundle and copy to iOS project (runs autolink first)").action((opts) => {
|
|
6302
6271
|
validateDebugRelease(opts.debug, opts.release);
|
|
6303
6272
|
const release = opts.release === true;
|
|
6304
6273
|
bundle_default2({ target: opts.target, release });
|
|
6305
6274
|
});
|
|
6306
|
-
var iosBuildCmd = ios.command("build").option("-t, --target <target>", "Build target:
|
|
6275
|
+
var iosBuildCmd = ios.command("build").option("-t, --target <target>", "Build target: dev-app (default) or host", "dev-app").option("-e, --embeddable", "Output bundle + code snippets to embeddable/ for adding LynxView to an existing app. Use with --release.").option("-i, --install", "Install and launch on booted simulator after building").option("-d, --debug", "Build debug (development) configuration").option("-r, --release", "Build release (production) configuration").description("Build iOS app (autolink + bundle + xcodebuild)").action(async () => {
|
|
6307
6276
|
const opts = iosBuildCmd.opts();
|
|
6308
6277
|
validateDebugRelease(opts.debug, opts.release);
|
|
6309
6278
|
const release = opts.release === true;
|
|
@@ -6375,8 +6344,8 @@ program.command("codegen").description("Generate code from @lynxmodule declarati
|
|
|
6375
6344
|
program.command("autolink-toggle").alias("autolink").description("Toggle autolink on/off in tamer.config.json (controls postinstall linking)").action(async () => {
|
|
6376
6345
|
const configPath = path25.join(process.cwd(), "tamer.config.json");
|
|
6377
6346
|
let config = {};
|
|
6378
|
-
if (
|
|
6379
|
-
config = JSON.parse(
|
|
6347
|
+
if (fs24.existsSync(configPath)) {
|
|
6348
|
+
config = JSON.parse(fs24.readFileSync(configPath, "utf8"));
|
|
6380
6349
|
}
|
|
6381
6350
|
if (config.autolink) {
|
|
6382
6351
|
delete config.autolink;
|
|
@@ -6385,7 +6354,7 @@ program.command("autolink-toggle").alias("autolink").description("Toggle autolin
|
|
|
6385
6354
|
config.autolink = true;
|
|
6386
6355
|
console.log("Autolink enabled in tamer.config.json");
|
|
6387
6356
|
}
|
|
6388
|
-
|
|
6357
|
+
fs24.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
6389
6358
|
console.log(`Updated ${configPath}`);
|
|
6390
6359
|
});
|
|
6391
6360
|
if (process.argv.length <= 2 || process.argv.length === 3 && process.argv[2] === "init") {
|