@tmhs/mobile-mcp 0.7.0 → 0.10.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.
- package/dist/index.js +23 -1
- package/dist/index.js.map +1 -1
- package/dist/tools/addMap.d.ts +3 -0
- package/dist/tools/addMap.d.ts.map +1 -0
- package/dist/tools/addMap.js +223 -0
- package/dist/tools/addMap.js.map +1 -0
- package/dist/tools/checkOfflineReady.d.ts +3 -0
- package/dist/tools/checkOfflineReady.d.ts.map +1 -0
- package/dist/tools/checkOfflineReady.js +190 -0
- package/dist/tools/checkOfflineReady.js.map +1 -0
- package/dist/tools/generateForm.d.ts +3 -0
- package/dist/tools/generateForm.d.ts.map +1 -0
- package/dist/tools/generateForm.js +337 -0
- package/dist/tools/generateForm.js.map +1 -0
- package/dist/tools/generateTestFile.d.ts +3 -0
- package/dist/tools/generateTestFile.d.ts.map +1 -0
- package/dist/tools/generateTestFile.js +184 -0
- package/dist/tools/generateTestFile.js.map +1 -0
- package/dist/tools/profilePerformance.d.ts +3 -0
- package/dist/tools/profilePerformance.d.ts.map +1 -0
- package/dist/tools/profilePerformance.js +222 -0
- package/dist/tools/profilePerformance.js.map +1 -0
- package/dist/tools/runTests.d.ts +3 -0
- package/dist/tools/runTests.d.ts.map +1 -0
- package/dist/tools/runTests.js +165 -0
- package/dist/tools/runTests.js.map +1 -0
- package/dist/tools/securityAudit.d.ts +3 -0
- package/dist/tools/securityAudit.d.ts.map +1 -0
- package/dist/tools/securityAudit.js +213 -0
- package/dist/tools/securityAudit.js.map +1 -0
- package/dist/tools/setupCI.d.ts +3 -0
- package/dist/tools/setupCI.d.ts.map +1 -0
- package/dist/tools/setupCI.js +202 -0
- package/dist/tools/setupCI.js.map +1 -0
- package/dist/tools/setupI18n.d.ts +3 -0
- package/dist/tools/setupI18n.d.ts.map +1 -0
- package/dist/tools/setupI18n.js +155 -0
- package/dist/tools/setupI18n.js.map +1 -0
- package/dist/tools/setupMonitoring.d.ts +3 -0
- package/dist/tools/setupMonitoring.d.ts.map +1 -0
- package/dist/tools/setupMonitoring.js +250 -0
- package/dist/tools/setupMonitoring.js.map +1 -0
- package/dist/tools/setupRealtime.d.ts +3 -0
- package/dist/tools/setupRealtime.d.ts.map +1 -0
- package/dist/tools/setupRealtime.js +311 -0
- package/dist/tools/setupRealtime.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { textResponse, errorResponse } from "../types.js";
|
|
5
|
+
const fieldSchema = z.object({
|
|
6
|
+
name: z.string().describe("Field name in camelCase (e.g. 'email', 'firstName')."),
|
|
7
|
+
type: z
|
|
8
|
+
.enum(["text", "email", "password", "number", "phone", "textarea", "select"])
|
|
9
|
+
.describe("Field input type."),
|
|
10
|
+
label: z.string().describe("Display label for the field."),
|
|
11
|
+
required: z.boolean().optional().default(true).describe("Whether the field is required."),
|
|
12
|
+
placeholder: z.string().optional().describe("Placeholder text."),
|
|
13
|
+
});
|
|
14
|
+
const inputSchema = {
|
|
15
|
+
form_name: z
|
|
16
|
+
.string()
|
|
17
|
+
.describe("Form component name in PascalCase (e.g. 'LoginForm', 'ContactForm')."),
|
|
18
|
+
fields: z
|
|
19
|
+
.array(fieldSchema)
|
|
20
|
+
.min(1)
|
|
21
|
+
.describe("Array of field definitions."),
|
|
22
|
+
project_path: z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Absolute path to the project root. Defaults to cwd."),
|
|
26
|
+
framework: z
|
|
27
|
+
.enum(["expo", "flutter"])
|
|
28
|
+
.optional()
|
|
29
|
+
.default("expo")
|
|
30
|
+
.describe("Project framework (default: expo)."),
|
|
31
|
+
output_directory: z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.default("components")
|
|
35
|
+
.describe("Output directory relative to project root (default: components)."),
|
|
36
|
+
};
|
|
37
|
+
function zodValidation(field) {
|
|
38
|
+
let chain = "z.string()";
|
|
39
|
+
if (field.required)
|
|
40
|
+
chain += '.min(1, "Required")';
|
|
41
|
+
if (field.type === "email")
|
|
42
|
+
chain += '.email("Invalid email")';
|
|
43
|
+
if (field.type === "number")
|
|
44
|
+
chain = "z.coerce.number()";
|
|
45
|
+
if (field.type === "phone")
|
|
46
|
+
chain += '.regex(/^\\+?[0-9\\s-()]+$/, "Invalid phone number")';
|
|
47
|
+
if (field.type === "password")
|
|
48
|
+
chain += '.min(8, "At least 8 characters")';
|
|
49
|
+
return chain;
|
|
50
|
+
}
|
|
51
|
+
function rnInputType(type) {
|
|
52
|
+
switch (type) {
|
|
53
|
+
case "email": return "email-address";
|
|
54
|
+
case "number": return "numeric";
|
|
55
|
+
case "phone": return "phone-pad";
|
|
56
|
+
default: return "default";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function generateExpoForm(name, fields) {
|
|
60
|
+
const schemaFields = fields
|
|
61
|
+
.map((f) => ` ${f.name}: ${zodValidation(f)},`)
|
|
62
|
+
.join("\n");
|
|
63
|
+
const formFields = fields
|
|
64
|
+
.map((f) => {
|
|
65
|
+
const secureEntry = f.type === "password" ? "\n secureTextEntry" : "";
|
|
66
|
+
const multiline = f.type === "textarea" ? "\n multiline\n numberOfLines={4}" : "";
|
|
67
|
+
const keyboard = f.type !== "text" && f.type !== "password" && f.type !== "textarea" && f.type !== "select"
|
|
68
|
+
? `\n keyboardType="${rnInputType(f.type)}"`
|
|
69
|
+
: "";
|
|
70
|
+
return ` <View style={styles.field}>
|
|
71
|
+
<Text style={styles.label}>${f.label}</Text>
|
|
72
|
+
<Controller
|
|
73
|
+
control={control}
|
|
74
|
+
name="${f.name}"
|
|
75
|
+
render={({ field: { onChange, onBlur, value } }) => (
|
|
76
|
+
<TextInput
|
|
77
|
+
style={[styles.input, errors.${f.name} && styles.inputError]}
|
|
78
|
+
onBlur={onBlur}
|
|
79
|
+
onChangeText={onChange}
|
|
80
|
+
value={value}
|
|
81
|
+
placeholder="${f.placeholder || f.label}"${secureEntry}${multiline}${keyboard}
|
|
82
|
+
/>
|
|
83
|
+
)}
|
|
84
|
+
/>
|
|
85
|
+
{errors.${f.name} && (
|
|
86
|
+
<Text style={styles.error}>{errors.${f.name}?.message}</Text>
|
|
87
|
+
)}
|
|
88
|
+
</View>`;
|
|
89
|
+
})
|
|
90
|
+
.join("\n\n");
|
|
91
|
+
const defaultValues = fields
|
|
92
|
+
.map((f) => ` ${f.name}: "",`)
|
|
93
|
+
.join("\n");
|
|
94
|
+
return `import { View, Text, TextInput, Pressable, StyleSheet } from "react-native";
|
|
95
|
+
import { useForm, Controller } from "react-hook-form";
|
|
96
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
97
|
+
import { z } from "zod";
|
|
98
|
+
|
|
99
|
+
const schema = z.object({
|
|
100
|
+
${schemaFields}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
type FormData = z.infer<typeof schema>;
|
|
104
|
+
|
|
105
|
+
interface ${name}Props {
|
|
106
|
+
onSubmit: (data: FormData) => void;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function ${name}({ onSubmit }: ${name}Props) {
|
|
110
|
+
const {
|
|
111
|
+
control,
|
|
112
|
+
handleSubmit,
|
|
113
|
+
formState: { errors, isSubmitting },
|
|
114
|
+
} = useForm<FormData>({
|
|
115
|
+
resolver: zodResolver(schema),
|
|
116
|
+
defaultValues: {
|
|
117
|
+
${defaultValues}
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<View style={styles.container}>
|
|
123
|
+
${formFields}
|
|
124
|
+
|
|
125
|
+
<Pressable
|
|
126
|
+
style={[styles.button, isSubmitting && styles.buttonDisabled]}
|
|
127
|
+
onPress={handleSubmit(onSubmit)}
|
|
128
|
+
disabled={isSubmitting}
|
|
129
|
+
>
|
|
130
|
+
<Text style={styles.buttonText}>
|
|
131
|
+
{isSubmitting ? "Submitting..." : "Submit"}
|
|
132
|
+
</Text>
|
|
133
|
+
</Pressable>
|
|
134
|
+
</View>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const styles = StyleSheet.create({
|
|
139
|
+
container: {
|
|
140
|
+
padding: 16,
|
|
141
|
+
gap: 12,
|
|
142
|
+
},
|
|
143
|
+
field: {
|
|
144
|
+
gap: 4,
|
|
145
|
+
},
|
|
146
|
+
label: {
|
|
147
|
+
fontSize: 14,
|
|
148
|
+
fontWeight: "600",
|
|
149
|
+
},
|
|
150
|
+
input: {
|
|
151
|
+
borderWidth: 1,
|
|
152
|
+
borderColor: "#ccc",
|
|
153
|
+
borderRadius: 8,
|
|
154
|
+
padding: 12,
|
|
155
|
+
fontSize: 16,
|
|
156
|
+
},
|
|
157
|
+
inputError: {
|
|
158
|
+
borderColor: "#dc2626",
|
|
159
|
+
},
|
|
160
|
+
error: {
|
|
161
|
+
color: "#dc2626",
|
|
162
|
+
fontSize: 12,
|
|
163
|
+
},
|
|
164
|
+
button: {
|
|
165
|
+
backgroundColor: "#0A84FF",
|
|
166
|
+
padding: 16,
|
|
167
|
+
borderRadius: 8,
|
|
168
|
+
alignItems: "center",
|
|
169
|
+
marginTop: 8,
|
|
170
|
+
},
|
|
171
|
+
buttonDisabled: {
|
|
172
|
+
opacity: 0.6,
|
|
173
|
+
},
|
|
174
|
+
buttonText: {
|
|
175
|
+
color: "#fff",
|
|
176
|
+
fontSize: 16,
|
|
177
|
+
fontWeight: "600",
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
`;
|
|
181
|
+
}
|
|
182
|
+
function generateFlutterForm(name, fields) {
|
|
183
|
+
const className = name.charAt(0).toUpperCase() + name.slice(1);
|
|
184
|
+
const controllers = fields
|
|
185
|
+
.map((f) => ` final _${f.name}Controller = TextEditingController();`)
|
|
186
|
+
.join("\n");
|
|
187
|
+
const disposeControllers = fields
|
|
188
|
+
.map((f) => ` _${f.name}Controller.dispose();`)
|
|
189
|
+
.join("\n");
|
|
190
|
+
const formFields = fields
|
|
191
|
+
.map((f) => {
|
|
192
|
+
const obscure = f.type === "password" ? "\n obscureText: true," : "";
|
|
193
|
+
const maxLines = f.type === "textarea" ? "\n maxLines: 4," : "";
|
|
194
|
+
const keyboard = f.type === "email"
|
|
195
|
+
? "\n keyboardType: TextInputType.emailAddress,"
|
|
196
|
+
: f.type === "number"
|
|
197
|
+
? "\n keyboardType: TextInputType.number,"
|
|
198
|
+
: f.type === "phone"
|
|
199
|
+
? "\n keyboardType: TextInputType.phone,"
|
|
200
|
+
: "";
|
|
201
|
+
const validator = f.required
|
|
202
|
+
? `\n validator: (value) {\n if (value == null || value.isEmpty) return '${f.label} is required';\n return null;\n },`
|
|
203
|
+
: "";
|
|
204
|
+
return ` TextFormField(
|
|
205
|
+
controller: _${f.name}Controller,
|
|
206
|
+
decoration: const InputDecoration(
|
|
207
|
+
labelText: '${f.label}',
|
|
208
|
+
hintText: '${f.placeholder || f.label}',
|
|
209
|
+
),${obscure}${maxLines}${keyboard}${validator}
|
|
210
|
+
),
|
|
211
|
+
const SizedBox(height: 16),`;
|
|
212
|
+
})
|
|
213
|
+
.join("\n");
|
|
214
|
+
return `import 'package:flutter/material.dart';
|
|
215
|
+
|
|
216
|
+
class ${className} extends StatefulWidget {
|
|
217
|
+
final void Function(Map<String, String> data) onSubmit;
|
|
218
|
+
|
|
219
|
+
const ${className}({super.key, required this.onSubmit});
|
|
220
|
+
|
|
221
|
+
@override
|
|
222
|
+
State<${className}> createState() => _${className}State();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
class _${className}State extends State<${className}> {
|
|
226
|
+
final _formKey = GlobalKey<FormState>();
|
|
227
|
+
bool _isSubmitting = false;
|
|
228
|
+
|
|
229
|
+
${controllers}
|
|
230
|
+
|
|
231
|
+
@override
|
|
232
|
+
void dispose() {
|
|
233
|
+
${disposeControllers}
|
|
234
|
+
super.dispose();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
Future<void> _handleSubmit() async {
|
|
238
|
+
if (!_formKey.currentState!.validate()) return;
|
|
239
|
+
|
|
240
|
+
setState(() => _isSubmitting = true);
|
|
241
|
+
try {
|
|
242
|
+
widget.onSubmit({
|
|
243
|
+
${fields.map((f) => ` '${f.name}': _${f.name}Controller.text,`).join("\n")}
|
|
244
|
+
});
|
|
245
|
+
} finally {
|
|
246
|
+
if (mounted) setState(() => _isSubmitting = false);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
@override
|
|
251
|
+
Widget build(BuildContext context) {
|
|
252
|
+
return Form(
|
|
253
|
+
key: _formKey,
|
|
254
|
+
child: Padding(
|
|
255
|
+
padding: const EdgeInsets.all(16),
|
|
256
|
+
child: Column(
|
|
257
|
+
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
258
|
+
children: [
|
|
259
|
+
${formFields}
|
|
260
|
+
ElevatedButton(
|
|
261
|
+
onPressed: _isSubmitting ? null : _handleSubmit,
|
|
262
|
+
child: Text(_isSubmitting ? 'Submitting...' : 'Submit'),
|
|
263
|
+
),
|
|
264
|
+
],
|
|
265
|
+
),
|
|
266
|
+
),
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
`;
|
|
271
|
+
}
|
|
272
|
+
export function register(server) {
|
|
273
|
+
server.tool("mobile_generateForm", "Scaffold a validated form component with typed fields, validation rules, and error handling. Uses React Hook Form + Zod for Expo or Form + TextFormField for Flutter.", inputSchema, async (args) => {
|
|
274
|
+
try {
|
|
275
|
+
const root = args.project_path || process.cwd();
|
|
276
|
+
const outDir = join(root, args.output_directory);
|
|
277
|
+
mkdirSync(outDir, { recursive: true });
|
|
278
|
+
const fields = args.fields.map((f) => ({
|
|
279
|
+
name: f.name,
|
|
280
|
+
type: f.type,
|
|
281
|
+
label: f.label,
|
|
282
|
+
required: f.required,
|
|
283
|
+
placeholder: f.placeholder,
|
|
284
|
+
}));
|
|
285
|
+
if (args.framework === "flutter") {
|
|
286
|
+
const fileName = args.form_name
|
|
287
|
+
.replace(/([A-Z])/g, "_$1")
|
|
288
|
+
.toLowerCase()
|
|
289
|
+
.replace(/^_/, "");
|
|
290
|
+
const filePath = join(outDir, `${fileName}.dart`);
|
|
291
|
+
if (existsSync(filePath)) {
|
|
292
|
+
return errorResponse(new Error(`File already exists: ${filePath}`));
|
|
293
|
+
}
|
|
294
|
+
writeFileSync(filePath, generateFlutterForm(args.form_name, fields), "utf-8");
|
|
295
|
+
return textResponse(JSON.stringify({
|
|
296
|
+
success: true,
|
|
297
|
+
framework: "flutter",
|
|
298
|
+
file_created: filePath,
|
|
299
|
+
form_name: args.form_name,
|
|
300
|
+
fields: fields.map((f) => f.name),
|
|
301
|
+
next_steps: [
|
|
302
|
+
"Import and use the form widget in your screen",
|
|
303
|
+
"Add email/phone validators if needed",
|
|
304
|
+
"Add keyboard avoidance with SingleChildScrollView",
|
|
305
|
+
],
|
|
306
|
+
}, null, 2));
|
|
307
|
+
}
|
|
308
|
+
const filePath = join(outDir, `${args.form_name}.tsx`);
|
|
309
|
+
if (existsSync(filePath)) {
|
|
310
|
+
return errorResponse(new Error(`File already exists: ${filePath}`));
|
|
311
|
+
}
|
|
312
|
+
writeFileSync(filePath, generateExpoForm(args.form_name, fields), "utf-8");
|
|
313
|
+
return textResponse(JSON.stringify({
|
|
314
|
+
success: true,
|
|
315
|
+
framework: "expo",
|
|
316
|
+
file_created: filePath,
|
|
317
|
+
form_name: args.form_name,
|
|
318
|
+
fields: fields.map((f) => f.name),
|
|
319
|
+
dependencies_needed: [
|
|
320
|
+
"react-hook-form",
|
|
321
|
+
"@hookform/resolvers",
|
|
322
|
+
"zod",
|
|
323
|
+
],
|
|
324
|
+
next_steps: [
|
|
325
|
+
"Install dependencies: npx expo install react-hook-form @hookform/resolvers zod",
|
|
326
|
+
"Import and render the form in your screen",
|
|
327
|
+
"Implement the onSubmit handler with your API call",
|
|
328
|
+
"Add KeyboardAvoidingView wrapper if fields are below the fold",
|
|
329
|
+
],
|
|
330
|
+
}, null, 2));
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
return errorResponse(err);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
//# sourceMappingURL=generateForm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateForm.js","sourceRoot":"","sources":["../../src/tools/generateForm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateTestFile.d.ts","sourceRoot":"","sources":["../../src/tools/generateTestFile.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAwHzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyGhD"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
3
|
+
import { join, dirname, basename, extname } from "node:path";
|
|
4
|
+
import { textResponse, errorResponse } from "../types.js";
|
|
5
|
+
const inputSchema = {
|
|
6
|
+
source_file: z
|
|
7
|
+
.string()
|
|
8
|
+
.describe("Path to the source file to generate a test for (relative to project root or absolute)."),
|
|
9
|
+
project_path: z
|
|
10
|
+
.string()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Absolute path to the project root. Defaults to cwd."),
|
|
13
|
+
framework: z
|
|
14
|
+
.enum(["expo", "flutter"])
|
|
15
|
+
.optional()
|
|
16
|
+
.default("expo")
|
|
17
|
+
.describe("Project framework (default: expo). Determines test file conventions."),
|
|
18
|
+
test_location: z
|
|
19
|
+
.enum(["__tests__", "colocated"])
|
|
20
|
+
.optional()
|
|
21
|
+
.default("__tests__")
|
|
22
|
+
.describe("Where to place test files. __tests__: sibling directory. colocated: same directory as source."),
|
|
23
|
+
};
|
|
24
|
+
function extractExports(content) {
|
|
25
|
+
const exports = [];
|
|
26
|
+
const patterns = [
|
|
27
|
+
/export\s+(?:default\s+)?function\s+(\w+)/g,
|
|
28
|
+
/export\s+(?:default\s+)?class\s+(\w+)/g,
|
|
29
|
+
/export\s+const\s+(\w+)/g,
|
|
30
|
+
];
|
|
31
|
+
for (const pattern of patterns) {
|
|
32
|
+
let match;
|
|
33
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
34
|
+
exports.push(match[1]);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return exports;
|
|
38
|
+
}
|
|
39
|
+
function isComponent(content) {
|
|
40
|
+
return (content.includes("from \"react-native\"") ||
|
|
41
|
+
content.includes("from 'react-native'") ||
|
|
42
|
+
content.includes("from \"react\"") ||
|
|
43
|
+
content.includes("from 'react'") ||
|
|
44
|
+
/<\w+/.test(content));
|
|
45
|
+
}
|
|
46
|
+
function generateExpoTest(sourceName, exports, isReactComponent, importPath) {
|
|
47
|
+
const lines = [];
|
|
48
|
+
if (isReactComponent) {
|
|
49
|
+
lines.push(`import { render, screen } from "@testing-library/react-native";`);
|
|
50
|
+
const named = exports.filter((e) => e !== "default");
|
|
51
|
+
if (named.length > 0) {
|
|
52
|
+
lines.push(`import { ${named.join(", ")} } from "${importPath}";`);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
lines.push(`import ${sourceName} from "${importPath}";`);
|
|
56
|
+
}
|
|
57
|
+
lines.push("");
|
|
58
|
+
const componentName = exports[0] || sourceName;
|
|
59
|
+
lines.push(`describe("${componentName}", () => {`);
|
|
60
|
+
lines.push(` it("renders without crashing", () => {`);
|
|
61
|
+
lines.push(` render(<${componentName} />);`);
|
|
62
|
+
lines.push(` });`);
|
|
63
|
+
lines.push("");
|
|
64
|
+
lines.push(` it.todo("handles user interaction");`);
|
|
65
|
+
lines.push(`});`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
if (exports.length > 0) {
|
|
69
|
+
lines.push(`import { ${exports.join(", ")} } from "${importPath}";`);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
lines.push(`import "${importPath}";`);
|
|
73
|
+
}
|
|
74
|
+
lines.push("");
|
|
75
|
+
lines.push(`describe("${sourceName}", () => {`);
|
|
76
|
+
for (const exp of exports) {
|
|
77
|
+
lines.push(` describe("${exp}", () => {`);
|
|
78
|
+
lines.push(` it.todo("works correctly");`);
|
|
79
|
+
lines.push(` });`);
|
|
80
|
+
lines.push("");
|
|
81
|
+
}
|
|
82
|
+
if (exports.length === 0) {
|
|
83
|
+
lines.push(` it.todo("works correctly");`);
|
|
84
|
+
}
|
|
85
|
+
lines.push(`});`);
|
|
86
|
+
}
|
|
87
|
+
lines.push("");
|
|
88
|
+
return lines.join("\n");
|
|
89
|
+
}
|
|
90
|
+
function generateFlutterTest(sourceName, importPath) {
|
|
91
|
+
return `import 'package:flutter_test/flutter_test.dart';
|
|
92
|
+
import '${importPath}';
|
|
93
|
+
|
|
94
|
+
void main() {
|
|
95
|
+
group('${sourceName}', () {
|
|
96
|
+
test('exists', () {
|
|
97
|
+
// Placeholder: replace with real assertions
|
|
98
|
+
expect(true, isTrue);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// TODO: add widget tests with testWidgets() if this is a widget
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
`;
|
|
105
|
+
}
|
|
106
|
+
export function register(server) {
|
|
107
|
+
server.tool("mobile_generateTestFile", "Scaffold a test file for an existing component or module. Reads exports from the source file and generates matching test boilerplate.", inputSchema, async (args) => {
|
|
108
|
+
try {
|
|
109
|
+
const root = args.project_path || process.cwd();
|
|
110
|
+
const sourceAbsolute = args.source_file.startsWith("/") || args.source_file.match(/^[A-Z]:\\/)
|
|
111
|
+
? args.source_file
|
|
112
|
+
: join(root, args.source_file);
|
|
113
|
+
if (!existsSync(sourceAbsolute)) {
|
|
114
|
+
return errorResponse(new Error(`Source file not found: ${sourceAbsolute}`));
|
|
115
|
+
}
|
|
116
|
+
const content = readFileSync(sourceAbsolute, "utf-8");
|
|
117
|
+
const ext = extname(sourceAbsolute);
|
|
118
|
+
const nameWithoutExt = basename(sourceAbsolute, ext);
|
|
119
|
+
const sourceDir = dirname(sourceAbsolute);
|
|
120
|
+
if (args.framework === "flutter") {
|
|
121
|
+
const testDir = join(root, "test");
|
|
122
|
+
const relativePath = sourceAbsolute.replace(join(root, "lib"), "").replace(/\\/g, "/");
|
|
123
|
+
const testFile = join(testDir, relativePath.replace(ext, "_test.dart"));
|
|
124
|
+
if (existsSync(testFile)) {
|
|
125
|
+
return errorResponse(new Error(`Test file already exists: ${testFile}`));
|
|
126
|
+
}
|
|
127
|
+
const packageName = basename(root);
|
|
128
|
+
const importPath = `package:${packageName}${relativePath.replace(/\\/g, "/")}`;
|
|
129
|
+
mkdirSync(dirname(testFile), { recursive: true });
|
|
130
|
+
writeFileSync(testFile, generateFlutterTest(nameWithoutExt, importPath), "utf-8");
|
|
131
|
+
return textResponse(JSON.stringify({
|
|
132
|
+
success: true,
|
|
133
|
+
file_created: testFile,
|
|
134
|
+
source_file: sourceAbsolute,
|
|
135
|
+
framework: "flutter",
|
|
136
|
+
next_steps: [
|
|
137
|
+
"Replace placeholder assertions with real tests",
|
|
138
|
+
"Add testWidgets() calls for widget tests",
|
|
139
|
+
"Run: flutter test " + testFile,
|
|
140
|
+
],
|
|
141
|
+
}, null, 2));
|
|
142
|
+
}
|
|
143
|
+
const exports = extractExports(content);
|
|
144
|
+
const isComp = isComponent(content);
|
|
145
|
+
let testFile;
|
|
146
|
+
let importPath;
|
|
147
|
+
if (args.test_location === "colocated") {
|
|
148
|
+
testFile = join(sourceDir, `${nameWithoutExt}.test${ext}`);
|
|
149
|
+
importPath = `./${nameWithoutExt}`;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
const testDir = join(sourceDir, "__tests__");
|
|
153
|
+
testFile = join(testDir, `${nameWithoutExt}.test${ext}`);
|
|
154
|
+
importPath = `../${nameWithoutExt}`;
|
|
155
|
+
mkdirSync(testDir, { recursive: true });
|
|
156
|
+
}
|
|
157
|
+
if (existsSync(testFile)) {
|
|
158
|
+
return errorResponse(new Error(`Test file already exists: ${testFile}`));
|
|
159
|
+
}
|
|
160
|
+
const testContent = generateExpoTest(nameWithoutExt, exports, isComp, importPath);
|
|
161
|
+
writeFileSync(testFile, testContent, "utf-8");
|
|
162
|
+
return textResponse(JSON.stringify({
|
|
163
|
+
success: true,
|
|
164
|
+
file_created: testFile,
|
|
165
|
+
source_file: sourceAbsolute,
|
|
166
|
+
framework: "expo",
|
|
167
|
+
detected_exports: exports,
|
|
168
|
+
is_component: isComp,
|
|
169
|
+
test_location: args.test_location,
|
|
170
|
+
next_steps: [
|
|
171
|
+
"Fill in the placeholder test cases",
|
|
172
|
+
isComp
|
|
173
|
+
? "Add interaction tests with fireEvent/userEvent"
|
|
174
|
+
: "Add assertions for each exported function",
|
|
175
|
+
"Run: npx jest " + testFile,
|
|
176
|
+
],
|
|
177
|
+
}, null, 2));
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
return errorResponse(err);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=generateTestFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateTestFile.js","sourceRoot":"","sources":["../../src/tools/generateTestFile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profilePerformance.d.ts","sourceRoot":"","sources":["../../src/tools/profilePerformance.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgNzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyChD"}
|