@teardown/cli 1.2.39 → 2.0.42

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.
Files changed (260) hide show
  1. package/bin/teardown.js +11 -1
  2. package/package.json +77 -57
  3. package/src/cli/commands/init.ts +254 -0
  4. package/src/cli/commands/plugins.ts +93 -0
  5. package/src/cli/commands/prebuild.ts +168 -0
  6. package/src/cli/commands/run.ts +727 -0
  7. package/src/cli/commands/start.ts +87 -0
  8. package/src/cli/commands/validate.ts +62 -0
  9. package/src/cli/index.ts +59 -0
  10. package/src/config/index.ts +45 -0
  11. package/src/config/loader.ts +366 -0
  12. package/src/config/schema.ts +235 -0
  13. package/src/config/types.ts +322 -0
  14. package/src/index.ts +177 -0
  15. package/src/pipeline/cache.ts +179 -0
  16. package/src/pipeline/index.ts +10 -0
  17. package/src/pipeline/stages.ts +692 -0
  18. package/src/plugins/base.ts +370 -0
  19. package/src/plugins/capabilities/biometrics.ts +64 -0
  20. package/src/plugins/capabilities/bluetooth.ts +86 -0
  21. package/src/plugins/capabilities/calendar.ts +57 -0
  22. package/src/plugins/capabilities/camera.ts +77 -0
  23. package/src/plugins/capabilities/contacts.ts +57 -0
  24. package/src/plugins/capabilities/deep-linking.ts +124 -0
  25. package/src/plugins/capabilities/firebase.ts +138 -0
  26. package/src/plugins/capabilities/index.ts +96 -0
  27. package/src/plugins/capabilities/location.ts +87 -0
  28. package/src/plugins/capabilities/photo-library.ts +80 -0
  29. package/src/plugins/capabilities/push-notifications.ts +98 -0
  30. package/src/plugins/capabilities/sign-in-with-apple.ts +53 -0
  31. package/src/plugins/context.ts +220 -0
  32. package/src/plugins/index.ts +26 -0
  33. package/src/plugins/resolver.ts +321 -0
  34. package/src/templates/generator.ts +507 -0
  35. package/src/templates/index.ts +9 -0
  36. package/src/templates/paths.ts +25 -0
  37. package/src/transformers/android/gradle.ts +400 -0
  38. package/src/transformers/android/index.ts +19 -0
  39. package/src/transformers/android/manifest.ts +506 -0
  40. package/src/transformers/index.ts +39 -0
  41. package/src/transformers/ios/entitlements.ts +283 -0
  42. package/src/transformers/ios/index.ts +10 -0
  43. package/src/transformers/ios/pbxproj.ts +267 -0
  44. package/src/transformers/ios/plist.ts +198 -0
  45. package/src/utils/fs.ts +429 -0
  46. package/src/utils/index.ts +21 -0
  47. package/src/utils/logger.ts +203 -0
  48. package/templates/.gitignore +63 -0
  49. package/templates/Gemfile +3 -0
  50. package/templates/android/app/build.gradle.kts +97 -0
  51. package/templates/android/app/proguard-rules.pro +10 -0
  52. package/templates/android/app/src/main/AndroidManifest.xml +26 -0
  53. package/templates/android/app/src/main/java/com/appname/MainActivity.kt +22 -0
  54. package/templates/android/app/src/main/java/com/appname/MainApplication.kt +44 -0
  55. package/templates/android/app/src/main/res/values/strings.xml +3 -0
  56. package/templates/android/app/src/main/res/values/styles.xml +7 -0
  57. package/templates/android/build.gradle.kts +44 -0
  58. package/templates/android/gradle.properties +39 -0
  59. package/templates/android/settings.gradle.kts +12 -0
  60. package/templates/babel.config.js +15 -0
  61. package/templates/index.js +7 -0
  62. package/templates/ios/.xcode.env +11 -0
  63. package/templates/ios/AppName/AppDelegate.swift +25 -0
  64. package/templates/ios/AppName/AppName-Bridging-Header.h +4 -0
  65. package/templates/ios/AppName/AppName.entitlements +6 -0
  66. package/templates/ios/AppName/Images.xcassets/AppIcon.appiconset/Contents.json +35 -0
  67. package/templates/ios/AppName/Images.xcassets/Contents.json +6 -0
  68. package/templates/ios/AppName/Info.plist +49 -0
  69. package/templates/ios/AppName/LaunchScreen.storyboard +38 -0
  70. package/templates/ios/AppName.xcodeproj/project.pbxproj +402 -0
  71. package/templates/ios/AppName.xcodeproj/xcshareddata/xcschemes/AppName.xcscheme +78 -0
  72. package/templates/ios/Podfile +35 -0
  73. package/templates/metro.config.js +41 -0
  74. package/templates/package.json +57 -0
  75. package/templates/react-native.config.js +8 -0
  76. package/templates/src/app/index.tsx +34 -0
  77. package/templates/src/assets/fonts/.gitkeep +1 -0
  78. package/templates/src/assets/images/.gitkeep +1 -0
  79. package/templates/src/components/ui/accordion.tsx +114 -0
  80. package/templates/src/components/ui/avatar.tsx +75 -0
  81. package/templates/src/components/ui/button.tsx +93 -0
  82. package/templates/src/components/ui/card.tsx +120 -0
  83. package/templates/src/components/ui/checkbox.tsx +133 -0
  84. package/templates/src/components/ui/chip.tsx +95 -0
  85. package/templates/src/components/ui/dialog.tsx +134 -0
  86. package/templates/src/components/ui/divider.tsx +67 -0
  87. package/templates/src/components/ui/error-view.tsx +82 -0
  88. package/templates/src/components/ui/form-field.tsx +101 -0
  89. package/templates/src/components/ui/index.ts +100 -0
  90. package/templates/src/components/ui/popover.tsx +92 -0
  91. package/templates/src/components/ui/pressable-feedback.tsx +88 -0
  92. package/templates/src/components/ui/radio-group.tsx +153 -0
  93. package/templates/src/components/ui/scroll-shadow.tsx +108 -0
  94. package/templates/src/components/ui/select.tsx +165 -0
  95. package/templates/src/components/ui/skeleton-group.tsx +97 -0
  96. package/templates/src/components/ui/skeleton.tsx +87 -0
  97. package/templates/src/components/ui/spinner.tsx +87 -0
  98. package/templates/src/components/ui/surface.tsx +95 -0
  99. package/templates/src/components/ui/switch.tsx +124 -0
  100. package/templates/src/components/ui/tabs.tsx +154 -0
  101. package/templates/src/components/ui/text-field.tsx +106 -0
  102. package/templates/src/components/ui/toast.tsx +129 -0
  103. package/templates/src/contexts/.gitkeep +2 -0
  104. package/templates/src/core/clients/api/api.client.ts +113 -0
  105. package/templates/src/core/clients/api/index.ts +1 -0
  106. package/templates/src/core/clients/storage/index.ts +1 -0
  107. package/templates/src/core/clients/storage/storage.client.ts +121 -0
  108. package/templates/src/core/constants/index.ts +19 -0
  109. package/templates/src/core/core.ts +40 -0
  110. package/templates/src/core/index.ts +10 -0
  111. package/templates/src/global.css +87 -0
  112. package/templates/src/hooks/index.ts +6 -0
  113. package/templates/src/hooks/use-debounce.ts +23 -0
  114. package/templates/src/hooks/use-mounted.ts +21 -0
  115. package/templates/src/index.ts +28 -0
  116. package/templates/src/lib/index.ts +5 -0
  117. package/templates/src/lib/utils.ts +115 -0
  118. package/templates/src/modules/.gitkeep +6 -0
  119. package/templates/src/navigation/index.ts +8 -0
  120. package/templates/src/navigation/navigation-provider.tsx +36 -0
  121. package/templates/src/navigation/router.tsx +137 -0
  122. package/templates/src/providers/app.provider.tsx +29 -0
  123. package/templates/src/providers/index.ts +5 -0
  124. package/templates/src/routes/(tabs)/_layout.tsx +42 -0
  125. package/templates/src/routes/(tabs)/explore.tsx +161 -0
  126. package/templates/src/routes/(tabs)/home.tsx +138 -0
  127. package/templates/src/routes/(tabs)/profile.tsx +151 -0
  128. package/templates/src/routes/_layout.tsx +18 -0
  129. package/templates/src/routes/settings.tsx +194 -0
  130. package/templates/src/screens/auth/index.ts +6 -0
  131. package/templates/src/screens/auth/login.tsx +165 -0
  132. package/templates/src/screens/auth/register.tsx +203 -0
  133. package/templates/src/screens/home.tsx +204 -0
  134. package/templates/src/screens/index.ts +17 -0
  135. package/templates/src/screens/profile.tsx +210 -0
  136. package/templates/src/screens/settings.tsx +216 -0
  137. package/templates/src/screens/welcome.tsx +101 -0
  138. package/templates/src/styles/index.ts +103 -0
  139. package/templates/src/types/common.ts +71 -0
  140. package/templates/src/types/index.ts +5 -0
  141. package/templates/tsconfig.json +14 -0
  142. package/README.md +0 -15
  143. package/assets/favicon.ico +0 -0
  144. package/dist/commands/dev/dev.d.ts +0 -22
  145. package/dist/commands/dev/dev.js +0 -56
  146. package/dist/commands/dev/dev.js.map +0 -1
  147. package/dist/commands/init/init-teardown.d.ts +0 -9
  148. package/dist/commands/init/init-teardown.js +0 -27
  149. package/dist/commands/init/init-teardown.js.map +0 -1
  150. package/dist/index.d.ts +0 -1
  151. package/dist/index.js +0 -21
  152. package/dist/index.js.map +0 -1
  153. package/dist/modules/dev/dev-menu/keyboard-handler.d.ts +0 -21
  154. package/dist/modules/dev/dev-menu/keyboard-handler.js +0 -139
  155. package/dist/modules/dev/dev-menu/keyboard-handler.js.map +0 -1
  156. package/dist/modules/dev/dev-menu/open-debugger-keyboard-handler.d.ts +0 -18
  157. package/dist/modules/dev/dev-menu/open-debugger-keyboard-handler.js +0 -106
  158. package/dist/modules/dev/dev-menu/open-debugger-keyboard-handler.js.map +0 -1
  159. package/dist/modules/dev/dev-server/cdp/cdp.adapter.d.ts +0 -6
  160. package/dist/modules/dev/dev-server/cdp/cdp.adapter.js +0 -13
  161. package/dist/modules/dev/dev-server/cdp/cdp.adapter.js.map +0 -1
  162. package/dist/modules/dev/dev-server/cdp/index.d.ts +0 -2
  163. package/dist/modules/dev/dev-server/cdp/index.js +0 -19
  164. package/dist/modules/dev/dev-server/cdp/index.js.map +0 -1
  165. package/dist/modules/dev/dev-server/cdp/types.d.ts +0 -107
  166. package/dist/modules/dev/dev-server/cdp/types.js +0 -3
  167. package/dist/modules/dev/dev-server/cdp/types.js.map +0 -1
  168. package/dist/modules/dev/dev-server/dev-server-checker.d.ts +0 -22
  169. package/dist/modules/dev/dev-server/dev-server-checker.js +0 -73
  170. package/dist/modules/dev/dev-server/dev-server-checker.js.map +0 -1
  171. package/dist/modules/dev/dev-server/dev-server.d.ts +0 -74
  172. package/dist/modules/dev/dev-server/dev-server.js +0 -272
  173. package/dist/modules/dev/dev-server/dev-server.js.map +0 -1
  174. package/dist/modules/dev/dev-server/inspector/device.d.ts +0 -46
  175. package/dist/modules/dev/dev-server/inspector/device.event-reporter.d.ts +0 -37
  176. package/dist/modules/dev/dev-server/inspector/device.event-reporter.js +0 -166
  177. package/dist/modules/dev/dev-server/inspector/device.event-reporter.js.map +0 -1
  178. package/dist/modules/dev/dev-server/inspector/device.js +0 -578
  179. package/dist/modules/dev/dev-server/inspector/device.js.map +0 -1
  180. package/dist/modules/dev/dev-server/inspector/inspector.d.ts +0 -27
  181. package/dist/modules/dev/dev-server/inspector/inspector.js +0 -225
  182. package/dist/modules/dev/dev-server/inspector/inspector.js.map +0 -1
  183. package/dist/modules/dev/dev-server/inspector/types.d.ts +0 -156
  184. package/dist/modules/dev/dev-server/inspector/types.js +0 -3
  185. package/dist/modules/dev/dev-server/inspector/types.js.map +0 -1
  186. package/dist/modules/dev/dev-server/inspector/wss/servers/debugger-connection.server.d.ts +0 -14
  187. package/dist/modules/dev/dev-server/inspector/wss/servers/debugger-connection.server.js +0 -63
  188. package/dist/modules/dev/dev-server/inspector/wss/servers/debugger-connection.server.js.map +0 -1
  189. package/dist/modules/dev/dev-server/inspector/wss/servers/device-connection.server.d.ts +0 -19
  190. package/dist/modules/dev/dev-server/inspector/wss/servers/device-connection.server.js +0 -66
  191. package/dist/modules/dev/dev-server/inspector/wss/servers/device-connection.server.js.map +0 -1
  192. package/dist/modules/dev/dev-server/plugins/devtools.plugin.d.ts +0 -1
  193. package/dist/modules/dev/dev-server/plugins/devtools.plugin.js +0 -51
  194. package/dist/modules/dev/dev-server/plugins/devtools.plugin.js.map +0 -1
  195. package/dist/modules/dev/dev-server/plugins/favicon.plugin.d.ts +0 -1
  196. package/dist/modules/dev/dev-server/plugins/favicon.plugin.js +0 -19
  197. package/dist/modules/dev/dev-server/plugins/favicon.plugin.js.map +0 -1
  198. package/dist/modules/dev/dev-server/plugins/multipart.plugin.d.ts +0 -1
  199. package/dist/modules/dev/dev-server/plugins/multipart.plugin.js +0 -63
  200. package/dist/modules/dev/dev-server/plugins/multipart.plugin.js.map +0 -1
  201. package/dist/modules/dev/dev-server/plugins/systrace.plugin.d.ts +0 -1
  202. package/dist/modules/dev/dev-server/plugins/systrace.plugin.js +0 -29
  203. package/dist/modules/dev/dev-server/plugins/systrace.plugin.js.map +0 -1
  204. package/dist/modules/dev/dev-server/plugins/types.d.ts +0 -11
  205. package/dist/modules/dev/dev-server/plugins/types.js +0 -3
  206. package/dist/modules/dev/dev-server/plugins/types.js.map +0 -1
  207. package/dist/modules/dev/dev-server/plugins/wss/index.d.ts +0 -3
  208. package/dist/modules/dev/dev-server/plugins/wss/index.js +0 -20
  209. package/dist/modules/dev/dev-server/plugins/wss/index.js.map +0 -1
  210. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-api.server.d.ts +0 -37
  211. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-api.server.js +0 -67
  212. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-api.server.js.map +0 -1
  213. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-debugger.server.d.ts +0 -63
  214. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-debugger.server.js +0 -129
  215. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-debugger.server.js.map +0 -1
  216. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-dev-client.server.d.ts +0 -32
  217. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-dev-client.server.js +0 -76
  218. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-dev-client.server.js.map +0 -1
  219. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-events.server.d.ts +0 -75
  220. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-events.server.js +0 -199
  221. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-events.server.js.map +0 -1
  222. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-hmr.server.d.ts +0 -44
  223. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-hmr.server.js +0 -121
  224. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-hmr.server.js.map +0 -1
  225. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-message.server.d.ts +0 -135
  226. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-message.server.js +0 -364
  227. package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-message.server.js.map +0 -1
  228. package/dist/modules/dev/dev-server/plugins/wss/types.d.ts +0 -6
  229. package/dist/modules/dev/dev-server/plugins/wss/types.js +0 -3
  230. package/dist/modules/dev/dev-server/plugins/wss/types.js.map +0 -1
  231. package/dist/modules/dev/dev-server/plugins/wss/web-socket-router.d.ts +0 -32
  232. package/dist/modules/dev/dev-server/plugins/wss/web-socket-router.js +0 -58
  233. package/dist/modules/dev/dev-server/plugins/wss/web-socket-router.js.map +0 -1
  234. package/dist/modules/dev/dev-server/plugins/wss/web-socket-server-adapter.d.ts +0 -13
  235. package/dist/modules/dev/dev-server/plugins/wss/web-socket-server-adapter.js +0 -27
  236. package/dist/modules/dev/dev-server/plugins/wss/web-socket-server-adapter.js.map +0 -1
  237. package/dist/modules/dev/dev-server/plugins/wss/web-socket-server.d.ts +0 -39
  238. package/dist/modules/dev/dev-server/plugins/wss/web-socket-server.js +0 -47
  239. package/dist/modules/dev/dev-server/plugins/wss/web-socket-server.js.map +0 -1
  240. package/dist/modules/dev/dev-server/plugins/wss/wss.plugin.d.ts +0 -24
  241. package/dist/modules/dev/dev-server/plugins/wss/wss.plugin.js +0 -56
  242. package/dist/modules/dev/dev-server/plugins/wss/wss.plugin.js.map +0 -1
  243. package/dist/modules/dev/dev-server/sybmolicate/sybmolicate.plugin.d.ts +0 -7
  244. package/dist/modules/dev/dev-server/sybmolicate/sybmolicate.plugin.js +0 -41
  245. package/dist/modules/dev/dev-server/sybmolicate/sybmolicate.plugin.js.map +0 -1
  246. package/dist/modules/dev/dev-server/sybmolicate/types.d.ts +0 -64
  247. package/dist/modules/dev/dev-server/sybmolicate/types.js +0 -3
  248. package/dist/modules/dev/dev-server/sybmolicate/types.js.map +0 -1
  249. package/dist/modules/dev/terminal/base.terminal.reporter.d.ts +0 -25
  250. package/dist/modules/dev/terminal/base.terminal.reporter.js +0 -79
  251. package/dist/modules/dev/terminal/base.terminal.reporter.js.map +0 -1
  252. package/dist/modules/dev/terminal/terminal.reporter.d.ts +0 -13
  253. package/dist/modules/dev/terminal/terminal.reporter.js +0 -83
  254. package/dist/modules/dev/terminal/terminal.reporter.js.map +0 -1
  255. package/dist/modules/dev/types.d.ts +0 -20
  256. package/dist/modules/dev/types.js +0 -3
  257. package/dist/modules/dev/types.js.map +0 -1
  258. package/dist/modules/dev/utils/log.d.ts +0 -23
  259. package/dist/modules/dev/utils/log.js +0 -74
  260. package/dist/modules/dev/utils/log.js.map +0 -1
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Start command - starts the Metro bundler
3
+ */
4
+
5
+ import { spawn } from "node:child_process";
6
+ import { existsSync } from "node:fs";
7
+ import { join } from "node:path";
8
+ import chalk from "chalk";
9
+ import { Command } from "commander";
10
+
11
+ /**
12
+ * Check if a metro.config.js file exists in the project
13
+ */
14
+ function hasMetroConfig(projectRoot: string): boolean {
15
+ const configPaths = ["metro.config.js", "metro.config.cjs", "metro.config.mjs"];
16
+ return configPaths.some((config) => existsSync(join(projectRoot, config)));
17
+ }
18
+
19
+ /**
20
+ * Check if @teardown/metro-config is installed
21
+ */
22
+ function hasTeardownMetroConfig(projectRoot: string): boolean {
23
+ const nodeModulesPath = join(projectRoot, "node_modules", "@teardown", "metro-config");
24
+ return existsSync(nodeModulesPath);
25
+ }
26
+
27
+ /**
28
+ * Create the start command
29
+ */
30
+ export function createStartCommand(): Command {
31
+ const start = new Command("start")
32
+ .description("Start the Metro bundler")
33
+ .option("-p, --port <port>", "Port to run Metro on", "8081")
34
+ .option("--reset-cache", "Reset the Metro cache")
35
+ .option("--platform <platform>", "Platform to target (ios, android, all)", "all")
36
+ .option("--verbose", "Enable verbose logging")
37
+ .action(async (options) => {
38
+ const projectRoot = process.cwd();
39
+
40
+ // Check for metro config
41
+ if (!hasMetroConfig(projectRoot)) {
42
+ console.log(chalk.yellow("No metro.config.js found. Using default React Native config.\n"));
43
+ console.log(chalk.gray("Tip: Add @teardown/metro-config for 36x faster builds:\n"));
44
+ console.log(
45
+ chalk.gray(` 1. bun add @teardown/metro-config\n 2. Create metro.config.js with withTeardown()\n`)
46
+ );
47
+ } else if (!hasTeardownMetroConfig(projectRoot)) {
48
+ console.log(chalk.gray("Tip: Add @teardown/metro-config for 36x faster builds\n"));
49
+ }
50
+
51
+ console.log(chalk.blue("Starting Metro bundler...\n"));
52
+
53
+ const args = ["react-native", "start", "--port", options.port];
54
+
55
+ if (options.resetCache) {
56
+ args.push("--reset-cache");
57
+ }
58
+
59
+ if (options.verbose) {
60
+ args.push("--verbose");
61
+ }
62
+
63
+ const proc = spawn("npx", args, {
64
+ stdio: "inherit",
65
+ shell: true,
66
+ cwd: projectRoot,
67
+ env: {
68
+ ...process.env,
69
+ // Ensure proper encoding for CocoaPods compatibility
70
+ LANG: "en_US.UTF-8",
71
+ },
72
+ });
73
+
74
+ proc.on("error", (error) => {
75
+ console.error(chalk.red(`Failed to start Metro: ${error.message}`));
76
+ process.exit(1);
77
+ });
78
+
79
+ proc.on("close", (code) => {
80
+ if (code !== 0 && code !== null) {
81
+ process.exit(code);
82
+ }
83
+ });
84
+ });
85
+
86
+ return start;
87
+ }
@@ -0,0 +1,62 @@
1
+ import chalk from "chalk";
2
+ import { Command } from "commander";
3
+ import ora from "ora";
4
+ import { loadConfig } from "../../config";
5
+
6
+ /**
7
+ * Create the validate command
8
+ */
9
+ export function createValidateCommand(): Command {
10
+ const command = new Command("validate").description("Validate the Teardown configuration file").action(async () => {
11
+ const spinner = ora("Validating configuration...").start();
12
+
13
+ try {
14
+ const projectRoot = process.cwd();
15
+ const result = await loadConfig(projectRoot);
16
+
17
+ if (!result.success) {
18
+ spinner.fail("Configuration validation failed");
19
+
20
+ console.error(chalk.red("\nErrors:"));
21
+ for (const error of result.errors ?? []) {
22
+ console.error(chalk.red(` - ${error.path || "config"}: ${error.message}`));
23
+ if (error.suggestion) {
24
+ console.error(chalk.gray(` Suggestion: ${error.suggestion}`));
25
+ }
26
+ }
27
+ process.exit(1);
28
+ }
29
+
30
+ spinner.succeed("Configuration is valid");
31
+
32
+ console.log(chalk.green("\nConfiguration summary:"));
33
+ console.log(chalk.gray(` Name: ${result.config?.name}`));
34
+ console.log(chalk.gray(` Slug: ${result.config?.slug}`));
35
+ console.log(chalk.gray(` Version: ${result.config?.version}`));
36
+
37
+ if (result.config?.ios) {
38
+ console.log(chalk.blue("\n iOS:"));
39
+ console.log(chalk.gray(` Bundle ID: ${result.config?.ios.bundleIdentifier}`));
40
+ console.log(chalk.gray(` Deployment Target: ${result.config?.ios.deploymentTarget}`));
41
+ }
42
+
43
+ if (result.config?.android) {
44
+ console.log(chalk.green("\n Android:"));
45
+ console.log(chalk.gray(` Package: ${result.config?.android.packageName}`));
46
+ console.log(chalk.gray(` Min SDK: ${result.config?.android.minSdkVersion}`));
47
+ console.log(chalk.gray(` Target SDK: ${result.config?.android.targetSdkVersion}`));
48
+ }
49
+
50
+ const pluginCount = result.config?.plugins?.length ?? 0;
51
+ if (pluginCount > 0) {
52
+ console.log(chalk.cyan(`\n Plugins: ${pluginCount}`));
53
+ }
54
+ } catch (error) {
55
+ spinner.fail("Validation failed");
56
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
57
+ process.exit(1);
58
+ }
59
+ });
60
+
61
+ return command;
62
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * CLI for Teardown Launchpad
3
+ */
4
+
5
+ import { Command } from "commander";
6
+ import { createInitCommand } from "./commands/init";
7
+ import { createPluginsCommand } from "./commands/plugins";
8
+ import { createPrebuildCommand } from "./commands/prebuild";
9
+ import { createRunCommand } from "./commands/run";
10
+ import { createStartCommand } from "./commands/start";
11
+ import { createValidateCommand } from "./commands/validate";
12
+
13
+ /**
14
+ * Package version (injected at build time)
15
+ */
16
+ const VERSION = "0.0.1";
17
+
18
+ /**
19
+ * Create and configure the CLI program
20
+ */
21
+ export function createProgram(): Command {
22
+ const program = new Command()
23
+ .name("teardown")
24
+ .description("Teardown CLI - React Native Development Toolkit")
25
+ .version(VERSION);
26
+
27
+ // Add commands
28
+ program.addCommand(createPrebuildCommand());
29
+ program.addCommand(createValidateCommand());
30
+ program.addCommand(createInitCommand());
31
+ program.addCommand(createPluginsCommand());
32
+ program.addCommand(createRunCommand());
33
+ program.addCommand(createStartCommand());
34
+
35
+ // Default command (prebuild)
36
+ program.argument("[command]").action((cmd) => {
37
+ if (!cmd) {
38
+ program.help();
39
+ }
40
+ });
41
+
42
+ return program;
43
+ }
44
+
45
+ /**
46
+ * Run the CLI
47
+ */
48
+ export async function run(args: string[] = process.argv): Promise<void> {
49
+ const program = createProgram();
50
+ await program.parseAsync(args);
51
+ }
52
+
53
+ export { createInitCommand } from "./commands/init";
54
+ export { createPluginsCommand } from "./commands/plugins";
55
+ // Export commands for testing
56
+ export { createPrebuildCommand } from "./commands/prebuild";
57
+ export { createRunCommand } from "./commands/run";
58
+ export { createStartCommand } from "./commands/start";
59
+ export { createValidateCommand } from "./commands/validate";
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Configuration module for Teardown Launchpad
3
+ *
4
+ * Provides configuration loading, validation, and type definitions
5
+ * for the prebuild system.
6
+ */
7
+
8
+ export type { ConfigLoadResult } from "./loader";
9
+
10
+ export { findConfigFile, generateDefaultConfig, loadConfig, watchConfig } from "./loader";
11
+ export {
12
+ AndroidConfigSchema,
13
+ defineConfig,
14
+ formatValidationErrors,
15
+ iOSConfigSchema,
16
+ SplashConfigSchema,
17
+ TeardownConfigSchema,
18
+ validateConfig,
19
+ } from "./schema";
20
+
21
+ export type {
22
+ AndroidConfig,
23
+ AndroidIntentFilter,
24
+ AndroidWidgetDefinition,
25
+ BuildConfig,
26
+ DryRunResult,
27
+ FileChange,
28
+ HealthConnectDataType,
29
+ HealthKitDataType,
30
+ IntentDefinition,
31
+ IntentParameter,
32
+ iOSConfig,
33
+ PermissionConfig,
34
+ PermissionMapping,
35
+ PermissionStatus,
36
+ PluginEntry,
37
+ PrebuildError,
38
+ PrebuildOptions,
39
+ PrebuildWarning,
40
+ ProcessedAppConfig,
41
+ SplashConfig,
42
+ TeardownConfig,
43
+ TemplateContext,
44
+ WidgetDefinition,
45
+ } from "./types";
@@ -0,0 +1,366 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { Project, SyntaxKind } from "ts-morph";
4
+ import { type ValidationError, validateConfig } from "./schema";
5
+ import type { TeardownConfig } from "./types";
6
+
7
+ /**
8
+ * Configuration file names to search for (in order of priority)
9
+ */
10
+ const CONFIG_FILE_NAMES = [
11
+ "teardown.config.ts",
12
+ "teardown.config.js",
13
+ "teardown.config.mjs",
14
+ "launchpad.config.ts",
15
+ "launchpad.config.js",
16
+ ];
17
+
18
+ /**
19
+ * Result of loading configuration
20
+ */
21
+ export interface ConfigLoadResult {
22
+ success: boolean;
23
+ config?: TeardownConfig;
24
+ configPath?: string;
25
+ errors?: ValidationError[];
26
+ }
27
+
28
+ /**
29
+ * Find the configuration file in the project root
30
+ */
31
+ export function findConfigFile(projectRoot: string): string | null {
32
+ for (const fileName of CONFIG_FILE_NAMES) {
33
+ const filePath = path.join(projectRoot, fileName);
34
+ if (fs.existsSync(filePath)) {
35
+ return filePath;
36
+ }
37
+ }
38
+ return null;
39
+ }
40
+
41
+ /**
42
+ * Load and parse the configuration file
43
+ */
44
+ export async function loadConfig(projectRoot: string): Promise<ConfigLoadResult> {
45
+ const configPath = findConfigFile(projectRoot);
46
+
47
+ if (!configPath) {
48
+ return {
49
+ success: false,
50
+ errors: [
51
+ {
52
+ path: "",
53
+ message: `No configuration file found. Expected one of: ${CONFIG_FILE_NAMES.join(", ")}`,
54
+ suggestion: "Create a teardown.config.ts file in your project root",
55
+ },
56
+ ],
57
+ };
58
+ }
59
+
60
+ try {
61
+ // For TypeScript files, we need to transpile first
62
+ if (configPath.endsWith(".ts")) {
63
+ return await loadTypeScriptConfig(configPath);
64
+ }
65
+
66
+ // For JavaScript files, we can import directly
67
+ const module = await import(configPath);
68
+ const config = module.default || module;
69
+
70
+ const validation = validateConfig(config);
71
+
72
+ if (!validation.success) {
73
+ return {
74
+ success: false,
75
+ configPath,
76
+ errors: validation.errors,
77
+ };
78
+ }
79
+
80
+ return {
81
+ success: true,
82
+ config: validation.data,
83
+ configPath,
84
+ };
85
+ } catch (error) {
86
+ return {
87
+ success: false,
88
+ configPath,
89
+ errors: [
90
+ {
91
+ path: "",
92
+ message: `Failed to load configuration: ${error instanceof Error ? error.message : String(error)}`,
93
+ },
94
+ ],
95
+ };
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Load TypeScript configuration file
101
+ */
102
+ async function loadTypeScriptConfig(configPath: string): Promise<ConfigLoadResult> {
103
+ try {
104
+ // Use Bun's native TypeScript support if available
105
+ if (typeof Bun !== "undefined") {
106
+ // Add cache-busting query param to force fresh import
107
+ const cacheBuster = `?t=${Date.now()}`;
108
+ const module = await import(configPath + cacheBuster);
109
+ const config = module.default || module;
110
+
111
+ const validation = validateConfig(config);
112
+
113
+ if (!validation.success) {
114
+ return {
115
+ success: false,
116
+ configPath,
117
+ errors: validation.errors,
118
+ };
119
+ }
120
+
121
+ return {
122
+ success: true,
123
+ config: validation.data,
124
+ configPath,
125
+ };
126
+ }
127
+
128
+ // Fallback: Parse with ts-morph for analysis
129
+ const project = new Project({
130
+ compilerOptions: {
131
+ target: 99, // ESNext
132
+ module: 99, // ESNext
133
+ moduleResolution: 100, // Bundler
134
+ },
135
+ });
136
+
137
+ const sourceFile = project.addSourceFileAtPath(configPath);
138
+
139
+ // Find the default export
140
+ const defaultExport = sourceFile.getExportAssignment((d) => !d.isExportEquals());
141
+
142
+ if (!defaultExport) {
143
+ return {
144
+ success: false,
145
+ configPath,
146
+ errors: [
147
+ {
148
+ path: "",
149
+ message: "Configuration file must have a default export",
150
+ suggestion: "Add 'export default defineConfig({ ... })' to your config file",
151
+ },
152
+ ],
153
+ };
154
+ }
155
+
156
+ // Get the expression being exported
157
+ const expression = defaultExport.getExpression();
158
+
159
+ // If it's a call expression (defineConfig(...)), get the argument
160
+ let configObject: unknown;
161
+
162
+ if (expression.getKind() === SyntaxKind.CallExpression) {
163
+ const callExpr = expression.asKind(SyntaxKind.CallExpression);
164
+ const args = callExpr?.getArguments();
165
+
166
+ if (args && args.length > 0) {
167
+ const firstArg = args[0];
168
+ if (firstArg.getKind() === SyntaxKind.ObjectLiteralExpression) {
169
+ configObject = evaluateObjectLiteral(firstArg);
170
+ }
171
+ }
172
+ } else if (expression.getKind() === SyntaxKind.ObjectLiteralExpression) {
173
+ configObject = evaluateObjectLiteral(expression);
174
+ }
175
+
176
+ if (!configObject) {
177
+ return {
178
+ success: false,
179
+ configPath,
180
+ errors: [
181
+ {
182
+ path: "",
183
+ message: "Could not parse configuration object",
184
+ suggestion: "Ensure your config exports a plain object or uses defineConfig()",
185
+ },
186
+ ],
187
+ };
188
+ }
189
+
190
+ const validation = validateConfig(configObject);
191
+
192
+ if (!validation.success) {
193
+ return {
194
+ success: false,
195
+ configPath,
196
+ errors: validation.errors,
197
+ };
198
+ }
199
+
200
+ return {
201
+ success: true,
202
+ config: validation.data,
203
+ configPath,
204
+ };
205
+ } catch (error) {
206
+ return {
207
+ success: false,
208
+ configPath,
209
+ errors: [
210
+ {
211
+ path: "",
212
+ message: `Failed to parse TypeScript config: ${error instanceof Error ? error.message : String(error)}`,
213
+ },
214
+ ],
215
+ };
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Evaluate an object literal expression to a JavaScript object
221
+ * This is a simplified evaluator that handles common cases
222
+ */
223
+ function evaluateObjectLiteral(node: import("ts-morph").Node): Record<string, unknown> {
224
+ const obj: Record<string, unknown> = {};
225
+ const objLiteral = node.asKind(SyntaxKind.ObjectLiteralExpression);
226
+
227
+ if (!objLiteral) {
228
+ return obj;
229
+ }
230
+
231
+ for (const prop of objLiteral.getProperties()) {
232
+ if (prop.getKind() === SyntaxKind.PropertyAssignment) {
233
+ const propAssign = prop.asKind(SyntaxKind.PropertyAssignment);
234
+ if (!propAssign) continue;
235
+
236
+ const name = propAssign.getName();
237
+ const initializer = propAssign.getInitializer();
238
+
239
+ if (!initializer) continue;
240
+
241
+ obj[name] = evaluateExpression(initializer);
242
+ } else if (prop.getKind() === SyntaxKind.ShorthandPropertyAssignment) {
243
+ const shorthand = prop.asKind(SyntaxKind.ShorthandPropertyAssignment);
244
+ if (!shorthand) continue;
245
+
246
+ const name = shorthand.getName();
247
+ // For shorthand, we can't easily resolve the value without runtime
248
+ obj[name] = undefined;
249
+ }
250
+ }
251
+
252
+ return obj;
253
+ }
254
+
255
+ /**
256
+ * Evaluate a simple expression to a JavaScript value
257
+ */
258
+ function evaluateExpression(node: import("ts-morph").Node): unknown {
259
+ const kind = node.getKind();
260
+
261
+ switch (kind) {
262
+ case SyntaxKind.StringLiteral:
263
+ return node.asKind(SyntaxKind.StringLiteral)?.getLiteralValue();
264
+
265
+ case SyntaxKind.NumericLiteral:
266
+ return node.asKind(SyntaxKind.NumericLiteral)?.getLiteralValue();
267
+
268
+ case SyntaxKind.TrueKeyword:
269
+ return true;
270
+
271
+ case SyntaxKind.FalseKeyword:
272
+ return false;
273
+
274
+ case SyntaxKind.NullKeyword:
275
+ return null;
276
+
277
+ case SyntaxKind.ObjectLiteralExpression:
278
+ return evaluateObjectLiteral(node);
279
+
280
+ case SyntaxKind.ArrayLiteralExpression: {
281
+ const arrayLiteral = node.asKind(SyntaxKind.ArrayLiteralExpression);
282
+ if (!arrayLiteral) return [];
283
+ return arrayLiteral.getElements().map((el) => evaluateExpression(el));
284
+ }
285
+
286
+ default:
287
+ // For complex expressions, return the text representation
288
+ return node.getText();
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Watch configuration file for changes
294
+ */
295
+ export function watchConfig(projectRoot: string, onChange: (result: ConfigLoadResult) => void): () => void {
296
+ const configPath = findConfigFile(projectRoot);
297
+
298
+ if (!configPath) {
299
+ onChange({
300
+ success: false,
301
+ errors: [
302
+ {
303
+ path: "",
304
+ message: "No configuration file found",
305
+ },
306
+ ],
307
+ });
308
+ return () => {};
309
+ }
310
+
311
+ const watcher = fs.watch(configPath, async (eventType) => {
312
+ if (eventType === "change") {
313
+ const result = await loadConfig(projectRoot);
314
+ onChange(result);
315
+ }
316
+ });
317
+
318
+ return () => watcher.close();
319
+ }
320
+
321
+ /**
322
+ * Generate a default configuration file
323
+ */
324
+ export function generateDefaultConfig(options: {
325
+ name: string;
326
+ slug: string;
327
+ bundleIdentifier?: string;
328
+ packageName?: string;
329
+ }): string {
330
+ const { name, slug } = options;
331
+ const bundleIdentifier = options.bundleIdentifier || `com.example.${slug.replace(/-/g, "")}`;
332
+ const packageName = options.packageName || bundleIdentifier;
333
+
334
+ return `import { defineConfig } from "@teardown/cli";
335
+
336
+ export default defineConfig({
337
+ name: '${name}',
338
+ slug: '${slug}',
339
+ version: '1.0.0',
340
+
341
+ ios: {
342
+ bundleIdentifier: '${bundleIdentifier}',
343
+ buildNumber: 1,
344
+ deploymentTarget: '15.0',
345
+ },
346
+
347
+ android: {
348
+ packageName: '${packageName}',
349
+ versionCode: 1,
350
+ minSdkVersion: 23,
351
+ targetSdkVersion: 34,
352
+ },
353
+
354
+ icon: './assets/icon.png',
355
+
356
+ splash: {
357
+ image: './assets/splash.png',
358
+ backgroundColor: '#FFFFFF',
359
+ },
360
+
361
+ plugins: [
362
+ // Add your plugins here
363
+ ],
364
+ });
365
+ `;
366
+ }