@jetstart/core 1.7.0 → 2.0.0

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 (40) hide show
  1. package/README.md +189 -74
  2. package/dist/build/dex-generator.d.ts +27 -0
  3. package/dist/build/dex-generator.js +202 -0
  4. package/dist/build/dsl-parser.d.ts +3 -30
  5. package/dist/build/dsl-parser.js +67 -240
  6. package/dist/build/dsl-types.d.ts +8 -0
  7. package/dist/build/gradle.d.ts +51 -0
  8. package/dist/build/gradle.js +233 -1
  9. package/dist/build/hot-reload-service.d.ts +36 -0
  10. package/dist/build/hot-reload-service.js +179 -0
  11. package/dist/build/js-compiler-service.d.ts +61 -0
  12. package/dist/build/js-compiler-service.js +421 -0
  13. package/dist/build/kotlin-compiler.d.ts +54 -0
  14. package/dist/build/kotlin-compiler.js +450 -0
  15. package/dist/build/kotlin-parser.d.ts +91 -0
  16. package/dist/build/kotlin-parser.js +1030 -0
  17. package/dist/build/override-generator.d.ts +54 -0
  18. package/dist/build/override-generator.js +430 -0
  19. package/dist/server/index.d.ts +16 -1
  20. package/dist/server/index.js +147 -42
  21. package/dist/websocket/handler.d.ts +20 -4
  22. package/dist/websocket/handler.js +73 -38
  23. package/dist/websocket/index.d.ts +8 -0
  24. package/dist/websocket/index.js +15 -11
  25. package/dist/websocket/manager.d.ts +2 -2
  26. package/dist/websocket/manager.js +1 -1
  27. package/package.json +3 -3
  28. package/src/build/dex-generator.ts +197 -0
  29. package/src/build/dsl-parser.ts +73 -272
  30. package/src/build/dsl-types.ts +9 -0
  31. package/src/build/gradle.ts +259 -1
  32. package/src/build/hot-reload-service.ts +178 -0
  33. package/src/build/js-compiler-service.ts +411 -0
  34. package/src/build/kotlin-compiler.ts +460 -0
  35. package/src/build/kotlin-parser.ts +1043 -0
  36. package/src/build/override-generator.ts +478 -0
  37. package/src/server/index.ts +162 -54
  38. package/src/websocket/handler.ts +94 -56
  39. package/src/websocket/index.ts +27 -14
  40. package/src/websocket/manager.ts +2 -2
@@ -37,12 +37,244 @@ var __importStar = (this && this.__importStar) || (function () {
37
37
  };
38
38
  })();
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
- exports.GradleExecutor = void 0;
40
+ exports.GradleExecutor = exports.AdbHelper = void 0;
41
41
  const child_process_1 = require("child_process");
42
42
  const fs = __importStar(require("fs"));
43
43
  const path = __importStar(require("path"));
44
44
  const os = __importStar(require("os"));
45
45
  const parser_1 = require("./parser");
