@jetstart/core 1.7.0 → 2.0.1
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/README.md +189 -74
- package/dist/build/dex-generator.d.ts +27 -0
- package/dist/build/dex-generator.js +202 -0
- package/dist/build/dsl-parser.d.ts +3 -30
- package/dist/build/dsl-parser.js +67 -240
- package/dist/build/dsl-types.d.ts +8 -0
- package/dist/build/gradle.d.ts +51 -0
- package/dist/build/gradle.js +233 -1
- package/dist/build/hot-reload-service.d.ts +36 -0
- package/dist/build/hot-reload-service.js +179 -0
- package/dist/build/js-compiler-service.d.ts +61 -0
- package/dist/build/js-compiler-service.js +421 -0
- package/dist/build/kotlin-compiler.d.ts +54 -0
- package/dist/build/kotlin-compiler.js +450 -0
- package/dist/build/kotlin-parser.d.ts +91 -0
- package/dist/build/kotlin-parser.js +1030 -0
- package/dist/build/override-generator.d.ts +54 -0
- package/dist/build/override-generator.js +430 -0
- package/dist/server/index.d.ts +16 -1
- package/dist/server/index.js +147 -42
- package/dist/websocket/handler.d.ts +20 -4
- package/dist/websocket/handler.js +73 -38
- package/dist/websocket/index.d.ts +8 -0
- package/dist/websocket/index.js +15 -11
- package/dist/websocket/manager.d.ts +2 -2
- package/dist/websocket/manager.js +1 -1
- package/package.json +3 -3
- package/src/build/dex-generator.ts +197 -0
- package/src/build/dsl-parser.ts +73 -272
- package/src/build/dsl-types.ts +9 -0
- package/src/build/gradle.ts +259 -1
- package/src/build/hot-reload-service.ts +178 -0
- package/src/build/js-compiler-service.ts +411 -0
- package/src/build/kotlin-compiler.ts +460 -0
- package/src/build/kotlin-parser.ts +1043 -0
- package/src/build/override-generator.ts +478 -0
- package/src/server/index.ts +162 -54
- package/src/websocket/handler.ts +94 -56
- package/src/websocket/index.ts +27 -14
- package/src/websocket/manager.ts +2 -2
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Override Generator
|
|
3
|
+
* Generates $override classes that implement IncrementalChange interface.
|
|
4
|
+
* These classes contain the new method implementations and route calls via access$dispatch.
|
|
5
|
+
*/
|
|
6
|
+
export interface OverrideGeneratorResult {
|
|
7
|
+
success: boolean;
|
|
8
|
+
overrideClassFiles: string[];
|
|
9
|
+
errors: string[];
|
|
10
|
+
}
|
|
11
|
+
export declare class OverrideGenerator {
|
|
12
|
+
private static readonly TAG;
|
|
13
|
+
/**
|
|
14
|
+
* Generate $override classes for all compiled class files.
|
|
15
|
+
* The override classes implement IncrementalChange and contain the new method implementations.
|
|
16
|
+
*
|
|
17
|
+
* Strategy: Instead of complex bytecode manipulation, we generate Kotlin source code
|
|
18
|
+
* for the $Override classes and compile them. This is simpler and more maintainable.
|
|
19
|
+
*/
|
|
20
|
+
generateOverrides(classFiles: string[], sourceFile: string, outputDir: string): Promise<OverrideGeneratorResult>;
|
|
21
|
+
/**
|
|
22
|
+
* Parse Kotlin source file to extract class and method information
|
|
23
|
+
*/
|
|
24
|
+
private parseKotlinSource;
|
|
25
|
+
/**
|
|
26
|
+
* Parse methods from a class body
|
|
27
|
+
*/
|
|
28
|
+
private parseMethodsFromClassBody;
|
|
29
|
+
/**
|
|
30
|
+
* Parse top-level functions (not inside a class)
|
|
31
|
+
*/
|
|
32
|
+
private parseTopLevelFunctions;
|
|
33
|
+
/**
|
|
34
|
+
* Parse parameter string into typed parameters
|
|
35
|
+
*/
|
|
36
|
+
private parseParameters;
|
|
37
|
+
/**
|
|
38
|
+
* Parse a single parameter definition
|
|
39
|
+
*/
|
|
40
|
+
private parseParameter;
|
|
41
|
+
/**
|
|
42
|
+
* Generate a method signature string for dispatch routing
|
|
43
|
+
*/
|
|
44
|
+
private generateMethodSignature;
|
|
45
|
+
/**
|
|
46
|
+
* Convert Kotlin type to JVM descriptor-style string
|
|
47
|
+
*/
|
|
48
|
+
private typeToDescriptor;
|
|
49
|
+
/**
|
|
50
|
+
* Generate Kotlin source code for the $override class
|
|
51
|
+
*/
|
|
52
|
+
private generateOverrideSource;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=override-generator.d.ts.map
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Override Generator
|
|
4
|
+
* Generates $override classes that implement IncrementalChange interface.
|
|
5
|
+
* These classes contain the new method implementations and route calls via access$dispatch.
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.OverrideGenerator = void 0;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const logger_1 = require("../utils/logger");
|
|
45
|
+
class OverrideGenerator {
|
|
46
|
+
static TAG = 'OverrideGenerator';
|
|
47
|
+
/**
|
|
48
|
+
* Generate $override classes for all compiled class files.
|
|
49
|
+
* The override classes implement IncrementalChange and contain the new method implementations.
|
|
50
|
+
*
|
|
51
|
+
* Strategy: Instead of complex bytecode manipulation, we generate Kotlin source code
|
|
52
|
+
* for the $Override classes and compile them. This is simpler and more maintainable.
|
|
53
|
+
*/
|
|
54
|
+
async generateOverrides(classFiles, sourceFile, outputDir) {
|
|
55
|
+
const overrideClassFiles = [];
|
|
56
|
+
const errors = [];
|
|
57
|
+
try {
|
|
58
|
+
// Read the original Kotlin source to understand method signatures
|
|
59
|
+
const sourceContent = fs.readFileSync(sourceFile, 'utf-8');
|
|
60
|
+
// Parse class and method information from source
|
|
61
|
+
const classInfo = this.parseKotlinSource(sourceContent, sourceFile);
|
|
62
|
+
if (classInfo.length === 0) {
|
|
63
|
+
// No classes found - this is normal for files with only @Composable functions
|
|
64
|
+
// Return success with 0 overrides and let the fallback handle it
|
|
65
|
+
(0, logger_1.log)(`ℹ️ No classes found in ${sourceFile} - using direct class hot reload`);
|
|
66
|
+
return { success: true, overrideClassFiles: [], errors: [] };
|
|
67
|
+
}
|
|
68
|
+
// Generate override class source for each class
|
|
69
|
+
for (const info of classInfo) {
|
|
70
|
+
const overrideSource = this.generateOverrideSource(info);
|
|
71
|
+
const overrideSourcePath = path.join(outputDir, `${info.className}\$override.kt`);
|
|
72
|
+
fs.writeFileSync(overrideSourcePath, overrideSource);
|
|
73
|
+
(0, logger_1.log)(`Generated override source: ${info.className}$override.kt`);
|
|
74
|
+
// Track the generated source file
|
|
75
|
+
overrideClassFiles.push(overrideSourcePath);
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
success: true,
|
|
79
|
+
overrideClassFiles,
|
|
80
|
+
errors: []
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
const errorMsg = e instanceof Error ? e.message : String(e);
|
|
85
|
+
errors.push(errorMsg);
|
|
86
|
+
return { success: false, overrideClassFiles: [], errors };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Parse Kotlin source file to extract class and method information
|
|
91
|
+
*/
|
|
92
|
+
parseKotlinSource(source, filePath) {
|
|
93
|
+
const classes = [];
|
|
94
|
+
// Extract package name
|
|
95
|
+
const packageMatch = source.match(/^package\s+([\w.]+)/m);
|
|
96
|
+
const packageName = packageMatch ? packageMatch[1] : '';
|
|
97
|
+
// Simple regex-based parsing for class definitions
|
|
98
|
+
// This handles basic cases - complex nested classes may need more sophisticated parsing
|
|
99
|
+
const classRegex = /(?:class|object)\s+(\w+)(?:\s*:\s*[\w\s,<>]+)?\s*\{/g;
|
|
100
|
+
let classMatch;
|
|
101
|
+
while ((classMatch = classRegex.exec(source)) !== null) {
|
|
102
|
+
const className = classMatch[1];
|
|
103
|
+
const classStartIndex = classMatch.index;
|
|
104
|
+
// Find matching closing brace
|
|
105
|
+
let braceCount = 0;
|
|
106
|
+
let classEndIndex = classStartIndex;
|
|
107
|
+
let inString = false;
|
|
108
|
+
let stringChar = '';
|
|
109
|
+
for (let i = classStartIndex; i < source.length; i++) {
|
|
110
|
+
const char = source[i];
|
|
111
|
+
const prevChar = i > 0 ? source[i - 1] : '';
|
|
112
|
+
// Handle string literals
|
|
113
|
+
if ((char === '"' || char === '\'') && prevChar !== '\\') {
|
|
114
|
+
if (!inString) {
|
|
115
|
+
inString = true;
|
|
116
|
+
stringChar = char;
|
|
117
|
+
}
|
|
118
|
+
else if (char === stringChar) {
|
|
119
|
+
inString = false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (!inString) {
|
|
123
|
+
if (char === '{')
|
|
124
|
+
braceCount++;
|
|
125
|
+
if (char === '}') {
|
|
126
|
+
braceCount--;
|
|
127
|
+
if (braceCount === 0) {
|
|
128
|
+
classEndIndex = i;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const classBody = source.substring(classStartIndex, classEndIndex + 1);
|
|
135
|
+
const methods = this.parseMethodsFromClassBody(classBody, className);
|
|
136
|
+
classes.push({
|
|
137
|
+
packageName,
|
|
138
|
+
className,
|
|
139
|
+
fullClassName: packageName ? `${packageName}.${className}` : className,
|
|
140
|
+
methods
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// Also handle top-level functions (they go in FileNameKt class)
|
|
144
|
+
const topLevelMethods = this.parseTopLevelFunctions(source, filePath);
|
|
145
|
+
if (topLevelMethods.length > 0) {
|
|
146
|
+
const fileName = path.basename(filePath, '.kt');
|
|
147
|
+
const ktClassName = fileName.charAt(0).toUpperCase() + fileName.slice(1) + 'Kt';
|
|
148
|
+
classes.push({
|
|
149
|
+
packageName,
|
|
150
|
+
className: ktClassName,
|
|
151
|
+
fullClassName: packageName ? `${packageName}.${ktClassName}` : ktClassName,
|
|
152
|
+
methods: topLevelMethods
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return classes;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Parse methods from a class body
|
|
159
|
+
*/
|
|
160
|
+
parseMethodsFromClassBody(classBody, className) {
|
|
161
|
+
const methods = [];
|
|
162
|
+
// Match function definitions
|
|
163
|
+
// This regex handles: fun name(params): ReturnType
|
|
164
|
+
const funRegex = /fun\s+(\w+)\s*\(([^)]*)\)(?:\s*:\s*([\w<>?,\s]+))?\s*[{=]/g;
|
|
165
|
+
let funMatch;
|
|
166
|
+
while ((funMatch = funRegex.exec(classBody)) !== null) {
|
|
167
|
+
const methodName = funMatch[1];
|
|
168
|
+
const paramsStr = funMatch[2];
|
|
169
|
+
const returnType = funMatch[3]?.trim() || 'Unit';
|
|
170
|
+
// Parse parameters
|
|
171
|
+
const params = this.parseParameters(paramsStr);
|
|
172
|
+
// Generate method signature for dispatch
|
|
173
|
+
const signature = this.generateMethodSignature(methodName, params, returnType);
|
|
174
|
+
methods.push({
|
|
175
|
+
name: methodName,
|
|
176
|
+
parameters: params,
|
|
177
|
+
returnType,
|
|
178
|
+
signature,
|
|
179
|
+
isStatic: false // Assume instance method, TODO: detect companion object
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
return methods;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Parse top-level functions (not inside a class)
|
|
186
|
+
*/
|
|
187
|
+
parseTopLevelFunctions(source, filePath) {
|
|
188
|
+
const methods = [];
|
|
189
|
+
// Remove class bodies first to get only top-level content
|
|
190
|
+
let topLevelContent = source;
|
|
191
|
+
// Remove all class/object bodies
|
|
192
|
+
const classRegex = /(?:class|object)\s+\w+[^{]*\{/g;
|
|
193
|
+
let match;
|
|
194
|
+
const classPositions = [];
|
|
195
|
+
while ((match = classRegex.exec(source)) !== null) {
|
|
196
|
+
const startIndex = match.index;
|
|
197
|
+
let braceCount = 0;
|
|
198
|
+
let endIndex = startIndex;
|
|
199
|
+
let inString = false;
|
|
200
|
+
let stringChar = '';
|
|
201
|
+
for (let i = startIndex; i < source.length; i++) {
|
|
202
|
+
const char = source[i];
|
|
203
|
+
const prevChar = i > 0 ? source[i - 1] : '';
|
|
204
|
+
if ((char === '"' || char === '\'') && prevChar !== '\\') {
|
|
205
|
+
if (!inString) {
|
|
206
|
+
inString = true;
|
|
207
|
+
stringChar = char;
|
|
208
|
+
}
|
|
209
|
+
else if (char === stringChar) {
|
|
210
|
+
inString = false;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (!inString) {
|
|
214
|
+
if (char === '{')
|
|
215
|
+
braceCount++;
|
|
216
|
+
if (char === '}') {
|
|
217
|
+
braceCount--;
|
|
218
|
+
if (braceCount === 0) {
|
|
219
|
+
endIndex = i;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
classPositions.push({ start: startIndex, end: endIndex + 1 });
|
|
226
|
+
}
|
|
227
|
+
// Sort and remove class bodies from end to start to maintain indices
|
|
228
|
+
classPositions.sort((a, b) => b.start - a.start);
|
|
229
|
+
for (const pos of classPositions) {
|
|
230
|
+
topLevelContent = topLevelContent.substring(0, pos.start) + topLevelContent.substring(pos.end);
|
|
231
|
+
}
|
|
232
|
+
// Now parse functions from top-level content
|
|
233
|
+
const funRegex = /fun\s+(\w+)\s*\(([^)]*)\)(?:\s*:\s*([\w<>?,\s]+))?\s*[{=]/g;
|
|
234
|
+
let funMatch;
|
|
235
|
+
while ((funMatch = funRegex.exec(topLevelContent)) !== null) {
|
|
236
|
+
const methodName = funMatch[1];
|
|
237
|
+
const paramsStr = funMatch[2];
|
|
238
|
+
const returnType = funMatch[3]?.trim() || 'Unit';
|
|
239
|
+
const params = this.parseParameters(paramsStr);
|
|
240
|
+
const signature = this.generateMethodSignature(methodName, params, returnType);
|
|
241
|
+
methods.push({
|
|
242
|
+
name: methodName,
|
|
243
|
+
parameters: params,
|
|
244
|
+
returnType,
|
|
245
|
+
signature,
|
|
246
|
+
isStatic: true // Top-level functions are static
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
return methods;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Parse parameter string into typed parameters
|
|
253
|
+
*/
|
|
254
|
+
parseParameters(paramsStr) {
|
|
255
|
+
if (!paramsStr.trim())
|
|
256
|
+
return [];
|
|
257
|
+
const params = [];
|
|
258
|
+
// Split by comma, but respect generics
|
|
259
|
+
let depth = 0;
|
|
260
|
+
let current = '';
|
|
261
|
+
for (const char of paramsStr) {
|
|
262
|
+
if (char === '<' || char === '(')
|
|
263
|
+
depth++;
|
|
264
|
+
if (char === '>' || char === ')')
|
|
265
|
+
depth--;
|
|
266
|
+
if (char === ',' && depth === 0) {
|
|
267
|
+
if (current.trim()) {
|
|
268
|
+
const param = this.parseParameter(current.trim());
|
|
269
|
+
if (param)
|
|
270
|
+
params.push(param);
|
|
271
|
+
}
|
|
272
|
+
current = '';
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
current += char;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (current.trim()) {
|
|
279
|
+
const param = this.parseParameter(current.trim());
|
|
280
|
+
if (param)
|
|
281
|
+
params.push(param);
|
|
282
|
+
}
|
|
283
|
+
return params;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Parse a single parameter definition
|
|
287
|
+
*/
|
|
288
|
+
parseParameter(paramStr) {
|
|
289
|
+
// Handle "name: Type" or "name: Type = default"
|
|
290
|
+
const match = paramStr.match(/(\w+)\s*:\s*([\w<>?,.\s]+?)(?:\s*=.*)?$/);
|
|
291
|
+
if (!match)
|
|
292
|
+
return null;
|
|
293
|
+
return {
|
|
294
|
+
name: match[1],
|
|
295
|
+
type: match[2].trim()
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Generate a method signature string for dispatch routing
|
|
300
|
+
*/
|
|
301
|
+
generateMethodSignature(methodName, params, returnType) {
|
|
302
|
+
// Format: methodName.(paramTypes)returnType
|
|
303
|
+
// Using JVM-style descriptors
|
|
304
|
+
const paramDescriptors = params.map(p => this.typeToDescriptor(p.type)).join('');
|
|
305
|
+
const returnDescriptor = this.typeToDescriptor(returnType);
|
|
306
|
+
return `${methodName}.(${paramDescriptors})${returnDescriptor}`;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Convert Kotlin type to JVM descriptor-style string
|
|
310
|
+
*/
|
|
311
|
+
typeToDescriptor(type) {
|
|
312
|
+
// Simplified mapping - expand as needed
|
|
313
|
+
const typeMap = {
|
|
314
|
+
'Unit': 'V',
|
|
315
|
+
'Int': 'I',
|
|
316
|
+
'Long': 'J',
|
|
317
|
+
'Float': 'F',
|
|
318
|
+
'Double': 'D',
|
|
319
|
+
'Boolean': 'Z',
|
|
320
|
+
'Byte': 'B',
|
|
321
|
+
'Char': 'C',
|
|
322
|
+
'Short': 'S',
|
|
323
|
+
'String': 'Ljava/lang/String;',
|
|
324
|
+
'Any': 'Ljava/lang/Object;',
|
|
325
|
+
};
|
|
326
|
+
// Handle nullable types
|
|
327
|
+
const nonNullType = type.replace('?', '');
|
|
328
|
+
if (typeMap[nonNullType]) {
|
|
329
|
+
return typeMap[nonNullType];
|
|
330
|
+
}
|
|
331
|
+
// Handle generic types like List<String>
|
|
332
|
+
const genericMatch = nonNullType.match(/^(\w+)<.*>$/);
|
|
333
|
+
if (genericMatch) {
|
|
334
|
+
return `L${genericMatch[1]};`;
|
|
335
|
+
}
|
|
336
|
+
// Default to object type
|
|
337
|
+
return `L${nonNullType.replace('.', '/')};`;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Generate Kotlin source code for the $override class
|
|
341
|
+
*/
|
|
342
|
+
generateOverrideSource(classInfo) {
|
|
343
|
+
const { packageName, className, methods } = classInfo;
|
|
344
|
+
const lines = [];
|
|
345
|
+
// Package declaration
|
|
346
|
+
if (packageName) {
|
|
347
|
+
lines.push(`package ${packageName}`);
|
|
348
|
+
lines.push('');
|
|
349
|
+
}
|
|
350
|
+
// Import IncrementalChange
|
|
351
|
+
lines.push('import com.jetstart.hotreload.IncrementalChange');
|
|
352
|
+
lines.push('');
|
|
353
|
+
// Generate override class
|
|
354
|
+
lines.push(`/**`);
|
|
355
|
+
lines.push(` * Generated override class for ${className}`);
|
|
356
|
+
lines.push(` * Implements IncrementalChange to provide hot-reloaded method implementations`);
|
|
357
|
+
lines.push(` * `);
|
|
358
|
+
lines.push(` * Pattern: args[0] is 'this' for instance methods, method parameters follow`);
|
|
359
|
+
lines.push(` */`);
|
|
360
|
+
lines.push(`class ${className}\$override : IncrementalChange {`);
|
|
361
|
+
lines.push('');
|
|
362
|
+
// Generate access$dispatch method
|
|
363
|
+
lines.push(' override fun access\$dispatch(methodSignature: String, vararg args: Any?): Any? {');
|
|
364
|
+
lines.push(' return when (methodSignature) {');
|
|
365
|
+
for (const method of methods) {
|
|
366
|
+
const { name, parameters, returnType, signature, isStatic } = method;
|
|
367
|
+
// Generate case for this method
|
|
368
|
+
lines.push(` "${signature}" -> {`);
|
|
369
|
+
// For instance methods, cast args[0] to the instance type
|
|
370
|
+
if (!isStatic) {
|
|
371
|
+
lines.push(` val instance = args[0] as ${className}`);
|
|
372
|
+
}
|
|
373
|
+
// Cast arguments and call the method
|
|
374
|
+
if (parameters.length === 0) {
|
|
375
|
+
if (returnType === 'Unit') {
|
|
376
|
+
if (isStatic) {
|
|
377
|
+
lines.push(` ${className}.${name}()`);
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
lines.push(` instance.${name}()`);
|
|
381
|
+
}
|
|
382
|
+
lines.push(' null');
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
if (isStatic) {
|
|
386
|
+
lines.push(` ${className}.${name}()`);
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
lines.push(` instance.${name}()`);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
// Build argument list with casts
|
|
395
|
+
const argCasts = parameters.map((p, i) => {
|
|
396
|
+
// For instance methods: args[0] is 'this', method params start at args[1]
|
|
397
|
+
// For static methods: method params start at args[0]
|
|
398
|
+
const argIndex = isStatic ? i : i + 1;
|
|
399
|
+
return `args[${argIndex}] as ${p.type}`;
|
|
400
|
+
});
|
|
401
|
+
if (returnType === 'Unit') {
|
|
402
|
+
if (isStatic) {
|
|
403
|
+
lines.push(` ${className}.${name}(${argCasts.join(', ')})`);
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
lines.push(` instance.${name}(${argCasts.join(', ')})`);
|
|
407
|
+
}
|
|
408
|
+
lines.push(' null');
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
if (isStatic) {
|
|
412
|
+
lines.push(` ${className}.${name}(${argCasts.join(', ')})`);
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
lines.push(` instance.${name}(${argCasts.join(', ')})`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
lines.push(' }');
|
|
420
|
+
}
|
|
421
|
+
// Default case
|
|
422
|
+
lines.push(' else -> throw IllegalArgumentException("Unknown method: $methodSignature")');
|
|
423
|
+
lines.push(' }');
|
|
424
|
+
lines.push(' }');
|
|
425
|
+
lines.push('}');
|
|
426
|
+
return lines.join('\n');
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
exports.OverrideGenerator = OverrideGenerator;
|
|
430
|
+
//# sourceMappingURL=override-generator.js.map
|
package/dist/server/index.d.ts
CHANGED
|
@@ -9,6 +9,10 @@ export interface ServerConfig {
|
|
|
9
9
|
wsPort?: number;
|
|
10
10
|
host?: string;
|
|
11
11
|
displayHost?: string;
|
|
12
|
+
/** Override the URL injected into BuildConfig for emulator builds. Emulators reach the host at 10.0.2.2, not the local network IP. */
|
|
13
|
+
emulatorHost?: string;
|
|
14
|
+
/** Enable web emulator support (initializes kotlinc-js compiler). */
|
|
15
|
+
webEnabled?: boolean;
|
|
12
16
|
projectPath?: string;
|
|
13
17
|
projectName?: string;
|
|
14
18
|
}
|
|
@@ -20,9 +24,15 @@ export declare class JetStartServer extends EventEmitter {
|
|
|
20
24
|
private config;
|
|
21
25
|
private sessionManager;
|
|
22
26
|
private buildService;
|
|
27
|
+
private hotReloadService;
|
|
28
|
+
private jsCompiler;
|
|
23
29
|
private currentSession;
|
|
24
30
|
private buildMutex;
|
|
25
31
|
private latestApkPath;
|
|
32
|
+
private useTrueHotReload;
|
|
33
|
+
private adbHelper;
|
|
34
|
+
private autoInstall;
|
|
35
|
+
private isFileChangeBuild;
|
|
26
36
|
constructor(config?: ServerConfig);
|
|
27
37
|
start(): Promise<ServerSession>;
|
|
28
38
|
stop(): Promise<void>;
|
|
@@ -30,8 +40,13 @@ export declare class JetStartServer extends EventEmitter {
|
|
|
30
40
|
private setupBuildListeners;
|
|
31
41
|
private handleRebuild;
|
|
32
42
|
/**
|
|
33
|
-
* Handle UI file updates
|
|
43
|
+
* Handle UI file updates - uses TRUE hot reload (DEX-based) when available
|
|
34
44
|
*/
|
|
45
|
+
/**
|
|
46
|
+
* Compile a .kt file to a browser ES module and broadcast to web clients.
|
|
47
|
+
* Physical devices use DEX (already sent above). This targets browsers only.
|
|
48
|
+
*/
|
|
49
|
+
private sendJsPreview;
|
|
35
50
|
private handleUIUpdate;
|
|
36
51
|
}
|
|
37
52
|
//# sourceMappingURL=index.d.ts.map
|