@texturehq/edges 1.26.5 → 1.26.7

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/styles.css CHANGED
@@ -6171,6 +6171,11 @@
6171
6171
  position: relative;
6172
6172
  }
6173
6173
  }
6174
+ .md\:z-10 {
6175
+ @media (width >= 48rem) {
6176
+ z-index: 10;
6177
+ }
6178
+ }
6174
6179
  .md\:order-1 {
6175
6180
  @media (width >= 48rem) {
6176
6181
  order: 1;
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.26.5",
2
+ "version": "1.26.7",
3
3
  "categories": {
4
4
  "hooks": {
5
5
  "description": "React hooks for common functionality like breakpoints, debouncing, local storage, and media queries",
@@ -14,28 +14,28 @@
14
14
  {
15
15
  "name": "useBreakpoint",
16
16
  "type": "function",
17
- "description": "Hook to detect which Tailwind breakpoint is currently active Returns an object with boolean flags for each breakpoint and convenience helpers. All breakpoints use min-width queries to match Tailwind's mobile-first approach. ```tsx const { isMobile, isDesktop, current } = useBreakpoint(); // Conditional rendering based on screen size return isMobile ? <MobileNav /> : <DesktopNav />; // Check specific breakpoint if (isLg) { // Show expanded view on large screens } // Use current breakpoint console.log(`Current breakpoint: ${current}`); // \"md\", \"lg\", etc. ```",
17
+ "description": "Hook to detect which Tailwind breakpoint is currently active Returns an object with boolean flags for each breakpoint and convenience helpers. All breakpoints use min-width queries to match Tailwind's mobile-first approach.",
18
18
  "category": "hooks",
19
19
  "file": "hooks/useBreakpoint.ts"
20
20
  },
21
21
  {
22
22
  "name": "useChartExport",
23
23
  "type": "function",
24
- "description": "Hook for exporting chart data in various formats (CSV, SVG, PNG). Provides a stable callback for triggering exports with memoized dependencies. ```tsx const svgRef = useRef<SVGSVGElement>(null); const handleExport = useChartExport({ datasets: chartData, metadata: { xLabel: 'Date', yLabel: 'Value', seriesLabels: ['Series 1', 'Series 2'], filename: 'sales-report', timestamp: true }, svgRef }); // In your component <Button onPress={() => handleExport('csv')}>Export CSV</Button> <Button onPress={() => handleExport('png')}>Export PNG</Button> ```",
24
+ "description": "Hook for exporting chart data in various formats (CSV, SVG, PNG). Provides a stable callback for triggering exports with memoized dependencies.",
25
25
  "category": "hooks",
26
26
  "file": "hooks/useChartExport.ts"
27
27
  },
28
28
  {
29
29
  "name": "useClientDataControls",
30
30
  "type": "function",
31
- "description": "useClientDataControls Client-side hook for filtering, sorting, searching, and faceting data. Uses memoization to avoid unnecessary recomputation. Operations are applied in this order: 1. Search (fuzzy or exact matching) 2. Filter (structured conditions) 3. Facet computation (on filtered data) 4. Sort ```tsx const { data, facetCounts, resultCount } = useClientDataControls({ data: rawData, filters: createFilters([ createFilter('department', 'in', ['Engineering', 'Sales']) ]), sort: { field: 'name', direction: 'asc' }, search: { query: searchQuery, fields: ['name', 'email'] }, facetConfigs: [ { field: 'department', label: 'Department' }, { field: 'status', label: 'Status' } ] }); ```",
31
+ "description": "useClientDataControls Client-side hook for filtering, sorting, searching, and faceting data. Uses memoization to avoid unnecessary recomputation. Operations are applied in this order: 1. Search (fuzzy or exact matching) 2. Filter (structured conditions) 3. Facet computation (on filtered data) 4. Sort",
32
32
  "category": "hooks",
33
33
  "file": "hooks/useClientDataControls.ts"
34
34
  },
35
35
  {
36
36
  "name": "useDataControls",
37
37
  "type": "function",
38
- "description": "useDataControls Unified hook for managing data filtering, sorting, searching, and faceting. Supports both client-side and server-side modes. **Client Mode:** - Processes data locally using pure functions - Computes facet counts automatically - Best for datasets < 5000 rows **Server Mode:** - Notifies parent when state changes (debounced for search) - Passes through server-provided data and counts - Best for large datasets or complex queries ```tsx const { data, facetCounts, resultCount } = useDataControls({ mode: 'client', data: rawData, filters: createFilters([...]), sort: { field: 'name', direction: 'asc' }, search: { query: searchQuery, fields: ['name', 'email'] }, facetConfigs: [{ field: 'department', label: 'Department' }] }); ``` ```tsx const { data, facetCounts, resultCount } = useDataControls({ mode: 'server', data: serverData, // Already filtered filters, sort, search, resultCount: totalCount, facetCounts: serverFacets, onStateChange: (state) => refetch(state) }); ```",
38
+ "description": "useDataControls Unified hook for managing data filtering, sorting, searching, and faceting. Supports both client-side and server-side modes. **Client Mode:** - Processes data locally using pure functions - Computes facet counts automatically - Best for datasets < 5000 rows **Server Mode:** - Notifies parent when state changes (debounced for search) - Passes through server-provided data and counts - Best for large datasets or complex queries",
39
39
  "category": "hooks",
40
40
  "file": "hooks/useDataControls.ts"
41
41
  },
@@ -56,14 +56,14 @@
56
56
  {
57
57
  "name": "useElementSize",
58
58
  "type": "function",
59
- "description": "useElementSize A performant hook that tracks the dimensions of a DOM element using ResizeObserver. Returns a callback ref to attach to the element and its current width/height. Performance optimizations: - Uses ResizeObserver for efficient resize detection - Debounces updates using requestAnimationFrame - Cleans up observer on unmount ```tsx const { ref, width, height } = useElementSize(); return ( <div ref={ref}> Width: {width}px, Height: {height}px </div> ); ```",
59
+ "description": "useElementSize A performant hook that tracks the dimensions of a DOM element using ResizeObserver. Returns a callback ref to attach to the element and its current width/height. Performance optimizations: - Uses ResizeObserver for efficient resize detection - Debounces updates using requestAnimationFrame - Cleans up observer on unmount",
60
60
  "category": "hooks",
61
61
  "file": "hooks/useElementSize.ts"
62
62
  },
63
63
  {
64
64
  "name": "useInfiniteScroll",
65
65
  "type": "function",
66
- "description": "useInfiniteScroll Hook for implementing infinite scroll with optional virtualization. Intelligently detects initial vs loading-more states from context. Features: - Smart loading state detection (initial vs loading-more) - Optional explicit state control - TanStack Virtual integration for performance - Intersection Observer for load triggering - Configurable virtualization threshold ```tsx const { scrollRef, computedLoadingState, isLoadingMore } = useInfiniteScroll({ items, onLoadMore: fetchNextPage, hasMore: hasNextPage, isLoading: isFetching, }); ```",
66
+ "description": "useInfiniteScroll Hook for implementing infinite scroll with optional virtualization. Intelligently detects initial vs loading-more states from context. Features: - Smart loading state detection (initial vs loading-more) - Optional explicit state control - TanStack Virtual integration for performance - Intersection Observer for load triggering - Configurable virtualization threshold",
67
67
  "category": "hooks",
68
68
  "file": "hooks/useInfiniteScroll.ts"
69
69
  },
@@ -77,16 +77,23 @@
77
77
  {
78
78
  "name": "useMediaQuery",
79
79
  "type": "function",
80
- "description": "Hook to check if a media query matches the current viewport ```tsx const isMobile = useMediaQuery('(max-width: 767px)'); const prefersReducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)'); const isLandscape = useMediaQuery('(orientation: landscape)'); ```",
80
+ "description": "Hook to check if a media query matches the current viewport",
81
81
  "category": "hooks",
82
82
  "file": "hooks/useMediaQuery.ts"
83
83
  },
84
84
  {
85
85
  "name": "useServerDataControls",
86
86
  "type": "function",
87
- "description": "useServerDataControls Server-side hook that notifies the parent when filter/sort/search state changes. Search queries are debounced to avoid excessive API calls. This hook doesn't manipulate data - it just provides a clean way to: 1. Debounce search input 2. Notify when any state changes 3. Trigger server refetch ```tsx const [filters, setFilters] = useState(null); const [sort, setSort] = useState({ field: 'name', direction: 'asc' }); const [search, setSearch] = useState({ query: '', fields: ['name'] }); useServerDataControls({ filters, sort, search, onStateChange: (state) => { // Refetch data with new parameters refetch({ filters: state.filters, sort: state.sort, search: state.search?.query }); } }); ```",
87
+ "description": "useServerDataControls Server-side hook that notifies the parent when filter/sort/search state changes. Search queries are debounced to avoid excessive API calls. This hook doesn't manipulate data - it just provides a clean way to: 1. Debounce search input 2. Notify when any state changes 3. Trigger server refetch",
88
88
  "category": "hooks",
89
89
  "file": "hooks/useServerDataControls.ts"
90
+ },
91
+ {
92
+ "name": "useTableExport",
93
+ "type": "function",
94
+ "description": "Hook for exporting DataTable data as CSV. Provides a stable callback for triggering exports with memoized dependencies. For client-side DataTables where all data is in the browser. For server-side exports, use the `onExport` callback pattern instead.",
95
+ "category": "hooks",
96
+ "file": "hooks/useTableExport.ts"
90
97
  }
91
98
  ]
92
99
  },
@@ -173,7 +180,7 @@
173
180
  {
174
181
  "name": "createFormat",
175
182
  "type": "constant",
176
- "description": "Convenience function to create a format object ```typescript const currencyFormat = createFormat(\"currency\", { currency: \"EUR\" }); const dateFormat = createFormat(\"date\", { relative: true }); ```",
183
+ "description": "Convenience function to create a format object",
177
184
  "category": "formatting",
178
185
  "file": "utils/formatting/index.ts"
179
186
  },
@@ -222,14 +229,14 @@
222
229
  {
223
230
  "name": "formatCapacity",
224
231
  "type": "function",
225
- "description": "Format battery capacity (kWh) ```typescript formatCapacity(13.5); // \"13.5 kWh\" formatCapacity(1500); // \"1.5 MWh\" formatCapacity(null); // null ```",
232
+ "description": "Format battery capacity (kWh)",
226
233
  "category": "formatting",
227
234
  "file": "utils/formatting/capacity.ts"
228
235
  },
229
236
  {
230
237
  "name": "formatComponentValue",
231
238
  "type": "function",
232
- "description": "Format a value for display in a component Centralizes the logic used by Kpi, StatList, and similar components ```tsx // In a component const formatted = formatComponentValue({ value: 1500, formatter: { type: \"power\" } }); // Returns: \"1.5 kW\" ```",
239
+ "description": "Format a value for display in a component Centralizes the logic used by Kpi, StatList, and similar components",
233
240
  "category": "formatting",
234
241
  "file": "utils/formatting/component-formatter.tsx"
235
242
  },
@@ -271,7 +278,7 @@
271
278
  {
272
279
  "name": "formatFieldValue",
273
280
  "type": "constant",
274
- "description": "Main formatting function that routes to the appropriate formatter based on the format type ```typescript // Format as currency formatFieldValue(1234.56, { type: \"currency\", currency: \"USD\" }) // Returns: \"$1,234.56\" // Format as relative time formatFieldValue(new Date(), { type: \"date\", relative: true }) // Returns: \"just now\" // Format with custom formatter formatFieldValue(\"hello\", { type: \"custom\", formatter: (val) => String(val).toUpperCase() }) // Returns: \"HELLO\" ```",
281
+ "description": "Main formatting function that routes to the appropriate formatter based on the format type",
275
282
  "category": "formatting",
276
283
  "file": "utils/formatting/index.ts"
277
284
  },
@@ -320,7 +327,7 @@
320
327
  {
321
328
  "name": "formatPowerRating",
322
329
  "type": "function",
323
- "description": "Format power rating (kW) ```typescript formatPowerRating(5.2); // \"5.2 kW\" formatPowerRating(2500); // \"2.5 MW\" formatPowerRating(null); // null ```",
330
+ "description": "Format power rating (kW)",
324
331
  "category": "formatting",
325
332
  "file": "utils/formatting/capacity.ts"
326
333
  },
@@ -544,7 +551,7 @@
544
551
  {
545
552
  "name": "toDateString",
546
553
  "type": "constant",
547
- "description": "Format date to a localized string with optional time and timezone. ```typescript toDateString(new Date()); // \"12/25/2023\" toDateString(new Date(), true); // \"12/25/2023, 3:30 PM\" toDateString(\"2023-12-25T15:30:00Z\", true, \"America/New_York\"); // \"12/25/2023, 10:30 AM\" ```",
554
+ "description": "Format date to a localized string with optional time and timezone.",
548
555
  "category": "formatting",
549
556
  "file": "utils/formatting/date.ts"
550
557
  },
@@ -824,7 +831,7 @@
824
831
  {
825
832
  "name": "toRelativeTime",
826
833
  "type": "constant",
827
- "description": "Format date to relative time (e.g., \"2 hours ago\", \"in 3 days\"). Automatically chooses the most appropriate unit. ```typescript toRelativeTime(new Date(Date.now() - 3600000)); // \"1 hour ago\" toRelativeTime(new Date(Date.now() + 86400000)); // \"in 1 day\" toRelativeTime(new Date()); // \"now\" ```",
834
+ "description": "Format date to relative time (e.g., \"2 hours ago\", \"in 3 days\"). Automatically chooses the most appropriate unit.",
828
835
  "category": "formatting",
829
836
  "file": "utils/formatting/date.ts"
830
837
  },
@@ -845,7 +852,7 @@
845
852
  {
846
853
  "name": "toSentenceCase",
847
854
  "type": "function",
848
- "description": "Convert text to sentence case (first letter capitalized, rest lowercase). ```typescript toSentenceCase(\"HELLO WORLD\"); // \"Hello world\" toSentenceCase(\"hello world\"); // \"Hello world\" ```",
855
+ "description": "Convert text to sentence case (first letter capitalized, rest lowercase).",
849
856
  "category": "formatting",
850
857
  "file": "utils/formatting/text.ts"
851
858
  },
@@ -859,7 +866,7 @@
859
866
  {
860
867
  "name": "toTitleCase",
861
868
  "type": "function",
862
- "description": "Convert text to title case with proper handling of articles and prepositions. Capitalizes the first letter of each word except common articles/prepositions (unless they're the first word). ```typescript toTitleCase(\"the quick brown fox\"); // \"The Quick Brown Fox\" toTitleCase(\"war and peace\"); // \"War and Peace\" toTitleCase(\"to be or not to be\"); // \"To Be or Not to Be\" ```",
869
+ "description": "Convert text to title case with proper handling of articles and prepositions. Capitalizes the first letter of each word except common articles/prepositions (unless they're the first word).",
863
870
  "category": "formatting",
864
871
  "file": "utils/formatting/text.ts"
865
872
  },
@@ -950,7 +957,7 @@
950
957
  {
951
958
  "name": "useComponentFormatter",
952
959
  "type": "function",
953
- "description": "Hook for using the component formatter Provides memoization for better performance ```tsx function MyComponent({ value, formatter }) { const format = useComponentFormatter(formatter); const formatted = format(value); return <span>{formatted}</span>; } ```",
960
+ "description": "Hook for using the component formatter Provides memoization for better performance",
954
961
  "category": "formatting",
955
962
  "file": "utils/formatting/component-formatter.tsx"
956
963
  },
@@ -1011,7 +1018,7 @@
1011
1018
  {
1012
1019
  "name": "exportChart",
1013
1020
  "type": "function",
1014
- "description": "Main export function that handles all chart export types. Supports CSV, SVG, and PNG formats with automatic filename generation. ```typescript // Export single series as CSV await exportChart(\"csv\", data, { xLabel: \"Date\", yLabel: \"Value\", filename: \"sales-data\" }, svgRef); // Export multi-series chart as PNG await exportChart(\"png\", [series1, series2], { seriesLabels: [\"Revenue\", \"Profit\"], timestamp: false }, svgRef); ```",
1021
+ "description": "Main export function that handles all chart export types. Supports CSV, SVG, and PNG formats with automatic filename generation.",
1015
1022
  "category": "charts",
1016
1023
  "file": "utils/chartExport.ts"
1017
1024
  },
@@ -1042,13 +1049,6 @@
1042
1049
  "description": "Utility to check if export is supported in the current environment",
1043
1050
  "category": "charts",
1044
1051
  "file": "utils/chartExport.ts"
1045
- },
1046
- {
1047
- "name": "that",
1048
- "type": "function",
1049
- "description": "",
1050
- "category": "charts",
1051
- "file": "utils/chartExport.ts"
1052
1052
  }
1053
1053
  ]
