@promakeai/inspector-hook 1.0.1 → 1.1.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/README.md +1499 -0
- package/dist/utils/jsxUpdater.d.ts +2 -1
- package/dist/utils/jsxUpdater.d.ts.map +1 -1
- package/dist/utils/jsxUpdater.js +318 -117
- package/package.json +1 -9
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* JSX Source Code Updater
|
|
3
|
-
*
|
|
3
|
+
* Lightweight regex-based utility for updating styles and classNames in JSX/TSX source code
|
|
4
|
+
* No Babel dependencies - works perfectly in browser environments!
|
|
4
5
|
*/
|
|
5
6
|
export interface UpdateJSXSourceOptions {
|
|
6
7
|
sourceCode: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsxUpdater.d.ts","sourceRoot":"","sources":["../../src/utils/jsxUpdater.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"jsxUpdater.d.ts","sourceRoot":"","sources":["../../src/utils/jsxUpdater.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA4YD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,sBAAsB,GAC9B,qBAAqB,CAkFvB"}
|
package/dist/utils/jsxUpdater.js
CHANGED
|
@@ -1,120 +1,320 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* JSX Source Code Updater
|
|
3
|
-
*
|
|
3
|
+
* Lightweight regex-based utility for updating styles and classNames in JSX/TSX source code
|
|
4
|
+
* No Babel dependencies - works perfectly in browser environments!
|
|
4
5
|
*/
|
|
5
|
-
import * as parser from '@babel/parser';
|
|
6
|
-
import traverse from '@babel/traverse';
|
|
7
|
-
import generate from '@babel/generator';
|
|
8
|
-
import * as t from '@babel/types';
|
|
9
6
|
/**
|
|
10
|
-
*
|
|
7
|
+
* Extract tag name from JSX opening tag (handles generics like Component<T>)
|
|
11
8
|
*/
|
|
12
|
-
function
|
|
13
|
-
|
|
9
|
+
function extractTagName(tagContent) {
|
|
10
|
+
// Match tag name, supporting generics: <Component<T> or <div
|
|
11
|
+
const match = tagContent.match(/^<([A-Za-z_$][A-Za-z0-9_$]*)/);
|
|
12
|
+
return match ? match[1] : null;
|
|
14
13
|
}
|
|
15
14
|
/**
|
|
16
|
-
* Find JSX
|
|
15
|
+
* Find the JSX opening tag at the specified line and column
|
|
17
16
|
*/
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
17
|
+
function findJSXTagAtPosition(sourceCode, lineNumber, columnNumber, tagName) {
|
|
18
|
+
const lines = sourceCode.split("\n");
|
|
19
|
+
if (lineNumber < 1 || lineNumber > lines.length) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
// Calculate absolute position in source code
|
|
23
|
+
let absolutePosition = 0;
|
|
24
|
+
for (let i = 0; i < lineNumber - 1; i++) {
|
|
25
|
+
absolutePosition += lines[i].length + 1; // +1 for newline
|
|
26
|
+
}
|
|
27
|
+
absolutePosition += columnNumber;
|
|
28
|
+
// Check if we're at the start of a tag (flexible - allows any tag)
|
|
29
|
+
const remainingCode = sourceCode.slice(absolutePosition);
|
|
30
|
+
const tagPattern = /^<[A-Za-z_$][A-Za-z0-9_$]*/;
|
|
31
|
+
if (!tagPattern.test(remainingCode)) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
// Extract actual tag name found at this position
|
|
35
|
+
const foundTagName = extractTagName(remainingCode);
|
|
36
|
+
if (!foundTagName) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
// Find the end of the opening tag
|
|
40
|
+
let depth = 0;
|
|
41
|
+
let angleBracketDepth = 0; // For TypeScript generics
|
|
42
|
+
let inString = false;
|
|
43
|
+
let stringChar = "";
|
|
44
|
+
let inExpression = false;
|
|
45
|
+
let i = absolutePosition + 1; // Skip the '<'
|
|
46
|
+
let hasSeenTagName = false;
|
|
47
|
+
while (i < sourceCode.length) {
|
|
48
|
+
const char = sourceCode[i];
|
|
49
|
+
const prevChar = i > 0 ? sourceCode[i - 1] : "";
|
|
50
|
+
// Handle strings
|
|
51
|
+
if ((char === '"' || char === "'" || char === "`") && prevChar !== "\\") {
|
|
52
|
+
if (!inString) {
|
|
53
|
+
inString = true;
|
|
54
|
+
stringChar = char;
|
|
55
|
+
}
|
|
56
|
+
else if (char === stringChar) {
|
|
57
|
+
inString = false;
|
|
58
|
+
stringChar = "";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Handle JSX expressions and TypeScript generics
|
|
62
|
+
if (!inString) {
|
|
63
|
+
if (char === "{") {
|
|
64
|
+
inExpression = true;
|
|
65
|
+
depth++;
|
|
66
|
+
}
|
|
67
|
+
else if (char === "}") {
|
|
68
|
+
depth--;
|
|
69
|
+
if (depth === 0) {
|
|
70
|
+
inExpression = false;
|
|
71
|
+
}
|
|
72
|
+
// Detect unterminated expressions
|
|
73
|
+
if (depth < 0) {
|
|
74
|
+
return null; // Invalid JSX
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (char === "<" && !hasSeenTagName) {
|
|
78
|
+
// TypeScript generic opening
|
|
79
|
+
angleBracketDepth++;
|
|
80
|
+
}
|
|
81
|
+
else if (char === ">" && angleBracketDepth > 0) {
|
|
82
|
+
// TypeScript generic closing
|
|
83
|
+
angleBracketDepth--;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Mark that we've passed the tag name
|
|
87
|
+
if (!hasSeenTagName &&
|
|
88
|
+
(char === " " || char === "\t" || char === "\n" || char === "<")) {
|
|
89
|
+
hasSeenTagName = true;
|
|
90
|
+
}
|
|
91
|
+
// Check for end of opening tag
|
|
92
|
+
if (!inString && !inExpression && depth === 0 && angleBracketDepth === 0) {
|
|
93
|
+
if (char === ">" ||
|
|
94
|
+
(char === "/" && i + 1 < sourceCode.length && sourceCode[i + 1] === ">")) {
|
|
95
|
+
const end = char === "/" ? i + 2 : i + 1;
|
|
96
|
+
const content = sourceCode.slice(absolutePosition, end);
|
|
97
|
+
// Additional validation: check for incomplete/malformed closing tag
|
|
98
|
+
if (!content.trim().endsWith(">") && !content.trim().endsWith("/>")) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
start: absolutePosition,
|
|
103
|
+
end: end,
|
|
104
|
+
content: content,
|
|
105
|
+
foundTagName: foundTagName,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
i++;
|
|
110
|
+
}
|
|
111
|
+
// If we reach here, the tag was not properly closed
|
|
112
|
+
return null;
|
|
32
113
|
}
|
|
33
114
|
/**
|
|
34
|
-
*
|
|
115
|
+
* Parse inline style object from style attribute
|
|
35
116
|
*/
|
|
36
|
-
function
|
|
37
|
-
const
|
|
38
|
-
//
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
117
|
+
function parseStyleObject(styleValue) {
|
|
118
|
+
const styles = {};
|
|
119
|
+
// Remove outer {{ }}
|
|
120
|
+
const objectMatch = styleValue.match(/\{\s*\{([^}]*)\}\s*\}/s);
|
|
121
|
+
if (!objectMatch) {
|
|
122
|
+
return styles;
|
|
123
|
+
}
|
|
124
|
+
const content = objectMatch[1];
|
|
125
|
+
// Parse property: value pairs
|
|
126
|
+
const propRegex = /(\w+):\s*['"]([^'"]*)['"]/g;
|
|
127
|
+
let match;
|
|
128
|
+
while ((match = propRegex.exec(content)) !== null) {
|
|
129
|
+
styles[match[1]] = match[2];
|
|
130
|
+
}
|
|
131
|
+
return styles;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Create style object string from styles
|
|
135
|
+
*/
|
|
136
|
+
function createStyleString(styles) {
|
|
137
|
+
const entries = Object.entries(styles).map(([key, value]) => `${key}: "${value}"`);
|
|
138
|
+
return `{{ ${entries.join(", ")} }}`;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Validate that the tag content has proper syntax
|
|
142
|
+
*/
|
|
143
|
+
function validateTagSyntax(tagContent) {
|
|
144
|
+
// Check for incomplete attributes (e.g., className= without value)
|
|
145
|
+
if (/\s+\w+=$/.test(tagContent) || /\s+\w+=\s*>/.test(tagContent)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
// Check for proper closing
|
|
149
|
+
if (!tagContent.endsWith(">") && !tagContent.endsWith("/>")) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Check if a JSX element has a proper closing tag and valid content (basic check)
|
|
156
|
+
*/
|
|
157
|
+
function hasProperClosingTag(sourceCode, tagStart, tagEnd, tagName) {
|
|
158
|
+
// For self-closing tags, no closing tag needed
|
|
159
|
+
const openingTag = sourceCode.slice(tagStart, tagEnd);
|
|
160
|
+
if (openingTag.trim().endsWith("/>")) {
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
// Look for closing tag after the opening tag
|
|
164
|
+
const afterOpening = sourceCode.slice(tagEnd);
|
|
165
|
+
const closingTagPattern = new RegExp(`</${tagName}\\s*>`);
|
|
166
|
+
// Check if there's a closing tag somewhere
|
|
167
|
+
const closingMatch = closingTagPattern.exec(afterOpening);
|
|
168
|
+
if (!closingMatch) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
// Check the content between opening and closing tags for unmatched braces
|
|
172
|
+
const contentBetween = afterOpening.slice(0, closingMatch.index);
|
|
173
|
+
let braceDepth = 0;
|
|
174
|
+
let inString = false;
|
|
175
|
+
let stringChar = "";
|
|
176
|
+
for (let i = 0; i < contentBetween.length; i++) {
|
|
177
|
+
const char = contentBetween[i];
|
|
178
|
+
const prevChar = i > 0 ? contentBetween[i - 1] : "";
|
|
179
|
+
// Handle strings
|
|
180
|
+
if ((char === '"' || char === "'" || char === "`") && prevChar !== "\\") {
|
|
181
|
+
if (!inString) {
|
|
182
|
+
inString = true;
|
|
183
|
+
stringChar = char;
|
|
184
|
+
}
|
|
185
|
+
else if (char === stringChar) {
|
|
186
|
+
inString = false;
|
|
187
|
+
stringChar = "";
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Count braces outside of strings
|
|
191
|
+
if (!inString) {
|
|
192
|
+
if (char === "{") {
|
|
193
|
+
braceDepth++;
|
|
194
|
+
}
|
|
195
|
+
else if (char === "}") {
|
|
196
|
+
braceDepth--;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// If braces don't match, JSX is invalid
|
|
201
|
+
if (braceDepth !== 0) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
// Validate proper nesting by tracking all opening and closing tags
|
|
205
|
+
let tagStack = [tagName];
|
|
206
|
+
let i = 0;
|
|
207
|
+
while (i < afterOpening.length && tagStack.length > 0) {
|
|
208
|
+
// Look for next tag (opening or closing)
|
|
209
|
+
const remainingCode = afterOpening.slice(i);
|
|
210
|
+
const nextTag = remainingCode.match(/^<\/?([A-Za-z_$][A-Za-z0-9_$]*)/);
|
|
211
|
+
if (!nextTag) {
|
|
212
|
+
// No more tags, move forward
|
|
213
|
+
i++;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const isClosing = remainingCode.startsWith("</");
|
|
217
|
+
const foundTagName = nextTag[1];
|
|
218
|
+
if (isClosing) {
|
|
219
|
+
// Closing tag - should match top of stack
|
|
220
|
+
if (tagStack.length === 0 ||
|
|
221
|
+
tagStack[tagStack.length - 1] !== foundTagName) {
|
|
222
|
+
return false; // Mismatched closing tag
|
|
223
|
+
}
|
|
224
|
+
tagStack.pop();
|
|
225
|
+
// If this was our target tag's closing, we're done
|
|
226
|
+
if (tagStack.length === 0) {
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
62
229
|
}
|
|
63
230
|
else {
|
|
64
|
-
//
|
|
65
|
-
|
|
231
|
+
// Opening tag - check if it's self-closing
|
|
232
|
+
const tagEndMatch = remainingCode.match(/^<[^>]+?(\/?)>/);
|
|
233
|
+
if (tagEndMatch && !tagEndMatch[1]) {
|
|
234
|
+
// Not self-closing, add to stack
|
|
235
|
+
tagStack.push(foundTagName);
|
|
236
|
+
}
|
|
237
|
+
// If self-closing (/>), don't add to stack
|
|
66
238
|
}
|
|
239
|
+
// Move past this tag
|
|
240
|
+
const tagEnd = remainingCode.indexOf(">");
|
|
241
|
+
if (tagEnd === -1)
|
|
242
|
+
break;
|
|
243
|
+
i += tagEnd + 1;
|
|
244
|
+
}
|
|
245
|
+
// Stack should be empty if all tags matched properly
|
|
246
|
+
if (tagStack.length > 0) {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Update or add style attribute in JSX tag
|
|
253
|
+
*/
|
|
254
|
+
function updateStyleAttribute(tagContent, newStyles) {
|
|
255
|
+
// Validate syntax before attempting to update
|
|
256
|
+
if (!validateTagSyntax(tagContent)) {
|
|
257
|
+
throw new Error("Invalid JSX syntax: malformed attributes or incomplete tag");
|
|
258
|
+
}
|
|
259
|
+
const styleMatch = tagContent.match(/style=\{\s*\{[^}]*\}\s*\}/s);
|
|
260
|
+
if (styleMatch) {
|
|
261
|
+
// Merge with existing styles
|
|
262
|
+
const existingStyles = parseStyleObject(styleMatch[0]);
|
|
263
|
+
const mergedStyles = { ...existingStyles, ...newStyles };
|
|
264
|
+
const newStyleAttr = `style=${createStyleString(mergedStyles)}`;
|
|
265
|
+
return tagContent.replace(/style=\{\s*\{[^}]*\}\s*\}/s, newStyleAttr);
|
|
67
266
|
}
|
|
68
267
|
else {
|
|
69
268
|
// Add new style attribute
|
|
70
|
-
const
|
|
71
|
-
|
|
269
|
+
const newStyleAttr = ` style=${createStyleString(newStyles)}`;
|
|
270
|
+
// Insert before closing > or />
|
|
271
|
+
if (tagContent.endsWith("/>")) {
|
|
272
|
+
return tagContent.slice(0, -2) + newStyleAttr + " />";
|
|
273
|
+
}
|
|
274
|
+
else if (tagContent.endsWith(">")) {
|
|
275
|
+
return tagContent.slice(0, -1) + newStyleAttr + ">";
|
|
276
|
+
}
|
|
72
277
|
}
|
|
278
|
+
return tagContent;
|
|
73
279
|
}
|
|
74
280
|
/**
|
|
75
|
-
*
|
|
281
|
+
* Update or add className attribute in JSX tag
|
|
76
282
|
*/
|
|
77
|
-
function
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
283
|
+
function updateClassNameAttribute(tagContent, newClassName) {
|
|
284
|
+
// Validate syntax before attempting to update
|
|
285
|
+
if (!validateTagSyntax(tagContent)) {
|
|
286
|
+
throw new Error("Invalid JSX syntax: malformed attributes or incomplete tag");
|
|
287
|
+
}
|
|
288
|
+
// Check for existing className
|
|
289
|
+
const classNameMatch = tagContent.match(/className=["']([^"']*)["']/);
|
|
290
|
+
if (classNameMatch) {
|
|
84
291
|
// Merge with existing className
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
//
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
else if (t.isJSXExpressionContainer(classNameAttr.value) &&
|
|
98
|
-
t.isTemplateLiteral(classNameAttr.value.expression)) {
|
|
99
|
-
// Template literal className
|
|
100
|
-
const templateLiteral = classNameAttr.value.expression;
|
|
101
|
-
const lastQuasi = templateLiteral.quasis[templateLiteral.quasis.length - 1];
|
|
102
|
-
lastQuasi.value.raw += ` ${newClassName}`;
|
|
103
|
-
lastQuasi.value.cooked = lastQuasi.value.raw;
|
|
292
|
+
const existingClasses = classNameMatch[1];
|
|
293
|
+
const allClasses = `${existingClasses} ${newClassName}`.trim();
|
|
294
|
+
return tagContent.replace(/className=["'][^"']*["']/, `className="${allClasses}"`);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
// Check for className with JSX expression
|
|
298
|
+
const classNameExprMatch = tagContent.match(/className=\{[^}]*\}/);
|
|
299
|
+
if (classNameExprMatch) {
|
|
300
|
+
// Wrap existing expression in template literal
|
|
301
|
+
const existingExpr = classNameExprMatch[0].slice(11, -1); // Remove className={ and }
|
|
302
|
+
const newExpr = `className={\`\${${existingExpr}} ${newClassName}\`}`;
|
|
303
|
+
return tagContent.replace(/className=\{[^}]*\}/, newExpr);
|
|
104
304
|
}
|
|
105
305
|
else {
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
306
|
+
// Add new className attribute
|
|
307
|
+
const newClassNameAttr = ` className="${newClassName}"`;
|
|
308
|
+
// Insert before closing > or />
|
|
309
|
+
if (tagContent.endsWith("/>")) {
|
|
310
|
+
return tagContent.slice(0, -2) + newClassNameAttr + " />";
|
|
311
|
+
}
|
|
312
|
+
else if (tagContent.endsWith(">")) {
|
|
313
|
+
return tagContent.slice(0, -1) + newClassNameAttr + ">";
|
|
314
|
+
}
|
|
111
315
|
}
|
|
112
316
|
}
|
|
113
|
-
|
|
114
|
-
// Add new className attribute
|
|
115
|
-
const classNameAttr = t.jsxAttribute(t.jsxIdentifier('className'), t.stringLiteral(newClassName));
|
|
116
|
-
attributes.push(classNameAttr);
|
|
117
|
-
}
|
|
317
|
+
return tagContent;
|
|
118
318
|
}
|
|
119
319
|
/**
|
|
120
320
|
* Update JSX source code with new styles and/or className
|
|
@@ -138,56 +338,57 @@ function mergeClassNameProp(jsxOpeningElement, newClassName) {
|
|
|
138
338
|
export function updateJSXSource(options) {
|
|
139
339
|
const { sourceCode, lineNumber, columnNumber, tagName, styles, className } = options;
|
|
140
340
|
try {
|
|
141
|
-
//
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
plugins: ['jsx', 'typescript', 'decorators-legacy'],
|
|
145
|
-
});
|
|
146
|
-
// Find the target JSX element at the specified position
|
|
147
|
-
const elementPath = findJSXElementAtPosition(ast, lineNumber, columnNumber);
|
|
148
|
-
if (!elementPath) {
|
|
341
|
+
// Find the JSX tag at the specified position
|
|
342
|
+
const tagInfo = findJSXTagAtPosition(sourceCode, lineNumber, columnNumber, tagName);
|
|
343
|
+
if (!tagInfo) {
|
|
149
344
|
return {
|
|
150
345
|
success: false,
|
|
151
346
|
code: sourceCode,
|
|
152
347
|
message: `Could not find JSX element <${tagName}> at line ${lineNumber}, column ${columnNumber}`,
|
|
153
348
|
};
|
|
154
349
|
}
|
|
155
|
-
// Verify tag name matches
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
350
|
+
// Verify tag name matches
|
|
351
|
+
if (tagInfo.foundTagName.toLowerCase() !== tagName.toLowerCase()) {
|
|
352
|
+
return {
|
|
353
|
+
success: false,
|
|
354
|
+
code: sourceCode,
|
|
355
|
+
message: `Tag name mismatch: expected <${tagName}>, found <${tagInfo.foundTagName}>`,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
// Validate that the element has proper closing tag
|
|
359
|
+
if (!hasProperClosingTag(sourceCode, tagInfo.start, tagInfo.end, tagInfo.foundTagName)) {
|
|
160
360
|
return {
|
|
161
361
|
success: false,
|
|
162
362
|
code: sourceCode,
|
|
163
|
-
message: `
|
|
363
|
+
message: `Invalid JSX: element <${tagInfo.foundTagName}> is missing or has mismatched closing tag`,
|
|
164
364
|
};
|
|
165
365
|
}
|
|
366
|
+
let updatedTagContent = tagInfo.content;
|
|
166
367
|
// Apply style updates if provided
|
|
167
368
|
if (styles && Object.keys(styles).length > 0) {
|
|
168
|
-
|
|
369
|
+
updatedTagContent = updateStyleAttribute(updatedTagContent, styles);
|
|
169
370
|
}
|
|
170
371
|
// Apply className updates if provided
|
|
171
372
|
if (className && className.trim()) {
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
//
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
concise: false,
|
|
179
|
-
});
|
|
373
|
+
updatedTagContent = updateClassNameAttribute(updatedTagContent, className.trim());
|
|
374
|
+
}
|
|
375
|
+
// Replace the tag in the source code
|
|
376
|
+
const updatedCode = sourceCode.slice(0, tagInfo.start) +
|
|
377
|
+
updatedTagContent +
|
|
378
|
+
sourceCode.slice(tagInfo.end);
|
|
180
379
|
return {
|
|
181
380
|
success: true,
|
|
182
|
-
code:
|
|
183
|
-
message:
|
|
381
|
+
code: updatedCode,
|
|
382
|
+
message: "JSX source updated successfully",
|
|
184
383
|
};
|
|
185
384
|
}
|
|
186
385
|
catch (error) {
|
|
187
386
|
return {
|
|
188
387
|
success: false,
|
|
189
388
|
code: sourceCode,
|
|
190
|
-
message: error instanceof Error
|
|
389
|
+
message: error instanceof Error
|
|
390
|
+
? error.message
|
|
391
|
+
: "Unknown error occurred during JSX update",
|
|
191
392
|
};
|
|
192
393
|
}
|
|
193
394
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@promakeai/inspector-hook",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "React hook for controlling inspector in parent applications",
|
|
5
5
|
"author": "Promake",
|
|
6
6
|
"type": "module",
|
|
@@ -45,16 +45,8 @@
|
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@promakeai/inspector-types": "^1.0.1",
|
|
48
|
-
"@types/babel__traverse": "^7.20.0",
|
|
49
|
-
"@types/babel__generator": "^7.6.0",
|
|
50
48
|
"vitest": "^1.0.0"
|
|
51
49
|
},
|
|
52
|
-
"dependencies": {
|
|
53
|
-
"@babel/parser": "^7.23.0",
|
|
54
|
-
"@babel/traverse": "^7.23.0",
|
|
55
|
-
"@babel/generator": "^7.23.0",
|
|
56
|
-
"@babel/types": "^7.23.0"
|
|
57
|
-
},
|
|
58
50
|
"publishConfig": {
|
|
59
51
|
"access": "public"
|
|
60
52
|
}
|