renusify 2.5.2 → 3.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.
Files changed (212) hide show
  1. package/components/app/index.vue +74 -22
  2. package/components/app/toast/index.vue +76 -71
  3. package/components/app/toast/toast.vue +62 -44
  4. package/components/avatar/index.vue +207 -84
  5. package/components/button/buttonConfirm.vue +53 -26
  6. package/components/button/buttonGroup.js +0 -2
  7. package/components/button/buttonGroup.vue +310 -62
  8. package/components/button/index.vue +584 -100
  9. package/components/calendar/index.js +0 -2
  10. package/components/calendar/index.vue +326 -262
  11. package/components/calendar/month.vue +64 -55
  12. package/components/calendar/year.vue +30 -25
  13. package/components/card/index.vue +139 -59
  14. package/components/codeEditor/highlightCss.vue +38 -39
  15. package/components/codeEditor/highlightHtml.vue +64 -64
  16. package/components/codeEditor/highlightJs.vue +37 -38
  17. package/components/codeEditor/index.vue +129 -79
  18. package/components/codeEditor/run.vue +225 -39
  19. package/components/codeEditor/useCodeFormatter.js +150 -0
  20. package/components/confirm/index.vue +139 -80
  21. package/components/container/col.vue +5 -4
  22. package/components/container/divider.vue +28 -19
  23. package/components/container/index.vue +34 -15
  24. package/components/container/row.vue +26 -9
  25. package/components/container/spacer.vue +2 -4
  26. package/components/container/style.scss +3 -0
  27. package/components/content/index.vue +49 -32
  28. package/components/cropper/index.vue +401 -244
  29. package/components/float/index.vue +542 -415
  30. package/components/form/addressInput/index.vue +184 -109
  31. package/components/form/camInput/index.vue +370 -244
  32. package/components/form/checkInput/index.vue +138 -71
  33. package/components/form/checkboxInput/index.vue +93 -49
  34. package/components/form/colorInput/Alpha.vue +81 -83
  35. package/components/form/colorInput/Hue.vue +91 -68
  36. package/components/form/colorInput/Preview.vue +43 -47
  37. package/components/form/colorInput/Saturation.vue +101 -86
  38. package/components/form/colorInput/index.vue +71 -39
  39. package/components/form/colorInput/picker.vue +111 -106
  40. package/components/form/colorInput/useColor.js +153 -0
  41. package/components/form/dateInput/index.vue +691 -356
  42. package/components/form/dateInput/month.vue +63 -54
  43. package/components/form/dateInput/year.vue +35 -25
  44. package/components/form/fileInput/index.js +0 -1
  45. package/components/form/fileInput/index.vue +263 -106
  46. package/components/form/fileInput/single.vue +332 -168
  47. package/components/form/groupInput/index.vue +199 -101
  48. package/components/form/index.vue +189 -83
  49. package/components/form/input/index.vue +416 -377
  50. package/components/form/jsonInput/JsonView.vue +54 -56
  51. package/components/form/jsonInput/index.vue +247 -165
  52. package/components/form/maskInput/index.vue +252 -132
  53. package/components/form/numberInput/index.js +0 -1
  54. package/components/form/numberInput/index.vue +226 -117
  55. package/components/form/passwordInput/index.js +2 -1
  56. package/components/form/passwordInput/index.vue +269 -102
  57. package/components/form/radioInput/index.vue +143 -72
  58. package/components/form/rangeInput/index.vue +280 -167
  59. package/components/form/ratingInput/index.vue +57 -57
  60. package/components/form/selectInput/index.js +1 -3
  61. package/components/form/selectInput/index.vue +584 -296
  62. package/components/form/switchInput/index.vue +73 -59
  63. package/components/form/telInput/index.js +0 -1
  64. package/components/form/telInput/index.vue +238 -135
  65. package/components/form/textArea/index.vue +72 -35
  66. package/components/form/textEditor/index.vue +739 -0
  67. package/components/form/{text-editor → textEditor}/style.scss +8 -16
  68. package/components/form/textInput/index.vue +54 -32
  69. package/components/form/timeInput/index.vue +82 -55
  70. package/components/form/timeInput/range.vue +115 -94
  71. package/components/form/timeInput/timepicker.vue +382 -449
  72. package/components/form/uniqueInput/index.vue +105 -48
  73. package/components/form/unitInput/index.vue +139 -84
  74. package/components/formCreator/index.js +0 -1
  75. package/components/formCreator/index.vue +314 -148
  76. package/components/highlight/index.vue +41 -25
  77. package/components/highlight/style.scss +2 -2
  78. package/components/highlight/{mixin.js → useHighlight.js} +181 -160
  79. package/components/icon/index.vue +79 -33
  80. package/components/img/index.vue +250 -147
  81. package/components/img/preview.vue +180 -198
  82. package/components/img/svgImg.vue +42 -39
  83. package/components/index.js +5 -20
  84. package/components/infinite/index.js +3 -3
  85. package/components/infinite/index.vue +290 -66
  86. package/components/map/index.vue +428 -261
  87. package/components/map/route.vue +794 -487
  88. package/components/map/select.vue +118 -58
  89. package/components/menu/index.vue +206 -94
  90. package/components/meta/meta.js +26 -3
  91. package/components/modal/index.vue +382 -156
  92. package/components/notify/index.vue +204 -86
  93. package/components/notify/notification.vue +38 -55
  94. package/components/progress/circle.vue +189 -70
  95. package/components/progress/line.vue +266 -46
  96. package/components/searchBox/index.js +1 -3
  97. package/components/searchBox/index.vue +194 -101
  98. package/components/skeleton/index.vue +45 -20
  99. package/components/slider/index.vue +319 -156
  100. package/components/swiper/index.vue +237 -108
  101. package/components/table/crud/footer.vue +77 -53
  102. package/components/table/crud/header.vue +71 -72
  103. package/components/table/crud/index.vue +629 -399
  104. package/components/table/index.vue +721 -278
  105. package/components/timeAgo/index.vue +145 -96
  106. package/components/tour/index.vue +338 -235
  107. package/components/tree/index.vue +235 -89
  108. package/components/tree/tree-element.vue +106 -106
  109. package/directive/animate/index.js +77 -0
  110. package/directive/clickOutSide/index.js +98 -0
  111. package/directive/drag/index.js +153 -0
  112. package/directive/index.js +11 -13
  113. package/directive/intersect/index.js +263 -0
  114. package/directive/mask/index.js +67 -0
  115. package/directive/parallax/index.js +78 -0
  116. package/directive/ripple/index.js +14 -0
  117. package/directive/scroll/index.js +272 -24
  118. package/directive/sortable/index.js +274 -0
  119. package/directive/title/index.js +75 -0
  120. package/directive/touch/index.js +268 -0
  121. package/index.js +11 -19
  122. package/package.json +5 -2
  123. package/plugins/validation/Validate.js +88 -79
  124. package/scripts/generate-docs.mjs +226 -0
  125. package/scripts/menu.mjs +240 -0
  126. package/scripts/parser.mjs +1086 -0
  127. package/style/_index.scss +7 -0
  128. package/style/app.scss +13 -65
  129. package/style/colors.scss +5 -22
  130. package/style/functions/index.scss +8 -0
  131. package/style/mixins/index.scss +17 -5
  132. package/style/variables/base.scss +155 -178
  133. package/style/variables/color.scss +0 -12
  134. package/style/variables/utilities.scss +0 -180
  135. package/tools/helper.js +0 -8
  136. package/tools/icons.js +7 -2
  137. package/tools/root.js +71 -0
  138. package/components/app/style.scss +0 -41
  139. package/components/app/toast/style.scss +0 -20
  140. package/components/avatar/style.scss +0 -32
  141. package/components/bar/bottomNav.js +0 -1
  142. package/components/bar/bottomNav.vue +0 -28
  143. package/components/bar/bottomNavigationCircle.js +0 -2
  144. package/components/bar/bottomNavigationCircle.vue +0 -99
  145. package/components/bar/scss/bottomNav.scss +0 -67
  146. package/components/bar/scss/toolbar.scss +0 -174
  147. package/components/bar/toolbar/index.js +0 -8
  148. package/components/bar/toolbar/index.vue +0 -35
  149. package/components/bar/toolbar/laptop.vue +0 -33
  150. package/components/bar/toolbar/menuChilds.vue +0 -41
  151. package/components/bar/toolbar/menuLaptop.vue +0 -41
  152. package/components/bar/toolbar/menuMob.vue +0 -39
  153. package/components/bar/toolbar/mixin.js +0 -43
  154. package/components/bar/toolbar/mobile.vue +0 -34
  155. package/components/breadcrumb/bredcrumbItem.vue +0 -39
  156. package/components/breadcrumb/index.js +0 -3
  157. package/components/breadcrumb/index.vue +0 -71
  158. package/components/breadcrumb/style.scss +0 -51
  159. package/components/button/style.scss +0 -411
  160. package/components/card/style.scss +0 -86
  161. package/components/chart/chart.js +0 -1
  162. package/components/chart/chart.vue +0 -69
  163. package/components/chart/worldMap.js +0 -2
  164. package/components/chart/worldMap.vue +0 -1112
  165. package/components/chat/MessageList.vue +0 -163
  166. package/components/chat/chatInput.vue +0 -150
  167. package/components/chat/chatMsg.vue +0 -276
  168. package/components/chat/index.js +0 -11
  169. package/components/chat/index.vue +0 -113
  170. package/components/chip/index.js +0 -3
  171. package/components/chip/index.vue +0 -77
  172. package/components/chip/style.scss +0 -199
  173. package/components/codeEditor/mixin.js +0 -145
  174. package/components/countdown/index.js +0 -1
  175. package/components/countdown/index.vue +0 -105
  176. package/components/form/colorInput/mixin.js +0 -132
  177. package/components/form/fileInput/file.js +0 -148
  178. package/components/form/telInput/assets/flags.png +0 -0
  179. package/components/form/telInput/assets/flags@2x.png +0 -0
  180. package/components/form/text-editor/index.vue +0 -705
  181. package/components/icon/style.scss +0 -17
  182. package/components/infinite/div.js +0 -6
  183. package/components/infinite/div.vue +0 -193
  184. package/components/infinite/page.js +0 -3
  185. package/components/infinite/page.vue +0 -105
  186. package/components/list/index.js +0 -3
  187. package/components/list/index.vue +0 -122
  188. package/components/list/style.scss +0 -66
  189. package/components/message/index.js +0 -4
  190. package/components/message/index.vue +0 -40
  191. package/components/modal/style.scss +0 -146
  192. package/components/nestable/NestableItem.vue +0 -307
  193. package/components/nestable/editable.js +0 -44
  194. package/components/nestable/index.js +0 -1
  195. package/components/nestable/index.vue +0 -226
  196. package/components/nestable/methods.js +0 -416
  197. package/components/progress/style.scss +0 -229
  198. package/components/table/style.scss +0 -338
  199. package/components/tabs/index.js +0 -3
  200. package/components/tabs/index.vue +0 -151
  201. package/components/timeline/index.js +0 -6
  202. package/components/timeline/index.vue +0 -76
  203. package/directive/resize/index.js +0 -30
  204. package/directive/skeleton/index.js +0 -27
  205. package/directive/skeleton/style.scss +0 -37
  206. package/plugins/request/Request.js +0 -68
  207. package/style/animation.scss +0 -94
  208. package/style/style.scss +0 -8
  209. package/tools/rootable.js +0 -75
  210. /package/components/form/{text-editor → textEditor}/index.js +0 -0
  211. /package/components/form/{text-editor → textEditor}/preview.js +0 -0
  212. /package/components/form/{text-editor → textEditor}/preview.vue +0 -0