1054
1054
  },
@@ -1086,7 +1086,7 @@
1086
1086
  {
1087
1087
  "name": "createCategoricalMapping",
1088
1088
  "type": "constant",
1089
- "description": "Creates a categorical color mapping for use with vector layers or explicit mappings This is a helper for cases where categorical auto-assignment doesn't work: - Vector tile layers (data not accessible at render time) - URL-based GeoJSON layers - Custom pin layers // Vector layer with categorical coloring layer.vector({ tileset: \"mapbox://my-tileset\", sourceLayer: \"buildings\", style: { color: createCategoricalMapping(\"type\", [\"residential\", \"commercial\", \"industrial\"]) } }) // With custom colors for specific values const mapping = createCategoricalMapping(\"status\", [\"active\", \"pending\", \"inactive\"]); // Then override specific colors if needed: mapping.mapping.inactive = { hex: \"#cccccc\" };",
1089
+ "description": "Creates a categorical color mapping for use with vector layers or explicit mappings This is a helper for cases where categorical auto-assignment doesn't work: - Vector tile layers (data not accessible at render time) - URL-based GeoJSON layers - Custom pin layers",
1090
1090
  "category": "colors",
1091
1091
  "file": "utils/colors.ts"
1092
1092
  },
@@ -1107,14 +1107,14 @@
1107
1107
  {
1108
1108
  "name": "createDivergingMapping",
1109
1109
  "type": "constant",
1110
- "description": "Creates a diverging color mapping for vector layers or manual bounds Use this helper when categorical auto-assignment doesn't work: - Vector tile layers (data not accessible at render time) - URL-based GeoJSON layers - When you want consistent colors across multiple maps // Vector layer with diverging coloring layer.vector({ tileset: \"mapbox://my-tileset\", sourceLayer: \"temperature\", style: { color: createDivergingMapping(\"temp_anomaly\", { min: -10, max: 10 }, 0, \"orangeYellowSeafoam\") } })",
1110
+ "description": "Creates a diverging color mapping for vector layers or manual bounds Use this helper when categorical auto-assignment doesn't work: - Vector tile layers (data not accessible at render time) - URL-based GeoJSON layers - When you want consistent colors across multiple maps",
1111
1111
  "category": "colors",
1112
1112
  "file": "utils/colors.ts"
1113
1113
  },
