@teardown/cli 1.2.39 → 2.0.41
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/bin/teardown.js +11 -1
- package/package.json +77 -57
- package/src/cli/commands/init.ts +254 -0
- package/src/cli/commands/plugins.ts +93 -0
- package/src/cli/commands/prebuild.ts +168 -0
- package/src/cli/commands/run.ts +727 -0
- package/src/cli/commands/start.ts +87 -0
- package/src/cli/commands/validate.ts +62 -0
- package/src/cli/index.ts +59 -0
- package/src/config/index.ts +45 -0
- package/src/config/loader.ts +366 -0
- package/src/config/schema.ts +235 -0
- package/src/config/types.ts +322 -0
- package/src/index.ts +177 -0
- package/src/pipeline/cache.ts +179 -0
- package/src/pipeline/index.ts +10 -0
- package/src/pipeline/stages.ts +692 -0
- package/src/plugins/base.ts +370 -0
- package/src/plugins/capabilities/biometrics.ts +64 -0
- package/src/plugins/capabilities/bluetooth.ts +86 -0
- package/src/plugins/capabilities/calendar.ts +57 -0
- package/src/plugins/capabilities/camera.ts +77 -0
- package/src/plugins/capabilities/contacts.ts +57 -0
- package/src/plugins/capabilities/deep-linking.ts +124 -0
- package/src/plugins/capabilities/firebase.ts +138 -0
- package/src/plugins/capabilities/index.ts +96 -0
- package/src/plugins/capabilities/location.ts +87 -0
- package/src/plugins/capabilities/photo-library.ts +80 -0
- package/src/plugins/capabilities/push-notifications.ts +98 -0
- package/src/plugins/capabilities/sign-in-with-apple.ts +53 -0
- package/src/plugins/context.ts +220 -0
- package/src/plugins/index.ts +26 -0
- package/src/plugins/resolver.ts +321 -0
- package/src/templates/generator.ts +507 -0
- package/src/templates/index.ts +9 -0
- package/src/templates/paths.ts +25 -0
- package/src/transformers/android/gradle.ts +400 -0
- package/src/transformers/android/index.ts +19 -0
- package/src/transformers/android/manifest.ts +506 -0
- package/src/transformers/index.ts +39 -0
- package/src/transformers/ios/entitlements.ts +283 -0
- package/src/transformers/ios/index.ts +10 -0
- package/src/transformers/ios/pbxproj.ts +267 -0
- package/src/transformers/ios/plist.ts +198 -0
- package/src/utils/fs.ts +429 -0
- package/src/utils/index.ts +21 -0
- package/src/utils/logger.ts +203 -0
- package/templates/.gitignore +63 -0
- package/templates/Gemfile +3 -0
- package/templates/android/app/build.gradle.kts +97 -0
- package/templates/android/app/proguard-rules.pro +10 -0
- package/templates/android/app/src/main/AndroidManifest.xml +26 -0
- package/templates/android/app/src/main/java/com/appname/MainActivity.kt +22 -0
- package/templates/android/app/src/main/java/com/appname/MainApplication.kt +44 -0
- package/templates/android/app/src/main/res/values/strings.xml +3 -0
- package/templates/android/app/src/main/res/values/styles.xml +7 -0
- package/templates/android/build.gradle.kts +44 -0
- package/templates/android/gradle.properties +39 -0
- package/templates/android/settings.gradle.kts +12 -0
- package/templates/babel.config.js +15 -0
- package/templates/index.js +7 -0
- package/templates/ios/.xcode.env +11 -0
- package/templates/ios/AppName/AppDelegate.swift +25 -0
- package/templates/ios/AppName/AppName-Bridging-Header.h +4 -0
- package/templates/ios/AppName/AppName.entitlements +6 -0
- package/templates/ios/AppName/Images.xcassets/AppIcon.appiconset/Contents.json +35 -0
- package/templates/ios/AppName/Images.xcassets/Contents.json +6 -0
- package/templates/ios/AppName/Info.plist +49 -0
- package/templates/ios/AppName/LaunchScreen.storyboard +38 -0
- package/templates/ios/AppName.xcodeproj/project.pbxproj +402 -0
- package/templates/ios/AppName.xcodeproj/xcshareddata/xcschemes/AppName.xcscheme +78 -0
- package/templates/ios/Podfile +35 -0
- package/templates/metro.config.js +41 -0
- package/templates/package.json +57 -0
- package/templates/react-native.config.js +8 -0
- package/templates/src/app/index.tsx +34 -0
- package/templates/src/assets/fonts/.gitkeep +1 -0
- package/templates/src/assets/images/.gitkeep +1 -0
- package/templates/src/components/ui/accordion.tsx +114 -0
- package/templates/src/components/ui/avatar.tsx +75 -0
- package/templates/src/components/ui/button.tsx +93 -0
- package/templates/src/components/ui/card.tsx +120 -0
- package/templates/src/components/ui/checkbox.tsx +133 -0
- package/templates/src/components/ui/chip.tsx +95 -0
- package/templates/src/components/ui/dialog.tsx +134 -0
- package/templates/src/components/ui/divider.tsx +67 -0
- package/templates/src/components/ui/error-view.tsx +82 -0
- package/templates/src/components/ui/form-field.tsx +101 -0
- package/templates/src/components/ui/index.ts +100 -0
- package/templates/src/components/ui/popover.tsx +92 -0
- package/templates/src/components/ui/pressable-feedback.tsx +88 -0
- package/templates/src/components/ui/radio-group.tsx +153 -0
- package/templates/src/components/ui/scroll-shadow.tsx +108 -0
- package/templates/src/components/ui/select.tsx +165 -0
- package/templates/src/components/ui/skeleton-group.tsx +97 -0
- package/templates/src/components/ui/skeleton.tsx +87 -0
- package/templates/src/components/ui/spinner.tsx +87 -0
- package/templates/src/components/ui/surface.tsx +95 -0
- package/templates/src/components/ui/switch.tsx +124 -0
- package/templates/src/components/ui/tabs.tsx +154 -0
- package/templates/src/components/ui/text-field.tsx +106 -0
- package/templates/src/components/ui/toast.tsx +129 -0
- package/templates/src/contexts/.gitkeep +2 -0
- package/templates/src/core/clients/api/api.client.ts +113 -0
- package/templates/src/core/clients/api/index.ts +1 -0
- package/templates/src/core/clients/storage/index.ts +1 -0
- package/templates/src/core/clients/storage/storage.client.ts +121 -0
- package/templates/src/core/constants/index.ts +19 -0
- package/templates/src/core/core.ts +40 -0
- package/templates/src/core/index.ts +10 -0
- package/templates/src/global.css +87 -0
- package/templates/src/hooks/index.ts +6 -0
- package/templates/src/hooks/use-debounce.ts +23 -0
- package/templates/src/hooks/use-mounted.ts +21 -0
- package/templates/src/index.ts +28 -0
- package/templates/src/lib/index.ts +5 -0
- package/templates/src/lib/utils.ts +115 -0
- package/templates/src/modules/.gitkeep +6 -0
- package/templates/src/navigation/index.ts +8 -0
- package/templates/src/navigation/navigation-provider.tsx +36 -0
- package/templates/src/navigation/router.tsx +137 -0
- package/templates/src/providers/app.provider.tsx +29 -0
- package/templates/src/providers/index.ts +5 -0
- package/templates/src/routes/(tabs)/_layout.tsx +42 -0
- package/templates/src/routes/(tabs)/explore.tsx +161 -0
- package/templates/src/routes/(tabs)/home.tsx +138 -0
- package/templates/src/routes/(tabs)/profile.tsx +151 -0
- package/templates/src/routes/_layout.tsx +18 -0
- package/templates/src/routes/settings.tsx +194 -0
- package/templates/src/screens/auth/index.ts +6 -0
- package/templates/src/screens/auth/login.tsx +165 -0
- package/templates/src/screens/auth/register.tsx +203 -0
- package/templates/src/screens/home.tsx +204 -0
- package/templates/src/screens/index.ts +17 -0
- package/templates/src/screens/profile.tsx +210 -0
- package/templates/src/screens/settings.tsx +216 -0
- package/templates/src/screens/welcome.tsx +101 -0
- package/templates/src/styles/index.ts +103 -0
- package/templates/src/types/common.ts +71 -0
- package/templates/src/types/index.ts +5 -0
- package/templates/tsconfig.json +14 -0
- package/README.md +0 -15
- package/assets/favicon.ico +0 -0
- package/dist/commands/dev/dev.d.ts +0 -22
- package/dist/commands/dev/dev.js +0 -56
- package/dist/commands/dev/dev.js.map +0 -1
- package/dist/commands/init/init-teardown.d.ts +0 -9
- package/dist/commands/init/init-teardown.js +0 -27
- package/dist/commands/init/init-teardown.js.map +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -21
- package/dist/index.js.map +0 -1
- package/dist/modules/dev/dev-menu/keyboard-handler.d.ts +0 -21
- package/dist/modules/dev/dev-menu/keyboard-handler.js +0 -139
- package/dist/modules/dev/dev-menu/keyboard-handler.js.map +0 -1
- package/dist/modules/dev/dev-menu/open-debugger-keyboard-handler.d.ts +0 -18
- package/dist/modules/dev/dev-menu/open-debugger-keyboard-handler.js +0 -106
- package/dist/modules/dev/dev-menu/open-debugger-keyboard-handler.js.map +0 -1
- package/dist/modules/dev/dev-server/cdp/cdp.adapter.d.ts +0 -6
- package/dist/modules/dev/dev-server/cdp/cdp.adapter.js +0 -13
- package/dist/modules/dev/dev-server/cdp/cdp.adapter.js.map +0 -1
- package/dist/modules/dev/dev-server/cdp/index.d.ts +0 -2
- package/dist/modules/dev/dev-server/cdp/index.js +0 -19
- package/dist/modules/dev/dev-server/cdp/index.js.map +0 -1
- package/dist/modules/dev/dev-server/cdp/types.d.ts +0 -107
- package/dist/modules/dev/dev-server/cdp/types.js +0 -3
- package/dist/modules/dev/dev-server/cdp/types.js.map +0 -1
- package/dist/modules/dev/dev-server/dev-server-checker.d.ts +0 -22
- package/dist/modules/dev/dev-server/dev-server-checker.js +0 -73
- package/dist/modules/dev/dev-server/dev-server-checker.js.map +0 -1
- package/dist/modules/dev/dev-server/dev-server.d.ts +0 -74
- package/dist/modules/dev/dev-server/dev-server.js +0 -272
- package/dist/modules/dev/dev-server/dev-server.js.map +0 -1
- package/dist/modules/dev/dev-server/inspector/device.d.ts +0 -46
- package/dist/modules/dev/dev-server/inspector/device.event-reporter.d.ts +0 -37
- package/dist/modules/dev/dev-server/inspector/device.event-reporter.js +0 -166
- package/dist/modules/dev/dev-server/inspector/device.event-reporter.js.map +0 -1
- package/dist/modules/dev/dev-server/inspector/device.js +0 -578
- package/dist/modules/dev/dev-server/inspector/device.js.map +0 -1
- package/dist/modules/dev/dev-server/inspector/inspector.d.ts +0 -27
- package/dist/modules/dev/dev-server/inspector/inspector.js +0 -225
- package/dist/modules/dev/dev-server/inspector/inspector.js.map +0 -1
- package/dist/modules/dev/dev-server/inspector/types.d.ts +0 -156
- package/dist/modules/dev/dev-server/inspector/types.js +0 -3
- package/dist/modules/dev/dev-server/inspector/types.js.map +0 -1
- package/dist/modules/dev/dev-server/inspector/wss/servers/debugger-connection.server.d.ts +0 -14
- package/dist/modules/dev/dev-server/inspector/wss/servers/debugger-connection.server.js +0 -63
- package/dist/modules/dev/dev-server/inspector/wss/servers/debugger-connection.server.js.map +0 -1
- package/dist/modules/dev/dev-server/inspector/wss/servers/device-connection.server.d.ts +0 -19
- package/dist/modules/dev/dev-server/inspector/wss/servers/device-connection.server.js +0 -66
- package/dist/modules/dev/dev-server/inspector/wss/servers/device-connection.server.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/devtools.plugin.d.ts +0 -1
- package/dist/modules/dev/dev-server/plugins/devtools.plugin.js +0 -51
- package/dist/modules/dev/dev-server/plugins/devtools.plugin.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/favicon.plugin.d.ts +0 -1
- package/dist/modules/dev/dev-server/plugins/favicon.plugin.js +0 -19
- package/dist/modules/dev/dev-server/plugins/favicon.plugin.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/multipart.plugin.d.ts +0 -1
- package/dist/modules/dev/dev-server/plugins/multipart.plugin.js +0 -63
- package/dist/modules/dev/dev-server/plugins/multipart.plugin.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/systrace.plugin.d.ts +0 -1
- package/dist/modules/dev/dev-server/plugins/systrace.plugin.js +0 -29
- package/dist/modules/dev/dev-server/plugins/systrace.plugin.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/types.d.ts +0 -11
- package/dist/modules/dev/dev-server/plugins/types.js +0 -3
- package/dist/modules/dev/dev-server/plugins/types.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/wss/index.d.ts +0 -3
- package/dist/modules/dev/dev-server/plugins/wss/index.js +0 -20
- package/dist/modules/dev/dev-server/plugins/wss/index.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-api.server.d.ts +0 -37
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-api.server.js +0 -67
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-api.server.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-debugger.server.d.ts +0 -63
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-debugger.server.js +0 -129
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-debugger.server.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-dev-client.server.d.ts +0 -32
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-dev-client.server.js +0 -76
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-dev-client.server.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-events.server.d.ts +0 -75
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-events.server.js +0 -199
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-events.server.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-hmr.server.d.ts +0 -44
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-hmr.server.js +0 -121
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-hmr.server.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-message.server.d.ts +0 -135
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-message.server.js +0 -364
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-message.server.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/wss/types.d.ts +0 -6
- package/dist/modules/dev/dev-server/plugins/wss/types.js +0 -3
- package/dist/modules/dev/dev-server/plugins/wss/types.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-router.d.ts +0 -32
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-router.js +0 -58
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-router.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-server-adapter.d.ts +0 -13
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-server-adapter.js +0 -27
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-server-adapter.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-server.d.ts +0 -39
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-server.js +0 -47
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-server.js.map +0 -1
- package/dist/modules/dev/dev-server/plugins/wss/wss.plugin.d.ts +0 -24
- package/dist/modules/dev/dev-server/plugins/wss/wss.plugin.js +0 -56
- package/dist/modules/dev/dev-server/plugins/wss/wss.plugin.js.map +0 -1
- package/dist/modules/dev/dev-server/sybmolicate/sybmolicate.plugin.d.ts +0 -7
- package/dist/modules/dev/dev-server/sybmolicate/sybmolicate.plugin.js +0 -41
- package/dist/modules/dev/dev-server/sybmolicate/sybmolicate.plugin.js.map +0 -1
- package/dist/modules/dev/dev-server/sybmolicate/types.d.ts +0 -64
- package/dist/modules/dev/dev-server/sybmolicate/types.js +0 -3
- package/dist/modules/dev/dev-server/sybmolicate/types.js.map +0 -1
- package/dist/modules/dev/terminal/base.terminal.reporter.d.ts +0 -25
- package/dist/modules/dev/terminal/base.terminal.reporter.js +0 -79
- package/dist/modules/dev/terminal/base.terminal.reporter.js.map +0 -1
- package/dist/modules/dev/terminal/terminal.reporter.d.ts +0 -13
- package/dist/modules/dev/terminal/terminal.reporter.js +0 -83
- package/dist/modules/dev/terminal/terminal.reporter.js.map +0 -1
- package/dist/modules/dev/types.d.ts +0 -20
- package/dist/modules/dev/types.js +0 -3
- package/dist/modules/dev/types.js.map +0 -1
- package/dist/modules/dev/utils/log.d.ts +0 -23
- package/dist/modules/dev/utils/log.js +0 -74
- package/dist/modules/dev/utils/log.js.map +0 -1
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Generator
|
|
3
|
+
*
|
|
4
|
+
* Handles copying and processing template files for iOS and Android projects.
|
|
5
|
+
* Uses EJS for template processing and handles dynamic file/folder renaming.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
10
|
+
import ejs from "ejs";
|
|
11
|
+
import type { VirtualFileSystem } from "../utils/fs";
|
|
12
|
+
import type { Logger } from "../utils/logger";
|
|
13
|
+
import { getTemplatePath, getTemplatesPath } from "./paths";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Template variables for EJS processing
|
|
17
|
+
*/
|
|
18
|
+
export interface TemplateVariables {
|
|
19
|
+
// Common variables
|
|
20
|
+
slug: string;
|
|
21
|
+
|
|
22
|
+
// iOS variables
|
|
23
|
+
appName: string;
|
|
24
|
+
bundleIdentifier: string;
|
|
25
|
+
version: string;
|
|
26
|
+
buildNumber: number;
|
|
27
|
+
|
|
28
|
+
// Android variables
|
|
29
|
+
packageName: string;
|
|
30
|
+
versionCode: number;
|
|
31
|
+
versionName: string;
|
|
32
|
+
|
|
33
|
+
// CLI version (for package.json template)
|
|
34
|
+
cliVersion?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Template generation options
|
|
39
|
+
*/
|
|
40
|
+
export interface TemplateOptions {
|
|
41
|
+
projectRoot: string;
|
|
42
|
+
variables: TemplateVariables;
|
|
43
|
+
logger?: Logger;
|
|
44
|
+
fs?: VirtualFileSystem;
|
|
45
|
+
dryRun?: boolean;
|
|
46
|
+
force?: boolean; // Overwrite existing files
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Result of template generation
|
|
51
|
+
*/
|
|
52
|
+
export interface TemplateResult {
|
|
53
|
+
success: boolean;
|
|
54
|
+
filesCreated: string[];
|
|
55
|
+
filesSkipped: string[];
|
|
56
|
+
errors: string[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Template Generator class
|
|
61
|
+
*/
|
|
62
|
+
export class TemplateGenerator {
|
|
63
|
+
private options: TemplateOptions;
|
|
64
|
+
private logger?: Logger;
|
|
65
|
+
|
|
66
|
+
constructor(options: TemplateOptions) {
|
|
67
|
+
this.options = options;
|
|
68
|
+
this.logger = options.logger;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Generate iOS project from templates
|
|
73
|
+
*/
|
|
74
|
+
async generateiOS(): Promise<TemplateResult> {
|
|
75
|
+
const templatePath = getTemplatePath("ios");
|
|
76
|
+
const outputPath = join(this.options.projectRoot, "ios");
|
|
77
|
+
|
|
78
|
+
this.logger?.info("Generating iOS project from template...");
|
|
79
|
+
|
|
80
|
+
return this.processTemplateDirectory(templatePath, outputPath, "ios");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Generate Android project from templates
|
|
85
|
+
*/
|
|
86
|
+
async generateAndroid(): Promise<TemplateResult> {
|
|
87
|
+
const templatePath = getTemplatePath("android");
|
|
88
|
+
const outputPath = join(this.options.projectRoot, "android");
|
|
89
|
+
|
|
90
|
+
this.logger?.info("Generating Android project from template...");
|
|
91
|
+
|
|
92
|
+
return this.processTemplateDirectory(templatePath, outputPath, "android");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Generate both iOS and Android projects
|
|
97
|
+
*/
|
|
98
|
+
async generateAll(): Promise<{ ios: TemplateResult; android: TemplateResult }> {
|
|
99
|
+
const ios = await this.generateiOS();
|
|
100
|
+
const android = await this.generateAndroid();
|
|
101
|
+
return { ios, android };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Check if iOS project already exists
|
|
106
|
+
*/
|
|
107
|
+
async iosProjectExists(): Promise<boolean> {
|
|
108
|
+
const xcodeProjectPath = join(this.options.projectRoot, "ios", `${this.options.variables.appName}.xcodeproj`);
|
|
109
|
+
try {
|
|
110
|
+
await stat(xcodeProjectPath);
|
|
111
|
+
return true;
|
|
112
|
+
} catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check if Android project already exists
|
|
119
|
+
*/
|
|
120
|
+
async androidProjectExists(): Promise<boolean> {
|
|
121
|
+
const manifestPath = join(this.options.projectRoot, "android", "app", "src", "main", "AndroidManifest.xml");
|
|
122
|
+
try {
|
|
123
|
+
await stat(manifestPath);
|
|
124
|
+
return true;
|
|
125
|
+
} catch {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Check if package.json exists
|
|
132
|
+
*/
|
|
133
|
+
async packageJsonExists(): Promise<boolean> {
|
|
134
|
+
const packagePath = join(this.options.projectRoot, "package.json");
|
|
135
|
+
try {
|
|
136
|
+
await stat(packagePath);
|
|
137
|
+
return true;
|
|
138
|
+
} catch {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Check if src folder exists
|
|
145
|
+
*/
|
|
146
|
+
async srcFolderExists(): Promise<boolean> {
|
|
147
|
+
const srcPath = join(this.options.projectRoot, "src", "index.ts");
|
|
148
|
+
try {
|
|
149
|
+
await stat(srcPath);
|
|
150
|
+
return true;
|
|
151
|
+
} catch {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Generate src folder from template
|
|
158
|
+
*/
|
|
159
|
+
async generateSrcFolder(): Promise<TemplateResult> {
|
|
160
|
+
const templatePath = join(getTemplatesPath(), "src");
|
|
161
|
+
const outputPath = join(this.options.projectRoot, "src");
|
|
162
|
+
|
|
163
|
+
this.logger?.info("Generating src folder from template...");
|
|
164
|
+
|
|
165
|
+
return this.processTemplateDirectory(templatePath, outputPath, "ios"); // Use ios as platform for EJS processing
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Generate root config files (tsconfig.json, babel.config.js, metro.config.js, index.js)
|
|
170
|
+
*/
|
|
171
|
+
async generateRootConfigFiles(): Promise<TemplateResult> {
|
|
172
|
+
const result: TemplateResult = {
|
|
173
|
+
success: true,
|
|
174
|
+
filesCreated: [],
|
|
175
|
+
filesSkipped: [],
|
|
176
|
+
errors: [],
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const configFiles = [
|
|
180
|
+
"tsconfig.json",
|
|
181
|
+
"babel.config.js",
|
|
182
|
+
"metro.config.js",
|
|
183
|
+
"index.js",
|
|
184
|
+
"react-native.config.js",
|
|
185
|
+
"Gemfile",
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
for (const file of configFiles) {
|
|
189
|
+
const templatePath = join(getTemplatesPath(), file);
|
|
190
|
+
const outputPath = join(this.options.projectRoot, file);
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
// Check if template file exists
|
|
194
|
+
try {
|
|
195
|
+
await stat(templatePath);
|
|
196
|
+
} catch {
|
|
197
|
+
// Template doesn't exist, skip
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Check if output file already exists
|
|
202
|
+
if (!this.options.force) {
|
|
203
|
+
try {
|
|
204
|
+
await stat(outputPath);
|
|
205
|
+
result.filesSkipped.push(outputPath);
|
|
206
|
+
this.logger?.debug(`${file} already exists, skipping`);
|
|
207
|
+
continue;
|
|
208
|
+
} catch {
|
|
209
|
+
// File doesn't exist, continue
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const content = await readFile(templatePath, "utf-8");
|
|
214
|
+
let processedContent = content;
|
|
215
|
+
|
|
216
|
+
// Process EJS if the file contains EJS tags
|
|
217
|
+
if (content.includes("<%=") || content.includes("<%")) {
|
|
218
|
+
processedContent = ejs.render(content, this.options.variables, {
|
|
219
|
+
filename: templatePath,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (!this.options.dryRun) {
|
|
224
|
+
await writeFile(outputPath, processedContent, "utf-8");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
result.filesCreated.push(outputPath);
|
|
228
|
+
this.logger?.debug(`Created: ${outputPath}`);
|
|
229
|
+
} catch (error) {
|
|
230
|
+
result.errors.push(`Failed to generate ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (result.errors.length > 0) {
|
|
235
|
+
result.success = false;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Generate .gitignore from template
|
|
243
|
+
*/
|
|
244
|
+
async generateGitignore(): Promise<TemplateResult> {
|
|
245
|
+
const result: TemplateResult = {
|
|
246
|
+
success: true,
|
|
247
|
+
filesCreated: [],
|
|
248
|
+
filesSkipped: [],
|
|
249
|
+
errors: [],
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const templatePath = join(getTemplatesPath(), ".gitignore");
|
|
253
|
+
const outputPath = join(this.options.projectRoot, ".gitignore");
|
|
254
|
+
|
|
255
|
+
try {
|
|
256
|
+
// Check if .gitignore already exists
|
|
257
|
+
if (!this.options.force) {
|
|
258
|
+
try {
|
|
259
|
+
await stat(outputPath);
|
|
260
|
+
result.filesSkipped.push(outputPath);
|
|
261
|
+
this.logger?.debug(".gitignore already exists, skipping");
|
|
262
|
+
return result;
|
|
263
|
+
} catch {
|
|
264
|
+
// File doesn't exist, continue
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const content = await readFile(templatePath, "utf-8");
|
|
269
|
+
|
|
270
|
+
if (!this.options.dryRun) {
|
|
271
|
+
await writeFile(outputPath, content, "utf-8");
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
result.filesCreated.push(outputPath);
|
|
275
|
+
this.logger?.debug(`Created: ${outputPath}`);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
result.success = false;
|
|
278
|
+
result.errors.push(`Failed to generate .gitignore: ${error instanceof Error ? error.message : String(error)}`);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Generate package.json from template
|
|
286
|
+
*/
|
|
287
|
+
async generatePackageJson(): Promise<TemplateResult> {
|
|
288
|
+
const result: TemplateResult = {
|
|
289
|
+
success: true,
|
|
290
|
+
filesCreated: [],
|
|
291
|
+
filesSkipped: [],
|
|
292
|
+
errors: [],
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const templatePath = join(getTemplatesPath(), "package.json");
|
|
296
|
+
const outputPath = join(this.options.projectRoot, "package.json");
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
// Check if package.json already exists
|
|
300
|
+
if (!this.options.force) {
|
|
301
|
+
try {
|
|
302
|
+
await stat(outputPath);
|
|
303
|
+
result.filesSkipped.push(outputPath);
|
|
304
|
+
this.logger?.debug("package.json already exists, skipping");
|
|
305
|
+
return result;
|
|
306
|
+
} catch {
|
|
307
|
+
// File doesn't exist, continue
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const content = await readFile(templatePath, "utf-8");
|
|
312
|
+
const processedContent = ejs.render(content, this.options.variables, {
|
|
313
|
+
filename: templatePath,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
if (!this.options.dryRun) {
|
|
317
|
+
await writeFile(outputPath, processedContent, "utf-8");
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
result.filesCreated.push(outputPath);
|
|
321
|
+
this.logger?.debug(`Created: ${outputPath}`);
|
|
322
|
+
} catch (error) {
|
|
323
|
+
result.success = false;
|
|
324
|
+
result.errors.push(`Failed to generate package.json: ${error instanceof Error ? error.message : String(error)}`);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return result;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Process a template directory recursively
|
|
332
|
+
*/
|
|
333
|
+
private async processTemplateDirectory(
|
|
334
|
+
templateDir: string,
|
|
335
|
+
outputDir: string,
|
|
336
|
+
platform: "ios" | "android"
|
|
337
|
+
): Promise<TemplateResult> {
|
|
338
|
+
const result: TemplateResult = {
|
|
339
|
+
success: true,
|
|
340
|
+
filesCreated: [],
|
|
341
|
+
filesSkipped: [],
|
|
342
|
+
errors: [],
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
try {
|
|
346
|
+
await this.processDirectory(templateDir, outputDir, platform, result);
|
|
347
|
+
} catch (error) {
|
|
348
|
+
result.success = false;
|
|
349
|
+
result.errors.push(error instanceof Error ? error.message : String(error));
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return result;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Recursively process a directory
|
|
357
|
+
*/
|
|
358
|
+
private async processDirectory(
|
|
359
|
+
srcDir: string,
|
|
360
|
+
destDir: string,
|
|
361
|
+
platform: "ios" | "android",
|
|
362
|
+
result: TemplateResult
|
|
363
|
+
): Promise<void> {
|
|
364
|
+
const entries = await readdir(srcDir, { withFileTypes: true });
|
|
365
|
+
|
|
366
|
+
// Create destination directory
|
|
367
|
+
if (!this.options.dryRun) {
|
|
368
|
+
await mkdir(destDir, { recursive: true });
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
for (const entry of entries) {
|
|
372
|
+
const srcPath = join(srcDir, entry.name);
|
|
373
|
+
|
|
374
|
+
// Special handling for Android java source directories
|
|
375
|
+
// When we encounter "com/appname", we need to replace it with the actual package path
|
|
376
|
+
if (platform === "android" && entry.name === "com" && entry.isDirectory()) {
|
|
377
|
+
// Check if this is the com/appname directory in the template
|
|
378
|
+
const appnamePath = join(srcPath, "appname");
|
|
379
|
+
try {
|
|
380
|
+
const appnameStat = await stat(appnamePath);
|
|
381
|
+
if (appnameStat.isDirectory()) {
|
|
382
|
+
// Replace com/appname with the actual package path
|
|
383
|
+
const packagePath = this.options.variables.packageName.replace(/\./g, "/");
|
|
384
|
+
const newDestDir = join(destDir, packagePath);
|
|
385
|
+
|
|
386
|
+
// Process files in com/appname and put them in the correct package directory
|
|
387
|
+
await this.processDirectory(appnamePath, newDestDir, platform, result);
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
} catch {
|
|
391
|
+
// com/appname doesn't exist, process normally
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const destName = this.replaceTemplateNames(entry.name, platform);
|
|
396
|
+
const destPath = join(destDir, destName);
|
|
397
|
+
|
|
398
|
+
if (entry.isDirectory()) {
|
|
399
|
+
await this.processDirectory(srcPath, destPath, platform, result);
|
|
400
|
+
} else {
|
|
401
|
+
await this.processFile(srcPath, destPath, platform, result);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Process a single template file
|
|
408
|
+
*/
|
|
409
|
+
private async processFile(
|
|
410
|
+
srcPath: string,
|
|
411
|
+
destPath: string,
|
|
412
|
+
platform: "ios" | "android",
|
|
413
|
+
result: TemplateResult
|
|
414
|
+
): Promise<void> {
|
|
415
|
+
// Check if destination exists
|
|
416
|
+
if (!this.options.force) {
|
|
417
|
+
try {
|
|
418
|
+
await stat(destPath);
|
|
419
|
+
result.filesSkipped.push(destPath);
|
|
420
|
+
this.logger?.debug(`Skipping existing file: ${destPath}`);
|
|
421
|
+
return;
|
|
422
|
+
} catch {
|
|
423
|
+
// File doesn't exist, continue
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
try {
|
|
428
|
+
const content = await readFile(srcPath, "utf-8");
|
|
429
|
+
let processedContent: string;
|
|
430
|
+
|
|
431
|
+
// Check if file needs EJS processing (contains <%= or <% tags)
|
|
432
|
+
if (this.shouldProcessAsTemplate(content)) {
|
|
433
|
+
processedContent = ejs.render(content, this.options.variables, {
|
|
434
|
+
filename: srcPath,
|
|
435
|
+
});
|
|
436
|
+
} else {
|
|
437
|
+
processedContent = content;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Replace template names in content as well (for things like package names in paths)
|
|
441
|
+
processedContent = this.replaceTemplateNamesInContent(processedContent, platform);
|
|
442
|
+
|
|
443
|
+
if (!this.options.dryRun) {
|
|
444
|
+
// Ensure directory exists
|
|
445
|
+
await mkdir(dirname(destPath), { recursive: true });
|
|
446
|
+
|
|
447
|
+
// Write file
|
|
448
|
+
await writeFile(destPath, processedContent, "utf-8");
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
result.filesCreated.push(destPath);
|
|
452
|
+
this.logger?.debug(`Created: ${destPath}`);
|
|
453
|
+
} catch (error) {
|
|
454
|
+
const errorMessage = `Failed to process ${srcPath}: ${error instanceof Error ? error.message : String(error)}`;
|
|
455
|
+
result.errors.push(errorMessage);
|
|
456
|
+
this.logger?.error(errorMessage);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Check if a file should be processed as an EJS template
|
|
462
|
+
*/
|
|
463
|
+
private shouldProcessAsTemplate(content: string): boolean {
|
|
464
|
+
return content.includes("<%=") || content.includes("<%");
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Replace template placeholder names in file/folder names
|
|
469
|
+
*/
|
|
470
|
+
private replaceTemplateNames(name: string, platform: "ios" | "android"): string {
|
|
471
|
+
const { appName, packageName } = this.options.variables;
|
|
472
|
+
|
|
473
|
+
let result = name;
|
|
474
|
+
|
|
475
|
+
// iOS replacements
|
|
476
|
+
if (platform === "ios") {
|
|
477
|
+
result = result.replace(/AppName/g, appName);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Android replacements
|
|
481
|
+
if (platform === "android") {
|
|
482
|
+
// Replace com/appname path structure with actual package path
|
|
483
|
+
if (name === "appname" || result.includes("appname")) {
|
|
484
|
+
const packagePath = packageName.replace(/\./g, "/");
|
|
485
|
+
result = result.replace(/com\/appname/g, packagePath);
|
|
486
|
+
result = result.replace(/appname/g, packagePath.split("/").pop() || appName.toLowerCase());
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return result;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Replace template names in file content
|
|
495
|
+
*/
|
|
496
|
+
private replaceTemplateNamesInContent(content: string, _platform: "ios" | "android"): string {
|
|
497
|
+
// These are already handled by EJS, but this catches any remaining placeholders
|
|
498
|
+
return content;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Create a template generator instance
|
|
504
|
+
*/
|
|
505
|
+
export function createTemplateGenerator(options: TemplateOptions): TemplateGenerator {
|
|
506
|
+
return new TemplateGenerator(options);
|
|
507
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template generation system for React Native projects
|
|
3
|
+
*
|
|
4
|
+
* Similar to Expo's approach, this module handles copying base templates
|
|
5
|
+
* and processing EJS variables to generate native iOS and Android projects.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { TemplateGenerator, type TemplateOptions, type TemplateVariables } from "./generator";
|
|
9
|
+
export { getTemplatePath, getTemplatesPath } from "./paths";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template path utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get the absolute path to the templates directory
|
|
10
|
+
*/
|
|
11
|
+
export function getTemplatesPath(): string {
|
|
12
|
+
// Get the directory of this file
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = dirname(__filename);
|
|
15
|
+
|
|
16
|
+
// Templates are in ../../templates relative to this file (src/templates/paths.ts)
|
|
17
|
+
return join(__dirname, "..", "..", "templates");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get the path to a specific template
|
|
22
|
+
*/
|
|
23
|
+
export function getTemplatePath(platform: "ios" | "android"): string {
|
|
24
|
+
return join(getTemplatesPath(), platform);
|
|
25
|
+
}
|