@@ -0,0 +1,1086 @@
1
+ /**
2
+ * @typedef {Object} ComponentProp
3
+ * @property {string} name - Prop name
4
+ * @property {string} [description] - Prop description from JSDoc
5
+ * @property {string} [type] - Prop type
6
+ * @property {string} [default] - Default value
7
+ */
8
+
9
+ /**
10
+ * @typedef {Object} ComponentEmit
11
+ * @property {string} name - Emit name
12
+ * @property {string} [description] - Emit description
13
+ * @property {string} [params] - Formatted parameter documentation
14
+ */
15
+
16
+ /**
17
+ * @typedef {Object} ComponentSlot
18
+ * @property {string} name - Slot name (defaults to 'default')
19
+ * @property {string} [description] - Slot description from HTML comment
20
+ * @property {string} [props] - Props passed to the slot
21
+ */
22
+
23
+ /**
24
+ * @typedef {Object} ComponentExpose
25
+ * @property {string} name - Exposed property name
26
+ * @property {string} [description] - Description from JSDoc
27
+ */
28
+
29
+ /**
30
+ * @typedef {Object} ComponentProvide
31
+ * @property {string} name - Provide key name
32
+ * @property {string} [description] - Description from JSDoc
33
+ * @property {string} [value] - Provided value (simplified)
34
+ */
35
+
36
+ /**
37
+ * @typedef {Object} ComponentAPI
38
+ * @property {ComponentProp[]} props - Component props
39
+ * @property {ComponentEmit[]} emits - Component emits
40
+ * @property {ComponentSlot[]} slots - Component slots
41
+ * @property {ComponentExpose[]} expose - Exposed properties
42
+ * @property {ComponentProvide[]} provide - Provided values
43
+ */
44
+
45
+ /**
46
+ * Vue Composition API Parser
47
+ *
48
+ * Parses Vue 3 script setup components and extracts their public API.
49
+ */
50
+ export class VueComponentAPIParser {
51
+ /**
52
+ * Parse Vue component text and extract API information
53
+ * @param {string} componentText - Full component text including template and script
54
+ * @returns {ComponentAPI} Extracted component API
55
+ */
56
+ static parse(componentText) {
57
+ const parser = new VueComponentAPIParser();
58
+ return parser.parseComponent(componentText);
59
+ }
60
+
61
+ /**
62
+ * Parse component text
63
+ * @param {string} componentText - Full component text
64
+ * @returns {ComponentAPI}
65
+ */
66
+ parseComponent(componentText) {
67
+ const scriptContent = this.extractScriptContent(componentText);
68
+ const templateContent = this.extractTemplateContent(componentText);
69
+
70
+ return {
71
+ example: this.parseExample(componentText),
72
+ props: this.parseProps(scriptContent),
73
+ emits: this.parseEmits(scriptContent),
74
+ slots: this.parseSlots(templateContent),
75
+ expose: this.parseExpose(scriptContent),
76
+ provide: this.parseProvide(scriptContent)
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Extract script setup content
82
+ * @param {string} componentText - Full component text
83
+ * @returns {string} Script content
84
+ * @private
85
+ */
86
+ extractScriptContent(componentText) {
87
+ const match = componentText.match(/<script[^>]*setup[^>]*>([\s\S]*?)<\/script>/);
88
+ return match ? match[1] : '';
89
+ }
90
+
91
+ /**
92
+ * Extract template content
93
+ * @param {string} componentText - Full component text
94
+ * @returns {string} Template content
95
+ * @private
96
+ */
97
+ extractTemplateContent(componentText) {
98
+ const match = componentText.match(/<template>([\s\S]*?)<\/template>/);
99
+ return match ? match[1] : '';
100
+ }
101
+
102
+ /**
103
+ * Parse example from the beginning of the file
104
+ * @param {string} componentText - Full component text
105
+ * @returns {Object} Object with example names as keys and {template, script, style} objects as values
106
+ * @private
107
+ */
108
+ parseExample(componentText) {
109
+ const examples = {};
110
+
111
+ // Look for the first JSDoc comment in the file
112
+ const firstJsdocMatch = componentText.match(/\/\*\*([\s\S]*?)\*\//);
113
+
114
+ if (!firstJsdocMatch) return examples;
115
+
116
+ const jsdocContent = firstJsdocMatch[1];
117
+
118
+ // Find all @example sections
119
+ const exampleRegex = /@example\s*\/\/\s*([^\n]+)([\s\S]*?)(?=@example|\*\/)/g;
120
+ let match;
121
+
122
+ while ((match = exampleRegex.exec(jsdocContent)) !== null) {
123
+ const exampleName = match[1].trim();
124
+ let exampleContent = match[2].trim();
125
+
126
+ // Clean the content - remove leading * from each line
127
+ exampleContent = this.cleanJsDocLines(exampleContent);
128
+
129
+ const exampleObj = this.parseExampleContent(exampleContent);
130
+ examples[exampleName] = exampleObj;
131
+ }
132
+
133
+ // Also handle the last example if it doesn't end with another @example
134
+ const lastExampleRegex = /@example\s*\/\/\s*([^\n]+)([\s\S]*)/;
135
+ const lastMatch = jsdocContent.match(lastExampleRegex);
136
+
137
+ if (lastMatch && !examples[lastMatch[1].trim()]) {
138
+ const exampleName = lastMatch[1].trim();
139
+ let exampleContent = lastMatch[2].replace(/\*\//, '').trim();
140
+
141
+ exampleContent = this.cleanJsDocLines(exampleContent);
142
+ const exampleObj = this.parseExampleContent(exampleContent);
143
+ examples[exampleName] = exampleObj;
144
+ }
145
+
146
+ return examples;
147
+ }
148
+
149
+ /**
150
+ * Clean JSDoc lines by removing leading * and trimming
151
+ * @param {string} content - Content with JSDoc markers
152
+ * @returns {string} Cleaned content
153
+ * @private
154
+ */
155
+ cleanJsDocLines(content) {
156
+ return content
157
+ .split('\n')
158
+ .map(line => line.replace(/^\s*\*\s?/, '').trim())
159
+ .filter(line => line !== '')
160
+ .join('\n');
161
+ }
162
+
163
+ /**
164
+ * Parse example content into template, script, and style parts
165
+ * @param {string} content - Raw example content
166
+ * @returns {Object} Object with template, script, and style properties
167
+ * @private
168
+ */
169
+ parseExampleContent(content) {
170
+ const result = {
171
+ template: '',
172
+ script: '',
173
+ style: ''
174
+ };
175
+
176
+ // Fix malformed script tags
177
+ content = content.replace(/<\/\/script>/g, '</script>');
178
+
179
+ // First, check if the content has <template> tags
180
+ const templateStart = content.indexOf('<template>');
181
+ let templateContent = '';
182
+
183
+ if (templateStart !== -1) {
184
+ // Find the closing </template> tag
185
+ const templateEnd = this.findTagEnd(content, templateStart, 'template');
186
+ if (templateEnd !== -1) {
187
+ // Get the content inside <template> tags
188
+ const templateTagEnd = content.indexOf('>', templateStart) + 1;
189
+ templateContent = content.substring(templateTagEnd, templateEnd).trim();
190
+ }
191
+ } else {
192
+ // No <template> tags, extract everything before script or style
193
+ let templateEnd = content.length;
194
+ const scriptStart = content.indexOf('<script');
195
+ const styleStart = content.indexOf('<style');
196
+
197
+ if (scriptStart !== -1) templateEnd = Math.min(templateEnd, scriptStart);
198
+ if (styleStart !== -1) templateEnd = Math.min(templateEnd, styleStart);
199
+
200
+ // Also look for JavaScript keywords that might indicate script start without tags
201
+ const jsKeywords = ['import ', 'export ', 'const ', 'let ', 'var ', 'function ', 'class '];
202
+ for (const keyword of jsKeywords) {
203
+ const idx = content.indexOf(keyword);
204
+ if (idx !== -1 && idx < templateEnd) {
205
+ templateEnd = idx;
206
+ break;
207
+ }
208
+ }
209
+
210
+ templateContent = content.substring(0, templateEnd).trim();
211
+ }
212
+
213
+ result.template = templateContent;
214
+
215
+ // Extract script content
216
+ const scriptStart = content.indexOf('<script');
217
+ if (scriptStart !== -1) {
218
+ // Find the end of the script tag
219
+ let scriptEnd = this.findTagEnd(content, scriptStart, 'script');
220
+ if (scriptEnd !== -1) {
221
+ // Get content between <script> and </script>
222
+ const scriptTagEnd = content.indexOf('>', scriptStart) + 1;
223
+ result.script = content.substring(scriptTagEnd, scriptEnd).trim();
224
+ }
225
+ } else {
226
+ // Look for script content without tags - after the template content
227
+ const afterTemplate = content.substring(content.indexOf(templateContent) + templateContent.length).trim();
228
+ if (afterTemplate && !afterTemplate.startsWith('<style')) {
229
+ // Check if it looks like script
230
+ let isScript = false;
231
+ const jsKeywords = ['import ', 'export ', 'const ', 'let ', 'var ', 'function ', 'class '];
232
+ for (const keyword of jsKeywords) {
233
+ if (afterTemplate.includes(keyword)) {
234
+ isScript = true;
235
+ break;
236
+ }
237
+ }
238
+ if (isScript) {
239
+ result.script = afterScriptTag.trim();
240
+ }
241
+ }
242
+ }
243
+
244
+ // Extract style content
245
+ const styleStart = content.indexOf('<style');
246
+ if (styleStart !== -1) {
247
+ let styleEnd = this.findTagEnd(content, styleStart, 'style');
248
+ if (styleEnd !== -1) {
249
+ const styleTagEnd = content.indexOf('>', styleStart) + 1;
250
+ result.style = content.substring(styleTagEnd, styleEnd).trim();
251
+ }
252
+ }
253
+
254
+ // Clean indentation
255
+ result.template = this.cleanIndentation(result.template);
256
+ result.script = this.cleanIndentation(result.script);
257
+ result.style = this.cleanIndentation(result.style);
258
+
259
+ return result;
260
+ }
261
+
262
+ /**
263
+ * Find the end position of a tag (closing tag)
264
+ * @param {string} content - Full content
265
+ * @param {number} startIndex - Start index of opening tag
266
+ * @param {string} tagName - Tag name
267
+ * @returns {number} End index or -1 if not found
268
+ * @private
269
+ */
270
+ findTagEnd(content, startIndex, tagName) {
271
+ const openingTag = `<${tagName}`;
272
+ const closingTag = `</${tagName}>`;
273
+
274
+ // Find the end of the opening tag
275
+ let tagEnd = content.indexOf('>', startIndex);
276
+ if (tagEnd === -1) return -1;
277
+
278
+ // Now look for the closing tag
279
+ let depth = 0;
280
+ let pos = tagEnd + 1;
281
+
282
+ while (pos < content.length) {
283
+ // Check for nested opening tags
284
+ const nextOpen = content.indexOf(openingTag, pos);
285
+ const nextClose = content.indexOf(closingTag, pos);
286
+
287
+ // If no closing tag found, return -1
288
+ if (nextClose === -1) return -1;
289
+
290
+ // If there's an opening tag before the closing tag, we have nesting
291
+ if (nextOpen !== -1 && nextOpen < nextClose) {
292
+ depth++;
293
+ pos = content.indexOf('>', nextOpen) + 1;
294
+ } else {
295
+ if (depth === 0) {
296
+ return nextClose;
297
+ }
298
+ depth--;
299
+ pos = nextClose + closingTag.length;
300
+ }
301
+ }
302
+
303
+ return -1;
304
+ }
305
+
306
+
307
+ /**
308
+ * Clean indentation from example content
309
+ * @param {string} content - Content with possible indentation
310
+ * @returns {string} Cleaned content
311
+ * @private
312
+ */
313
+ cleanIndentation(content) {
314
+ if (!content || content.trim() === '') return '';
315
+
316
+ const lines = content.split('\n');
317
+
318
+ // Find minimum indentation of non-empty lines
319
+ let minIndent = Infinity;
320
+ for (const line of lines) {
321
+ if (line.trim().length === 0) continue;
322
+ const leadingSpaces = line.match(/^(\s*)/)[0].length;
323
+ minIndent = Math.min(minIndent, leadingSpaces);
324
+ }
325
+
326
+ if (minIndent === Infinity) minIndent = 0;
327
+
328
+ // Remove minimum indentation from all lines
329
+ const cleanedLines = lines.map(line => {
330
+ if (line.trim().length === 0) return line;
331
+ if (line.length >= minIndent) {
332
+ return line.substring(minIndent);
333
+ }
334
+ return line;
335
+ });
336
+
337
+ // Remove leading and trailing empty lines
338
+ let start = 0;
339
+ let end = cleanedLines.length - 1;
340
+
341
+ while (start < cleanedLines.length && cleanedLines[start].trim() === '') start++;
342
+ while (end >= 0 && cleanedLines[end].trim() === '') end--;
343
+
344
+ if (start > end) return '';
345
+
346
+ return cleanedLines.slice(start, end + 1).join('\n').trim();
347
+ }
348
+
349
+ /**
350
+ * Parse props from script content
351
+ * @param {string} scriptContent - Script setup content
352
+ * @returns {ComponentProp[]}
353
+ * @private
354
+ */
355
+ parseProps(scriptContent) {
356
+ const props = [];
357
+ const propsMatch = scriptContent.match(/defineProps\s*\(\s*\{([\s\S]*?)\}\s*\)/);
358
+
359
+ if (!propsMatch) return props;
360
+
361
+ const propsContent = propsMatch[1];
362
+ const lines = propsContent.split('\n');
363
+
364
+ let currentJsdoc = null;
365
+ let braceDepth = 0;
366
+
367
+ for (let i = 0; i < lines.length; i++) {
368
+ const line = lines[i].trim();
369
+
370
+ // Track JSDoc comments
371
+ if (line.startsWith('/**')) {
372
+ currentJsdoc = this.collectJSDoc(lines, i);
373
+ i = currentJsdoc.endLine;
374
+ continue;
375
+ }
376
+
377
+ // Check for prop definition
378
+ const propMatch = line.match(/^(\w+)\s*:/);
379
+ if (propMatch && braceDepth === 0) {
380
+ const propName = propMatch[1];
381
+
382
+ // Parse prop value (could be simple type or object)
383
+ const propValue = line.slice(propMatch[0].length).trim();
384
+ const propInfo = this.parsePropDefinition(propValue, lines, i);
385
+
386
+ props.push({
387
+ name: propName,
388
+ description: currentJsdoc ? this.cleanJSDocText(currentJsdoc.text) : undefined,
389
+ type: propInfo.type,
390
+ default: propInfo.default
391
+ });
392
+
393
+ currentJsdoc = null;
394
+ }
395
+
396
+ // Track brace depth for nested objects
397
+ braceDepth += (line.match(/{/g) || []).length;
398
+ braceDepth -= (line.match(/}/g) || []).length;
399
+ }
400
+
401
+ return props;
402
+ }
403
+
404
+ /**
405
+ * Parse a single prop definition
406
+ * @param {string} propValue - Prop value string
407
+ * @param {string[]} lines - All lines
408
+ * @param {number} startLine - Starting line index
409
+ * @returns {{type: string, default: string}}
410
+ * @private
411
+ */
412
+ parsePropDefinition(propValue, lines, startLine) {
413
+ const result = {type: '', default: 'undefined'};
414
+
415
+ // Helper function to clean and normalize type string
416
+ const normalizeType = (typeStr) => {
417
+ return typeStr.trim().replace(/,$/, '').replace(/\s+/g, ' ');
418
+ };
419
+
420
+ // If it's a simple type (Boolean, String, etc.)
421
+ if (!propValue.startsWith('{')) {
422
+ result.type = normalizeType(propValue);
423
+ return result;
424
+ }
425
+
426
+ // Parse prop configuration object
427
+ let configContent = propValue;
428
+ let braceCount = (propValue.match(/{/g) || []).length - (propValue.match(/}/g) || []).length;
429
+ let lineIndex = startLine;
430
+
431
+ // Collect multi-line prop configuration
432
+ while (braceCount > 0 && lineIndex + 1 < lines.length) {
433
+ lineIndex++;
434
+ const nextLine = lines[lineIndex];
435
+ configContent += '\n' + nextLine;
436
+ braceCount += (nextLine.match(/{/g) || []).length;
437
+ braceCount -= (nextLine.match(/}/g) || []).length;
438
+ }
439
+
440
+ // Now parse the config object properties
441
+ // Remove the outer braces
442
+ const innerContent = configContent.substring(1, configContent.lastIndexOf('}')).trim();
443
+
444
+ // Split by properties (looking for key: value pairs)
445
+ // This is a simplified parser - we'll look for type and default specifically
446
+ const properties = [];
447
+ let currentProp = '';
448
+ let inBrackets = 0;
449
+ let inBraces = 0;
450
+ let inParens = 0;
451
+ let inString = false;
452
+ let stringChar = '';
453
+
454
+ for (let i = 0; i < innerContent.length; i++) {
455
+ const char = innerContent[i];
456
+ const prevChar = i > 0 ? innerContent[i - 1] : '';
457
+
458
+ // Handle strings
459
+ if (!inString && (char === "'" || char === '"' || char === '`')) {
460
+ inString = true;
461
+ stringChar = char;
462
+ } else if (inString && char === stringChar && prevChar !== '\\') {
463
+ inString = false;
464
+ }
465
+
466
+ // Only track brackets/braces/parens when not in a string
467
+ if (!inString) {
468
+ if (char === '[') inBrackets++;
469
+ else if (char === ']') inBrackets--;
470
+ else if (char === '{') inBraces++;
471
+ else if (char === '}') inBraces--;
472
+ else if (char === '(') inParens++;
473
+ else if (char === ')') inParens--;
474
+ }
475
+
476
+ // Check for property separator (comma) at top level
477
+ if (char === ',' && !inString && inBrackets === 0 && inBraces === 0 && inParens === 0) {
478
+ if (currentProp.trim()) {
479
+ properties.push(currentProp.trim());
480
+ currentProp = '';
481
+ }
482
+ } else {
483
+ currentProp += char;
484
+ }
485
+ }
486
+
487
+ // Add the last property
488
+ if (currentProp.trim()) {
489
+ properties.push(currentProp.trim());
490
+ }
491
+
492
+ // Now parse each property
493
+ for (const prop of properties) {
494
+ const colonIndex = prop.indexOf(':');
495
+ if (colonIndex === -1) continue;
496
+
497
+ const key = prop.substring(0, colonIndex).trim();
498
+ const value = prop.substring(colonIndex + 1).trim();
499
+
500
+ if (key === 'type') {
501
+ let typeValue = value;
502
+
503
+ // Clean up trailing comma if present
504
+ typeValue = typeValue.replace(/,$/, '').trim();
505
+
506
+ // Parse the type
507
+ result.type = this.parseTypeValue(typeValue);
508
+ } else if (key === 'default') {
509
+ let defaultValue = value;
510
+
511
+ // Clean up trailing comma if present
512
+ defaultValue = defaultValue.replace(/,$/, '').trim();
513
+
514
+ // Handle quoted strings
515
+ if ((defaultValue.startsWith("'") && defaultValue.endsWith("'")) ||
516
+ (defaultValue.startsWith('"') && defaultValue.endsWith('"'))) {
517
+ result.default = defaultValue.substring(1, defaultValue.length - 1);
518
+ } else {
519
+ result.default = defaultValue;
520
+ }
521
+ }
522
+ }
523
+
524
+ return result;
525
+ }
526
+
527
+ /**
528
+ * Parse type value from prop definition
529
+ * @param {string} typeValue - Raw type value
530
+ * @returns {string} Formatted type
531
+ * @private
532
+ */
533
+ parseTypeValue(typeValue) {
534
+ // Clean the value
535
+ typeValue = typeValue.trim();
536
+
537
+ // Handle array types: [String, Number]
538
+ if (typeValue.startsWith('[') && typeValue.endsWith(']')) {
539
+ const innerTypes = typeValue
540
+ .substring(1, typeValue.length - 1)
541
+ .split(',')
542
+ .map(t => t.trim())
543
+ .filter(t => t.length > 0);
544
+
545
+ if (innerTypes.length === 0) {
546
+ return 'Array';
547
+ } else if (innerTypes.length === 1) {
548
+ return innerTypes[0];
549
+ } else {
550
+ // For multiple types, show as union
551
+ return innerTypes.join(' | ');
552
+ }
553
+ }
554
+
555
+ // Handle union types
556
+ if (typeValue.includes('|')) {
557
+ const types = typeValue.split('|')
558
+ .map(t => t.trim())
559
+ .filter(t => t.length > 0);
560
+
561
+ if (types.length === 1) {
562
+ return types[0];
563
+ }
564
+ return types.join(' | ');
565
+ }
566
+
567
+ // Handle intersection types
568
+ if (typeValue.includes('&')) {
569
+ const types = typeValue.split('&')
570
+ .map(t => t.trim())
571
+ .filter(t => t.length > 0);
572
+
573
+ if (types.length === 1) {
574
+ return types[0];
575
+ }
576
+ return types.join(' & ');
577
+ }
578
+
579
+ // Handle common types
580
+ const typeMap = {
581
+ 'String': 'String',
582
+ 'Number': 'Number',
583
+ 'Boolean': 'Boolean',
584
+ 'Array': 'Array',
585
+ 'Object': 'Object',
586
+ 'Function': 'Function',
587
+ 'Symbol': 'Symbol',
588
+ 'Date': 'Date',
589
+ 'Promise': 'Promise',
590
+ 'RegExp': 'RegExp',
591
+ 'Error': 'Error'
592
+ };
593
+
594
+ return typeMap[typeValue] || typeValue;
595
+ }
596
+
597
+ /**
598
+ * Parse emits from script content
599
+ * @param {string} scriptContent - Script setup content
600
+ * @returns {ComponentEmit[]}
601
+ * @private
602
+ */
603
+ parseEmits(scriptContent) {
604
+ const emits = [];
605
+ const emitsMatch = scriptContent.match(/defineEmits\s*\(\s*\[([\s\S]*?)\]\s*\)/);
606
+
607
+ if (!emitsMatch) return emits;
608
+
609
+ const emitsContent = emitsMatch[1];
610
+ const lines = emitsContent.split('\n');
611
+
612
+ let currentJsdoc = null;
613
+
614
+ for (let i = 0; i < lines.length; i++) {
615
+ const line = lines[i].trim();
616
+
617
+ // Collect JSDoc
618
+ if (line.startsWith('/**')) {
619
+ currentJsdoc = this.collectJSDoc(lines, i);
620
+ i = currentJsdoc.endLine;
621
+ continue;
622
+ }
623
+
624
+ // Find emit names in quotes
625
+ const emitNames = this.extractQuotedStrings(line);
626
+
627
+ for (const emitName of emitNames) {
628
+ if (!emitName || emitName.includes('*')) continue;
629
+
630
+ const params = currentJsdoc ? this.extractJSDocParams(currentJsdoc.text) : null;
631
+
632
+ emits.push({
633
+ name: emitName,
634
+ description: currentJsdoc ? this.cleanJSDocText(currentJsdoc.text, true) : undefined,
635
+ params: params ? this.formatParams(params) : undefined
636
+ });
637
+ }
638
+
639
+ // Reset JSDoc after processing emits
640
+ if (emitNames.length > 0) {
641
+ currentJsdoc = null;
642
+ }
643
+ }
644
+
645
+ return emits.filter(emit => emit.name && emit.name.trim().length > 0);
646
+ }
647
+
648
+ /**
649
+ * Parse slots from template content
650
+ * @param {string} templateContent - Template content
651
+ * @returns {ComponentSlot[]}
652
+ * @private
653
+ */
654
+ parseSlots(templateContent) {
655
+ const slots = [];
656
+ if (!templateContent) return slots;
657
+
658
+ // Find all slot elements along with their preceding comments
659
+ const slotWithCommentRegex = /((?:<!--[\s\S]*?-->)?\s*)<slot\b([^>]*)>/g;
660
+ let match;
661
+
662
+ while ((match = slotWithCommentRegex.exec(templateContent)) !== null) {
663
+ const [fullMatch, whitespaceAndComment, slotAttrs] = match;
664
+ const slotName = this.extractSlotName(slotAttrs);
665
+ const slotProps = this.extractSlotProps(slotAttrs);
666
+
667
+ // Parse the comment if present
668
+ const commentMatch = whitespaceAndComment.match(/<!--([\s\S]*?)-->/);
669
+ let description = '';
670
+ let example = '';
671
+
672
+ if (commentMatch) {
673
+ const commentContent = commentMatch[1].trim();
674
+ const parsedComment = this.parseSlotComment(commentContent);
675
+ description = parsedComment.description;
676
+ example = parsedComment.example;
677
+ }
678
+
679
+ slots.push({
680
+ name: slotName,
681
+ description: description || undefined,
682
+ props: slotProps,
683
+ example: example || undefined
684
+ });
685
+ }
686
+
687
+ return slots;
688
+ }
689
+
690
+ /**
691
+ * Parse slot comment content to extract description and example
692
+ * @param {string} commentContent - Comment content without <!-- and -->
693
+ * @returns {{description: string, example: string}}
694
+ * @private
695
+ */
696
+ parseSlotComment(commentContent) {
697
+ let description = '';
698
+ let example = '';
699
+
700
+ // Split into lines and clean
701
+ const lines = commentContent.split('\n')
702
+ .map(line => line.trim())
703
+ .filter(line => line.length > 0);
704
+
705
+ // Remove leading * from each line if it's a JSDoc-style comment
706
+ const cleanedLines = lines.map(line => line.replace(/^\s*\*\s?/, ''));
707
+
708
+ // Join back and parse
709
+ const fullText = cleanedLines.join('\n');
710
+
711
+ // Split by @example tag
712
+ const parts = fullText.split(/@example\s*/);
713
+
714
+ if (parts.length > 0) {
715
+ description = parts[0].trim();
716
+
717
+ // If there's more content after @example
718
+ if (parts.length > 1) {
719
+ example = parts.slice(1).join('\n').trim();
720
+ }
721
+ }
722
+
723
+ return {description, example};
724
+ }
725
+
726
+ /**
727
+ * Extract slot name from attributes
728
+ * @param {string} attrs - Slot attributes string
729
+ * @returns {string}
730
+ * @private
731
+ */
732
+ extractSlotName(attrs) {
733
+ const nameMatch = attrs.match(/name\s*=\s*["']([^"']+)["']/);
734
+ return nameMatch ? nameMatch[1] : 'default';
735
+ }
736
+
737
+ /**
738
+ * Extract slot props from attributes
739
+ * @param {string} attrs - Slot attributes string
740
+ * @returns {string|undefined}
741
+ * @private
742
+ */
743
+ extractSlotProps(attrs) {
744
+ const props = [];
745
+
746
+ // Check for v-bind
747
+ const bindMatch = attrs.match(/v-bind\s*=\s*["']([^"']+)["']/);
748
+ if (bindMatch) {
749
+ return `v-bind="${bindMatch[1]}"`;
750
+ }
751
+
752
+ // Check for individual bindings
753
+ const bindingRegex = /:(\w+)\s*=\s*["']([^"']+)["']/g;
754
+ let bindingMatch;
755
+
756
+ while ((bindingMatch = bindingRegex.exec(attrs)) !== null) {
757
+ props.push(`${bindingMatch[1]}: ${bindingMatch[2]}`);
758
+ }
759
+
760
+ return props.length > 0 ? props.join(', ') : undefined;
761
+ }
762
+
763
+ /**
764
+ * Parse exposed properties
765
+ * @param {string} scriptContent - Script setup content
766
+ * @returns {ComponentExpose[]}
767
+ * @private
768
+ */
769
+ parseExpose(scriptContent) {
770
+ const exposed = [];
771
+
772
+ // Find defineExpose call
773
+ const exposeRegex = /defineExpose\s*\(\s*\{([\s\S]*?)\}\s*\)/;
774
+ const exposeMatch = scriptContent.match(exposeRegex);
775
+
776
+ if (!exposeMatch) return exposed;
777
+
778
+ const exposeContent = exposeMatch[1];
779
+ const lines = exposeContent.split('\n');
780
+
781
+ let currentJsdoc = null;
782
+ let inJsdoc = false;
783
+ let jsdocLines = [];
784
+
785
+ for (let i = 0; i < lines.length; i++) {
786
+ const line = lines[i].trim();
787
+
788
+ // Handle JSDoc comments
789
+ if (line.startsWith('/**')) {
790
+ inJsdoc = true;
791
+ jsdocLines = [line];
792
+
793
+ // Collect the rest of the JSDoc
794
+ let j = i + 1;
795
+ while (j < lines.length && !lines[j].includes('*/')) {
796
+ jsdocLines.push(lines[j]);
797
+ j++;
798
+ }
799
+
800
+ if (j < lines.length && lines[j].includes('*/')) {
801
+ jsdocLines.push(lines[j]);
802
+ i = j; // Skip to end of JSDoc
803
+ }
804
+
805
+ currentJsdoc = jsdocLines.join('\n');
806
+ continue;
807
+ }
808
+
809
+ // Skip empty lines and closing braces
810
+ if (!line || line === '}' || line === '},') {
811
+ continue;
812
+ }
813
+
814
+ // Handle property definitions
815
+ // This can be:
816
+ // 1. Simple property: propName,
817
+ // 2. Aliased property: alias:propName,
818
+ // 3. Method property: propName(),
819
+ const propertyMatch = this.matchExposedProperty(line);
820
+
821
+ if (propertyMatch) {
822
+ const {name, alias} = propertyMatch;
823
+
824
+ exposed.push({
825
+ name: alias || name,
826
+ description: currentJsdoc ? this.cleanJSDocText(currentJsdoc) : undefined
827
+ });
828
+
829
+ // Reset JSDoc for next property
830
+ currentJsdoc = null;
831
+ inJsdoc = false;
832
+ jsdocLines = [];
833
+ }
834
+
835
+ // If we're not in JSDoc and currentJsdoc exists but we didn't find a property,
836
+ // reset it (might be orphaned JSDoc)
837
+ if (!inJsdoc && currentJsdoc && !propertyMatch) {
838
+ // Check if this line has content that suggests the JSDoc wasn't for a property
839
+ if (line && !line.startsWith('*') && !line.startsWith('//')) {
840
+ currentJsdoc = null;
841
+ }
842
+ }
843
+ }
844
+
845
+ return exposed;
846
+ }
847
+
848
+ /**
849
+ * Match an exposed property from a line
850
+ * Handles: propName, alias:propName, propName(), alias:propName()
851
+ * @param {string} line - Line to parse
852
+ * @returns {{name: string, alias?: string}|null}
853
+ * @private
854
+ */
855
+ matchExposedProperty(line) {
856
+ // Remove trailing comma if present
857
+ let cleanLine = line.replace(/,$/, '').trim();
858
+
859
+ // Pattern 1: Simple property (propName)
860
+ const simplePropRegex = /^(\w+)$/;
861
+ let match = cleanLine.match(simplePropRegex);
862
+ if (match) {
863
+ return {name: match[1]};
864
+ }
865
+
866
+ // Pattern 2: Aliased property (alias:propName)
867
+ const aliasedPropRegex = /^(\w+)\s*:\s*(\w+)$/;
868
+ match = cleanLine.match(aliasedPropRegex);
869
+ if (match) {
870
+ return {name: match[2], alias: match[1]};
871
+ }
872
+
873
+ // Pattern 3: Method property (propName())
874
+ const methodPropRegex = /^(\w+)\(\s*\)$/;
875
+ match = cleanLine.match(methodPropRegex);
876
+ if (match) {
877
+ return {name: match[1]};
878
+ }
879
+
880
+ // Pattern 4: Aliased method property (alias:propName())
881
+ const aliasedMethodRegex = /^(\w+)\s*:\s*(\w+)\(\s*\)$/;
882
+ match = cleanLine.match(aliasedMethodRegex);
883
+ if (match) {
884
+ return {name: match[2], alias: match[1]};
885
+ }
886
+
887
+ // Pattern 5: Property with type annotation (propName: type)
888
+ // This might appear in TypeScript components
889
+ const typedPropRegex = /^(\w+)\s*:\s*\w+(?:<[^>]+>)?$/;
890
+ match = cleanLine.match(typedPropRegex);
891
+ if (match) {
892
+ return {name: match[1]};
893
+ }
894
+
895
+ // Pattern 6: Complex property (could be destructuring or computed)
896
+ // Look for any word that's not a JavaScript keyword
897
+ const wordMatch = cleanLine.match(/^(\w+)/);
898
+ if (wordMatch) {
899
+ const potentialName = wordMatch[1];
900
+ const jsKeywords = [
901
+ 'if', 'else', 'for', 'while', 'function', 'return', 'const', 'let', 'var',
902
+ 'import', 'export', 'default', 'class', 'extends', 'super', 'this', 'new',
903
+ 'typeof', 'instanceof', 'void', 'delete', 'in', 'of', 'await', 'async',
904
+ 'yield', 'debugger', 'with', 'switch', 'case', 'break', 'continue', 'try',
905
+ 'catch', 'finally', 'throw'
906
+ ];
907
+
908
+ if (!jsKeywords.includes(potentialName)) {
909
+ return {name: potentialName};
910
+ }
911
+ }
912
+
913
+ return null;
914
+ }
915
+
916
+ /**
917
+ * Parse provide statements
918
+ * @param {string} scriptContent - Script setup content
919
+ * @returns {ComponentProvide[]}
920
+ * @private
921
+ */
922
+ parseProvide(scriptContent) {
923
+ const provides = [];
924
+ const provideRegex = /provide\s*\(\s*['"]([^'"]+)['"]\s*,\s*([^);]+)/g;
925
+ let match;
926
+
927
+ while ((match = provideRegex.exec(scriptContent)) !== null) {
928
+ const name = match[1];
929
+ const value = match[2].trim();
930
+ const description = this.findPrecedingJSDoc(scriptContent, match.index);
931
+
932
+ provides.push({
933
+ name: name,
934
+ description: description ? this.cleanJSDocText(description) : undefined,
935
+ value: value.replace(/\s+/g, ' ').trim()
936
+ });
937
+ }
938
+
939
+ return provides;
940
+ }
941
+
942
+ /**
943
+ * Collect a complete JSDoc comment
944
+ * @param {string[]} lines - Array of lines
945
+ * @param {number} startLine - Starting line index
946
+ * @returns {{text: string, endLine: number}}
947
+ * @private
948
+ */
949
+ collectJSDoc(lines, startLine) {
950
+ let jsdocText = lines[startLine];
951
+ let currentLine = startLine;
952
+
953
+ while (currentLine < lines.length && !lines[currentLine].includes('*/')) {
954
+ currentLine++;
955
+ if (currentLine < lines.length) {
956
+ jsdocText += '\n' + lines[currentLine];
957
+ }
958
+ }
959
+
960
+ return {
961
+ text: jsdocText,
962
+ endLine: currentLine
963
+ };
964
+ }
965
+
966
+ /**
967
+ * Find JSDoc comment preceding a position
968
+ * @param {string} text - Full text
969
+ * @param {number} position - Position to search before
970
+ * @returns {string|null}
971
+ * @private
972
+ */
973
+ findPrecedingJSDoc(text, position) {
974
+ const before = text.substring(0, position);
975
+ const lines = before.split('\n');
976
+
977
+ for (let i = lines.length - 1; i >= 0; i--) {
978
+ if (lines[i].includes('/**')) {
979
+ // Collect the complete comment
980
+ let jsdoc = lines[i];
981
+ let j = i + 1;
982
+
983
+ while (j < lines.length && !lines[j].includes('*/')) {
984
+ jsdoc += '\n' + lines[j];
985
+ j++;
986
+ }
987
+
988
+ if (j < lines.length && lines[j].includes('*/')) {
989
+ jsdoc += '\n' + lines[j];
990
+ }
991
+
992
+ return jsdoc;
993
+ }
994
+ }
995
+
996
+ return null;
997
+ }
998
+
999
+ /**
1000
+ * Clean JSDoc text
1001
+ * @param {string} jsdocText - Raw JSDoc text
1002
+ * @param {boolean} removeParams - Whether to remove @param tags
1003
+ * @returns {string}
1004
+ * @private
1005
+ */
1006
+ cleanJSDocText(jsdocText, removeParams = false) {
1007
+ if (!jsdocText) return '';
1008
+
1009
+ // Extract content between /** and */
1010
+ const match = jsdocText.match(/\/\*\*\s*([\s\S]*?)\s*\*\//);
1011
+ if (!match) return '';
1012
+
1013
+ let content = match[1];
1014
+
1015
+ // Remove leading * from each line and trim
1016
+ const lines = content.split('\n');
1017
+ const cleanedLines = lines.map(line => {
1018
+ return line.replace(/^\s*\*\s?/, '').trim();
1019
+ }).filter(line => line.length > 0);
1020
+
1021
+ // Join and optionally remove @param tags
1022
+ let result = cleanedLines.join(' ').trim();
1023
+
1024
+ if (removeParams) {
1025
+ result = result.replace(/@param\s+\{[^}]+\}\s+\w+(?:\s+-\s+[^@]*)?/g, '').trim();
1026
+ }
1027
+
1028
+ return result;
1029
+ }
1030
+
1031
+ /**
1032
+ * Extract @param tags from JSDoc
1033
+ * @param {string} jsdocText - JSDoc text
1034
+ * @returns {Array<{type: string, name: string, description: string}>}
1035
+ * @private
1036
+ */
1037
+ extractJSDocParams(jsdocText) {
1038
+ const params = [];
1039
+ const paramRegex = /@param\s+{([^}]+)}\s+([^\s-]+)(?:\s+-\s+(.*))?/g;
1040
+ let match;
1041
+
1042
+ while ((match = paramRegex.exec(jsdocText)) !== null) {
1043
+ params.push({
1044
+ type: match[1].trim(),
1045
+ name: match[2].trim(),
1046
+ description: match[3] ? match[3].trim() : ''
1047
+ });
1048
+ }
1049
+
1050
+ return params;
1051
+ }
1052
+
1053
+ /**
1054
+ * Format parameters for display
1055
+ * @param {Array<{type: string, name: string, description: string}>} params
1056
+ * @returns {string}
1057
+ * @private
1058
+ */
1059
+ formatParams(params) {
1060
+ return params.map(param =>
1061
+ `@param {${param.type}} ${param.name}${param.description ? ` - ${param.description}` : ''}`
1062
+ ).join('\n');
1063
+ }
1064
+
1065
+ /**
1066
+ * Extract quoted strings from text
1067
+ * @param {string} text - Text to search
1068
+ * @returns {string[]}
1069
+ * @private
1070
+ */
1071
+ extractQuotedStrings(text) {
1072
+ const strings = [];
1073
+ const regex = /['"]([^'"]+)['"]/g;
1074
+ let match;
1075
+
1076
+ while ((match = regex.exec(text)) !== null) {
1077
+ strings.push(match[1]);
1078
+ }
1079
+
1080
+ return strings;
1081
+ }
1082
+ }
1083
+
1084
+ if (typeof module !== 'undefined' && module.exports) {
1085
+ module.exports = VueComponentAPIParser;
1086
+ }