1114
1114
  {
1115
1115
  "name": "createSequentialMapping",
1116
1116
  "type": "constant",
1117
- "description": "Creates a sequential color mapping for vector layers or manual bounds Use this helper when categorical auto-assignment doesn't work: - Vector tile layers (data not accessible at render time) - URL-based GeoJSON layers - When you want consistent colors across multiple maps // Vector layer with sequential coloring layer.vector({ tileset: \"mapbox://my-tileset\", sourceLayer: \"population\", style: { color: createSequentialMapping(\"density\", { min: 0, max: 100000 }, \"magma\") } })",
1117
+ "description": "Creates a sequential color mapping for vector layers or manual bounds Use this helper when categorical auto-assignment doesn't work: - Vector tile layers (data not accessible at render time) - URL-based GeoJSON layers - When you want consistent colors across multiple maps",
1118
1118
  "category": "colors",
1119
1119
  "file": "utils/colors.ts"
1120
1120
  },
@@ -1135,14 +1135,14 @@
1135
1135
  {
1136
1136
  "name": "getColorFromDivergingScale",
1137
1137
  "type": "constant",
1138
- "description": "Get color from diverging scale for a given value Uses existing diverging palettes to interpolate color based on value position relative to center // Get color for temperature anomaly (-10 to +10, center at 0) const color = getColorFromDivergingScale(5, -10, 10, 0, 'redYellowBlue');",
1138
+ "description": "Get color from diverging scale for a given value Uses existing diverging palettes to interpolate color based on value position relative to center",
1139
1139
  "category": "colors",
1140
1140
  "file": "utils/colors.ts"
1141
1141
  },
