@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.
Files changed (47) hide show
  1. package/dist/index.js +23 -1
  2. package/dist/index.js.map +1 -1
  3. package/dist/tools/addMap.d.ts +3 -0
  4. package/dist/tools/addMap.d.ts.map +1 -0
  5. package/dist/tools/addMap.js +223 -0
  6. package/dist/tools/addMap.js.map +1 -0
  7. package/dist/tools/checkOfflineReady.d.ts +3 -0
  8. package/dist/tools/checkOfflineReady.d.ts.map +1 -0
  9. package/dist/tools/checkOfflineReady.js +190 -0
  10. package/dist/tools/checkOfflineReady.js.map +1 -0
  11. package/dist/tools/generateForm.d.ts +3 -0
  12. package/dist/tools/generateForm.d.ts.map +1 -0
  13. package/dist/tools/generateForm.js +337 -0
  14. package/dist/tools/generateForm.js.map +1 -0
  15. package/dist/tools/generateTestFile.d.ts +3 -0
  16. package/dist/tools/generateTestFile.d.ts.map +1 -0
  17. package/dist/tools/generateTestFile.js +184 -0
  18. package/dist/tools/generateTestFile.js.map +1 -0
  19. package/dist/tools/profilePerformance.d.ts +3 -0
  20. package/dist/tools/profilePerformance.d.ts.map +1 -0
  21. package/dist/tools/profilePerformance.js +222 -0
  22. package/dist/tools/profilePerformance.js.map +1 -0
  23. package/dist/tools/runTests.d.ts +3 -0
  24. package/dist/tools/runTests.d.ts.map +1 -0
  25. package/dist/tools/runTests.js +165 -0
  26. package/dist/tools/runTests.js.map +1 -0
  27. package/dist/tools/securityAudit.d.ts +3 -0
  28. package/dist/tools/securityAudit.d.ts.map +1 -0
  29. package/dist/tools/securityAudit.js +213 -0
  30. package/dist/tools/securityAudit.js.map +1 -0
  31. package/dist/tools/setupCI.d.ts +3 -0
  32. package/dist/tools/setupCI.d.ts.map +1 -0
  33. package/dist/tools/setupCI.js +202 -0
  34. package/dist/tools/setupCI.js.map +1 -0
  35. package/dist/tools/setupI18n.d.ts +3 -0
  36. package/dist/tools/setupI18n.d.ts.map +1 -0
  37. package/dist/tools/setupI18n.js +155 -0
  38. package/dist/tools/setupI18n.js.map +1 -0
  39. package/dist/tools/setupMonitoring.d.ts +3 -0
  40. package/dist/tools/setupMonitoring.d.ts.map +1 -0
  41. package/dist/tools/setupMonitoring.js +250 -0
  42. package/dist/tools/setupMonitoring.js.map +1 -0
  43. package/dist/tools/setupRealtime.d.ts +3 -0
  44. package/dist/tools/setupRealtime.d.ts.map +1 -0
  45. package/dist/tools/setupRealtime.js +311 -0
  46. package/dist/tools/setupRealtime.js.map +1 -0
  47. 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,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function register(server: McpServer): void;
3
+ //# sourceMappingURL=generateTestFile.d.ts.map
@@ -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,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function register(server: McpServer): void;
3
+ //# sourceMappingURL=profilePerformance.d.ts.map
@@ -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"}