46
+ /**
47
+ * ADB Helper for auto-installing APKs
48
+ */
49
+ class AdbHelper {
50
+ adbPath = null;
51
+ connectedDevices = new Map();
52
+ constructor() {
53
+ this.adbPath = this.findAdb();
54
+ }
55
+ /**
56
+ * Find adb executable
57
+ */
58
+ findAdb() {
59
+ const isWindows = os.platform() === 'win32';
60
+ // Check common locations
61
+ const commonPaths = isWindows ? [
62
+ 'C:\\Android\\platform-tools\\adb.exe',
63
+ path.join(os.homedir(), 'AppData', 'Local', 'Android', 'Sdk', 'platform-tools', 'adb.exe'),
64
+ ] : [
65
+ path.join(os.homedir(), 'Android', 'Sdk', 'platform-tools', 'adb'),
66
+ path.join(os.homedir(), 'Library', 'Android', 'sdk', 'platform-tools', 'adb'),
67
+ '/opt/android-sdk/platform-tools/adb',
68
+ ];
69
+ for (const p of commonPaths) {
70
+ if (fs.existsSync(p)) {
71
+ console.log(`[ADB] Found at: ${p}`);
72
+ return p;
73
+ }
74
+ }
75
+ // Try PATH
76
+ try {
77
+ const result = (0, child_process_1.execSync)(isWindows ? 'where adb' : 'which adb', { encoding: 'utf8' });
78
+ const adbPath = result.trim().split('\n')[0];
79
+ if (fs.existsSync(adbPath)) {
80
+ console.log(`[ADB] Found in PATH: ${adbPath}`);
81
+ return adbPath;
82
+ }
83
+ }
84
+ catch {
85
+ // Not in PATH
86
+ }
87
+ console.warn('[ADB] Not found. Auto-install disabled.');
88
+ return null;
89
+ }
90
+ /**
91
+ * Get list of connected devices (FULLY READY devices only)
92
+ * Returns only devices in "device" state (connected and authorized)
93
+ */
94
+ getDevices() {
95
+ if (!this.adbPath)
96
+ return [];
97
+ try {
98
+ const output = (0, child_process_1.execSync)(`"${this.adbPath}" devices`, { encoding: 'utf8' });
99
+ const lines = output.trim().split('\n').slice(1); // Skip header
100
+ return lines
101
+ .filter(line => line.includes('\tdevice'))
102
+ .map(line => line.split('\t')[0]);
103
+ }
104
+ catch (err) {
105
+ console.error('[ADB] Failed to get devices:', err);
106
+ return [];
107
+ }
108
+ }
109
+ /**
110
+ * Get ALL devices including those in "connecting" or "offline" state
111
+ * Useful for debugging and understanding device availability
112
+ */
113
+ getAllDeviceStates() {
114
+ if (!this.adbPath)
115
+ return [];
116
+ try {
117
+ const output = (0, child_process_1.execSync)(`"${this.adbPath}" devices`, { encoding: 'utf8' });
118
+ const lines = output.trim().split('\n').slice(1); // Skip header
119
+ return lines
120
+ .filter(line => line.trim().length > 0)
121
+ .map(line => {
122
+ const parts = line.split(/\s+/);
123
+ return { id: parts[0], state: parts[1] || 'unknown' };
124
+ });
125
+ }
126
+ catch (err) {
127
+ console.error('[ADB] Failed to get device states:', err);
128
+ return [];
129
+ }
130
+ }
131
+ /**
132
+ * Install APK on a device
133
+ */
134
+ async installApk(apkPath, deviceId) {
135
+ if (!this.adbPath) {
136
+ return { success: false, error: 'ADB not found' };
137
+ }
138
+ if (!fs.existsSync(apkPath)) {
139
+ return { success: false, error: `APK not found: ${apkPath}` };
140
+ }
141
+ const devices = this.getDevices();
142
+ if (devices.length === 0) {
143
+ return { success: false, error: 'No devices connected' };
144
+ }
145
+ const target = deviceId || devices[0];
146
+ console.log(`[ADB] Installing APK on device: ${target}`);
147
+ return new Promise((resolve) => {
148
+ const args = ['-s', target, 'install', '-r', apkPath];
149
+ const proc = (0, child_process_1.spawn)(this.adbPath, args, { shell: true });
150
+ let output = '';
151
+ let errorOutput = '';
152
+ proc.stdout.on('data', (data) => {
153
+ output += data.toString();
154
+ console.log(`[ADB] ${data.toString().trim()}`);
155
+ });
156
+ proc.stderr.on('data', (data) => {
157
+ errorOutput += data.toString();
158
+ console.error(`[ADB] ${data.toString().trim()}`);
159
+ });
160
+ proc.on('close', (code) => {
161
+ if (code === 0 && output.includes('Success')) {
162
+ console.log('[ADB] ✅ APK installed successfully!');
163
+ resolve({ success: true });
164
+ }
165
+ else {
166
+ resolve({ success: false, error: errorOutput || output || `Exit code: ${code}` });
167
+ }
168
+ });
169
+ proc.on('error', (err) => {
170
+ resolve({ success: false, error: err.message });
171
+ });
172
+ });
173
+ }
174
+ /**
175
+ * Launch app on device
176
+ */
177
+ async launchApp(packageName, activityName, deviceId) {
178
+ if (!this.adbPath)
179
+ return false;
180
+ const devices = this.getDevices();
181
+ if (devices.length === 0)
182
+ return false;
183
+ const target = deviceId || devices[0];
184
+ try {
185
+ (0, child_process_1.execSync)(`"${this.adbPath}" -s ${target} shell am start -n ${packageName}/${activityName}`, { encoding: 'utf8' });
186
+ console.log(`[ADB] ✅ Launched ${packageName}`);
187
+ return true;
188
+ }
189
+ catch (err) {
190
+ console.error('[ADB] Failed to launch app:', err);
191
+ return false;
192
+ }
193
+ }
194
+ /**
195
+ * Connect to a device via wireless ADB with retry logic
196
+ * Called when the JetStart app connects via WebSocket
197
+ *
198
+ * Handles timing issues with wireless ADB:
199
+ * - Devices may need time for user approval
200
+ * - Network handshake can be slow
201
+ * - Retries automatically if device not ready
202
+ */
203
+ connectWireless(ipAddress, retryCount = 0) {
204
+ if (!this.adbPath) {
205
+ console.warn('[ADB] ADB not found, cannot connect wireless device');
206
+ return;
207
+ }
208
+ const target = `${ipAddress}:5555`;
209
+ const maxRetries = 5;
210
+ const retryDelays = [0, 1000, 2000, 3000, 5000]; // Escalating delays
211
+ try {
212
+ // console.log(`[ADB] Attempting wireless connection to ${target}...${retryCount > 0 ? ` (retry ${retryCount}/${maxRetries})` : ''}`);
213
+ // Use longer timeout: 15 seconds for wireless ADB handshake
214
+ // This allows time for:
215
+ // - User approval on device
216
+ // - Network handshake
217
+ // - ADB daemon initialization
218
+ (0, child_process_1.execSync)(`"${this.adbPath}" connect ${target}`, {
219
+ encoding: 'utf8',
220
+ timeout: 15000,
221
+ stdio: ['pipe', 'pipe', 'pipe']
222
+ });
223
+ // CRITICAL: After connect, device needs time to reach "device" state
224
+ // Poll for device state readiness
225
+ this.waitForDeviceReady(target, retryCount, maxRetries, retryDelays);
226
+ }
227
+ catch (err) {
228
+ // Handle timeout or connection errors with retry
229
+ if (retryCount < maxRetries) {
230
+ const delay = retryDelays[retryCount + 1] || 5000;
231
+ console.warn(`[ADB] Connection failed: ${err.message}`);
232
+ console.log(`[ADB] Retrying in ${delay}ms... (attempt ${retryCount + 1}/${maxRetries})`);
233
+ setTimeout(() => this.connectWireless(ipAddress, retryCount + 1), delay);
234
+ }
235
+ else {
236
+ console.error(`[ADB] Failed to connect ${target} after ${maxRetries} retries: ${err.message}`);
237
+ console.warn(`[ADB] Device may need user authorization on the phone. Check your device!`);
238
+ }
239
+ }
240
+ }
241
+ /**
242
+ * Wait for a device to reach "device" state after adb connect
243
+ * The device may be "connecting" or "offline" initially
244
+ */
245
+ waitForDeviceReady(target, connectRetryCount, maxConnectRetries, connectRetryDelays) {
246
+ const maxWaitAttempts = 10;
247
+ const waitInterval = 500; // Check every 500ms
248
+ const checkDeviceState = (attemptNum = 0) => {
249
+ if (attemptNum > maxWaitAttempts) {
250
+ console.warn(`[ADB] Device ${target} not ready after ${maxWaitAttempts * waitInterval}ms, will retry on next build`);
251
+ return;
252
+ }
253
+ const allDevices = this.getAllDeviceStates();
254
+ const device = allDevices.find(d => d.id === target);
255
+ if (device?.state === 'device') {
256
+ // ✅ Device is ready!
257
+ console.log(`[ADB] ✅ Wireless ADB connected and ready: ${target}`);
258
+ this.connectedDevices.set(target, { lastConnected: Date.now(), retryCount: 0 });
259
+ }
260
+ else if (device?.state === 'connecting' || device?.state === 'offline' || device?.state === 'unknown') {
261
+ // Device is still connecting, check again later
262
+ console.log(`[ADB] Device state: ${device?.state || 'not found'}, waiting...`);
263
+ setTimeout(() => checkDeviceState(attemptNum + 1), waitInterval);
264
+ }
265
+ else if (!device) {
266
+ // Device not found yet, retry connection
267
+ if (connectRetryCount < maxConnectRetries) {
268
+ const delay = connectRetryDelays[connectRetryCount + 1] || 5000;
269
+ setTimeout(() => this.connectWireless(target.split(':')[0], connectRetryCount + 1), delay);
270
+ }
271
+ }
272
+ };
273
+ // Start polling for device readiness
274
+ setTimeout(() => checkDeviceState(), 100);
275
+ }
276
+ }
277
+ exports.AdbHelper = AdbHelper;
46
278
  class GradleExecutor {
47
279
  javaHome;
48
280
  androidHome;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Hot Reload Service
3
+ * Orchestrates Kotlin compilation, DEX generation, and sending to app
4
+ */
5
+ export interface HotReloadResult {
6
+ success: boolean;
7
+ dexBase64: string | null;
8
+ classNames: string[];
9
+ errors: string[];
10
+ compileTime: number;
11
+ dexTime: number;
12
+ }
13
+ export declare class HotReloadService {
14
+ private kotlinCompiler;
15
+ private dexGenerator;
16
+ private overrideGenerator;
17
+ private projectPath;
18
+ constructor(projectPath: string);
19
+ /**
20
+ * Perform hot reload for a changed Kotlin file
21
+ * Returns DEX bytes ready to be sent to the app
22
+ */
23
+ hotReload(filePath: string): Promise<HotReloadResult>;
24
+ /**
25
+ * Extract fully qualified class names from class file paths
26
+ */
27
+ private extractClassNames;
28
+ /**
29
+ * Check if the environment is properly set up for hot reload
30
+ */
31
+ checkEnvironment(): Promise<{
32
+ ready: boolean;
33
+ issues: string[];
34
+ }>;
35
+ }
36
+ //# sourceMappingURL=hot-reload-service.d.ts.map
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ /**
3
+ * Hot Reload Service
4
+ * Orchestrates Kotlin compilation, DEX generation, and sending to app
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.HotReloadService = void 0;
41
+ const path = __importStar(require("path"));
42
+ const fs = __importStar(require("fs"));
43
+ const os = __importStar(require("os"));
44
+ const kotlin_compiler_1 = require("./kotlin-compiler");
45
+ const dex_generator_1 = require("./dex-generator");
46
+ const override_generator_1 = require("./override-generator");
47
+ const logger_1 = require("../utils/logger");
48
+ class HotReloadService {
49
+ kotlinCompiler;
50
+ dexGenerator;
51
+ overrideGenerator;
52
+ projectPath;
53
+ constructor(projectPath) {
54
+ this.projectPath = projectPath;
55
+ this.kotlinCompiler = new kotlin_compiler_1.KotlinCompiler(projectPath);
56
+ this.dexGenerator = new dex_generator_1.DexGenerator();
57
+ this.overrideGenerator = new override_generator_1.OverrideGenerator();
58
+ }
59
+ /**
60
+ * Perform hot reload for a changed Kotlin file
61
+ * Returns DEX bytes ready to be sent to the app
62
+ */
63
+ async hotReload(filePath) {
64
+ const startTime = Date.now();
65
+ (0, logger_1.log)(`🔥 Hot reload starting for: ${path.basename(filePath)}`);
66
+ // Step 1: Compile Kotlin to .class
67
+ const compileStart = Date.now();
68
+ const compileResult = await this.kotlinCompiler.compileFile(filePath);
69
+ const compileTime = Date.now() - compileStart;
70
+ if (!compileResult.success) {
71
+ (0, logger_1.error)(`Compilation failed: ${compileResult.errors.join(', ')}`);
72
+ return {
73
+ success: false,
74
+ dexBase64: null,
75
+ classNames: [],
76
+ errors: compileResult.errors,
77
+ compileTime,
78
+ dexTime: 0
79
+ };
80
+ }
81
+ (0, logger_1.log)(`Compilation completed in ${compileTime}ms (${compileResult.classFiles.length} classes)`);
82
+ // Step 2: Generate $Override classes (Phase 2)
83
+ const overrideDir = path.join(os.tmpdir(), 'jetstart-overrides', Date.now().toString());
84
+ fs.mkdirSync(overrideDir, { recursive: true });
85
+ const overrideResult = await this.overrideGenerator.generateOverrides(compileResult.classFiles, filePath, overrideDir);
86
+ if (!overrideResult.success) {
87
+ (0, logger_1.log)(`⚠️ Override generation failed: ${overrideResult.errors.join(', ')}`);
88
+ (0, logger_1.log)(`📝 Falling back to direct class hot reload (less efficient)`);
89
+ }
90
+ else {
91
+ (0, logger_1.log)(`Generated ${overrideResult.overrideClassFiles.length} override classes`);
92
+ // Compile override source files to .class
93
+ const allOverrideClassFiles = [];
94
+ for (const overrideFile of overrideResult.overrideClassFiles) {
95
+ const compRes = await this.kotlinCompiler.compileFile(overrideFile);
96
+ if (compRes.success) {
97
+ allOverrideClassFiles.push(...compRes.classFiles);
98
+ }
99
+ else {
100
+ (0, logger_1.log)(`⚠️ Failed to compile override ${path.basename(overrideFile)}: ${compRes.errors.join(', ')}`);
101
+ }
102
+ }
103
+ if (allOverrideClassFiles.length > 0) {
104
+ (0, logger_1.log)(`Compiled ${allOverrideClassFiles.length} override classes`);
105
+ // Add override classes to DEX generation
106
+ compileResult.classFiles.push(...allOverrideClassFiles);
107
+ }
108
+ }
109
+ // Step 3: Convert .class to .dex
110
+ const dexStart = Date.now();
111
+ const dexResult = await this.dexGenerator.generateDex(compileResult.classFiles);
112
+ const dexTime = Date.now() - dexStart;
113
+ if (!dexResult.success || !dexResult.dexBytes) {
114
+ (0, logger_1.error)(`DEX generation failed: ${dexResult.errors.join(', ')}`);
115
+ return {
116
+ success: false,
117
+ dexBase64: null,
118
+ classNames: [],
119
+ errors: dexResult.errors,
120
+ compileTime,
121
+ dexTime
122
+ };
123
+ }
124
+ (0, logger_1.log)(`DEX generated in ${dexTime}ms (${dexResult.dexBytes.length} bytes)`);
125
+ // Extract class names from file paths
126
+ const classNames = this.extractClassNames(compileResult.classFiles, compileResult.outputDir);
127
+ const totalTime = Date.now() - startTime;
128
+ (0, logger_1.success)(`🔥 Hot reload complete in ${totalTime}ms (compile: ${compileTime}ms, dex: ${dexTime}ms)`);
129
+ return {
130
+ success: true,
131
+ dexBase64: dexResult.dexBytes.toString('base64'),
132
+ classNames,
133
+ errors: [],
134
+ compileTime,
135
+ dexTime
136
+ };
137
+ }
138
+ /**
139
+ * Extract fully qualified class names from class file paths
140
+ */
141
+ extractClassNames(classFiles, outputDir) {
142
+ return classFiles.map(classFile => {
143
+ // Remove output dir prefix and .class suffix
144
+ let relativePath = classFile
145
+ .replace(outputDir, '')
146
+ .replace(/^[\/\\]/, '')
147
+ .replace('.class', '');
148
+ // Convert path separators to dots
149
+ return relativePath.replace(/[\/\\]/g, '.');
150
+ });
151
+ }
152
+ /**
153
+ * Check if the environment is properly set up for hot reload
154
+ */
155
+ async checkEnvironment() {
156
+ const issues = [];
157
+ // Check kotlinc
158
+ const kotlinc = await this.kotlinCompiler.findKotlinc();
159
+ if (!kotlinc) {
160
+ issues.push('kotlinc not found - install Kotlin or set KOTLIN_HOME');
161
+ }
162
+ // Check d8
163
+ const d8 = await this.dexGenerator.findD8();
164
+ if (!d8) {
165
+ issues.push('d8 not found - set ANDROID_HOME and install build-tools');
166
+ }
167
+ // Check classpath
168
+ const classpath = await this.kotlinCompiler.buildClasspath();
169
+ if (classpath.length === 0) {
170
+ issues.push('Cannot build classpath - ANDROID_HOME not set or SDK not installed');
171
+ }
172
+ return {
173
+ ready: issues.length === 0,
174
+ issues
175
+ };
176
+ }
177
+ }
178
+ exports.HotReloadService = HotReloadService;
179
+ //# sourceMappingURL=hot-reload-service.js.map
@@ -0,0 +1,61 @@
1
+ /**
2
+ * JsCompilerService
3
+ * Compiles Kotlin Compose source to browser-executable ES modules via kotlinc-js.
4
+ *
5
+ * Pipeline (two steps required by K2 compiler):
6
+ * 1. user.kt → screen.klib (compile)
7
+ * 2. screen.klib → screen.mjs (link, includes stdlib + stubs)
8
+ *
9
+ * The resulting .mjs exports renderScreen() which builds a plain JS object tree.
10
+ * The browser imports it, calls renderScreen(() => ScreenName()), renders tree as HTML.
11
+ */
12
+ export interface JsCompileResult {
13
+ success: boolean;
14
+ jsBase64?: string;
15
+ byteSize?: number;
16
+ compileTimeMs?: number;
17
+ screenFunctionName?: string;
18
+ error?: string;
19
+ }
20
+ export declare class JsCompilerService {
21
+ private kotlincJsPath;
22
+ private stdlibKlib;
23
+ private stubsKlib;
24
+ private readonly workDir;
25
+ constructor();
26
+ private init;
27
+ isAvailable(): boolean;
28
+ private writeStubsSource;
29
+ /** Build the Compose shims klib once. Returns klib path or null. */
30
+ private ensureStubsKlib;
31
+ /**
32
+ * Compile a .kt Compose file to a browser-runnable ES module.
33
+ * Returns base64-encoded .mjs content.
34
+ */
35
+ /**
36
+ * Remove horizontalArrangement = ... lines that appear inside non-Row containers.
37
+ * LazyVerticalStaggeredGrid etc. don't accept this param in our stubs.
38
+ * Row/LazyRow DO accept it — those lines are kept.
39
+ */
40
+ private removeHorizontalArrangementOutsideRow;
41
+ /**
42
+ * Remove a brace-balanced block (including optional trailing else block).
43
+ * Used to surgically strip LaunchedEffect, forEach, broken if-else blocks etc.
44
+ */
45
+ private removeBalancedBlock;
46
+ /**
47
+ * Remove "} else { BLOCK }" where the else body matches a predicate.
48
+ */
49
+ private removeElseBlockIf;
50
+ /**
51
+ * Preprocess a Kotlin Compose source file for kotlinc-js compilation.
52
+ *
53
+ * The user's file uses Android/Compose/Java imports that don't exist in
54
+ * a browser context. This method transforms the file so that only the
55
+ * Compose UI structure remains — which maps directly to our jetstart.compose
56
+ * shims. The result compiles cleanly with kotlinc-js.
57
+ */
58
+ private preprocessFile;
59
+ compile(ktFilePath: string): Promise<JsCompileResult>;
60
+ }
61
+ //# sourceMappingURL=js-compiler-service.d.ts.map