1142
1142
  {
1143
1143
  "name": "getColorFromSequentialScale",
1144
1144
  "type": "constant",
1145
- "description": "Get color from sequential scale for a given value Uses existing sequential palettes to interpolate color based on value position in range // Get color for response time (0-5000ms range) const color = getColorFromSequentialScale(2500, 0, 5000, 'viridis');",
1145
+ "description": "Get color from sequential scale for a given value Uses existing sequential palettes to interpolate color based on value position in range",
1146
1146
  "category": "colors",
1147
1147
  "file": "utils/colors.ts"
1148
1148
  },
@@ -1177,7 +1177,7 @@
1177
1177
  {
1178
1178
  "name": "getResolvedColor",
1179
1179
  "type": "constant",
1180
- "description": "Resolves a CSS variable to its computed color value Supports multiple formats and automatically adds the color- prefix if needed - \"brand-primary\" → resolves to --color-brand-primary - \"color-brand-primary\" → resolves to --color-brand-primary - \"--color-brand-primary\" → used as-is - \"var(--color-brand-primary)\" → unwrapped and used",
1180
+ "description": "Resolves a CSS variable to its computed color value Supports multiple formats and automatically adds the color- prefix if needed",
1181
1181
  "category": "colors",
1182
1182
  "file": "utils/colors.ts"
1183
1183
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@texturehq/edges",
3
- "version": "1.26.5",
3
+ "version": "1.26.7",
4
4
  "author": "Nicholas Brown <nick@texturehq.com>",
5
5
  "description": "A shared component library for Texture",
6
6
  "type": "module",
@@ -70,12 +70,12 @@
70
70
  "postinstall": "node scripts/setup-cursor-rules.js || echo \"! setup-cursor-rules: non-fatal error\""
71
71
  },
72
72
  "peerDependencies": {
73
- "@hookform/resolvers": "^3.x",
74
- "next": "*",
73
+ "@hookform/resolvers": "^3.x || ^5.x",
74
+ "next": "^14.2.35 || ^15.5.9",
75
75
  "react": "^19.0.0",
76
76
  "react-dom": "^19.0.0",
77
77
  "react-hook-form": "^7.x",
78
- "zod": "^3.x"
78
+ "zod": "^3.x || ^4.x"
79
79
  },
80
80
  "peerDependenciesMeta": {
81
81
  "@hookform/resolvers": {
@@ -326,13 +326,22 @@ function extractJSDoc(content, functionName) {
326
326
  if (match) {
327
327
  const jsdocMatch = match[0].match(/\/\*\*([\s\S]*?)\*\//);
328
328
  if (jsdocMatch) {
329
- const cleaned = jsdocMatch[1]
329
+ const lines = jsdocMatch[1]
330
330
  .split("\n")
331
- .map((line) => line.replace(/^\s*\*\s?/, "").trim())
332
- .filter((line) => line && !line.startsWith("@"))
333
- .join(" ")
334
- .trim();
335
- return cleaned;
331
+ .map((line) => line.replace(/^\s*\*\s?/, "").trim());
332
+
333
+ // Extract only the main description (before any @tags)
334
+ const descriptionLines = [];
335
+ for (const line of lines) {
336
+ if (line.startsWith("@")) {
337
+ break; // Stop at first @tag
338
+ }
339
+ if (line) {
340
+ descriptionLines.push(line);
341
+ }
342
+ }
343
+
344
+ return descriptionLines.join(" ").trim();
336
345
  }
337
346
  }
338
347
  }
@@ -345,33 +354,70 @@ function extractExportsFromFile(filePath) {
345
354
 
346
355
  const utilities = [];
347
356
 
357
+ // Helper to check if a match is inside a comment
358
+ function isInComment(matchIndex) {
359
+ const beforeMatch = content.slice(0, matchIndex);
360
+
361
+ // Check if we're inside a JSDoc comment (/** ... */)
362
+ const lastJSDocStart = beforeMatch.lastIndexOf("/**");
363
+ const lastJSDocEnd = beforeMatch.lastIndexOf("*/");
364
+ if (lastJSDocStart > lastJSDocEnd) {
365
+ return true; // Inside JSDoc comment
366
+ }
367
+
368
+ // Check if we're inside a regular block comment (/* ... */)
369
+ const lastBlockStart = beforeMatch.lastIndexOf("/*");
370
+ const lastBlockEnd = beforeMatch.lastIndexOf("*/");
371
+ if (lastBlockStart > lastBlockEnd) {
372
+ // Make sure it's not a JSDoc opener (/**)
373
+ const blockOpener = beforeMatch.slice(lastBlockStart, lastBlockStart + 3);
374
+ if (blockOpener !== "/**") {
375
+ return true; // Inside regular block comment
376
+ }
377
+ }
378
+
379
+ // Check if we're on a line comment (//)
380
+ const lastNewline = beforeMatch.lastIndexOf("\n");
381
+ const lineStart = lastNewline === -1 ? 0 : lastNewline + 1;
382
+ const line = beforeMatch.slice(lineStart);
383
+ if (line.includes("//")) {
384
+ return true; // Inside line comment
385
+ }
386
+
387
+ return false;
388
+ }
389
+
348
390
  // Match export function declarations
349
391
  const functionPattern = /export\s+(?:async\s+)?function\s+(\w+)/g;
350
392
  let match;
351
393
  while ((match = functionPattern.exec(content))) {
352
- const name = match[1];
353
- utilities.push({
354
- name,
355
- type: "function",
356
- description: extractJSDoc(content, name),
357
- });
394
+ if (!isInComment(match.index)) {
395
+ const name = match[1];
396
+ utilities.push({
397
+ name,
398
+ type: "function",
399
+ description: extractJSDoc(content, name),
400
+ });
401
+ }
358
402
  }
359
403
 
360
404
  // Match export const arrow functions and constants
361
405
  const constPattern = /export\s+const\s+(\w+)\s*(?::\s*[^=]+)?\s*=/g;
362
406
  while ((match = constPattern.exec(content))) {
363
- const name = match[1];
364
- const afterMatch = content.slice(
365
- match.index + match[0].length,
366
- match.index + match[0].length + 50
367
- );
368
- const isFunction = afterMatch.includes("=>") || afterMatch.includes("function");
369
-
370
- utilities.push({
371
- name,
372
- type: isFunction ? "function" : "constant",
373
- description: extractJSDoc(content, name),
374
- });
407
+ if (!isInComment(match.index)) {
408
+ const name = match[1];
409
+ const afterMatch = content.slice(
410
+ match.index + match[0].length,
411
+ match.index + match[0].length + 50
412
+ );
413
+ const isFunction = afterMatch.includes("=>") || afterMatch.includes("function");
414
+
415
+ utilities.push({
416
+ name,
417
+ type: isFunction ? "function" : "constant",
418
+ description: extractJSDoc(content, name),
419
+ });
420
+ }
375
421
  }
376
422
 
377
423
  return utilities;