docgen-utils 1.0.12 → 1.0.13

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 (65) hide show
  1. package/dist/bundle.js +3189 -1238
  2. package/dist/bundle.min.js +101 -99
  3. package/dist/cli.js +2653 -1117
  4. package/dist/packages/cli/commands/export-docs.d.ts.map +1 -1
  5. package/dist/packages/cli/commands/export-docs.js +131 -2
  6. package/dist/packages/cli/commands/export-docs.js.map +1 -1
  7. package/dist/packages/cli/commands/export-slides.d.ts.map +1 -1
  8. package/dist/packages/cli/commands/export-slides.js +25 -1
  9. package/dist/packages/cli/commands/export-slides.js.map +1 -1
  10. package/dist/packages/docs/common.d.ts +10 -0
  11. package/dist/packages/docs/common.d.ts.map +1 -1
  12. package/dist/packages/docs/common.js.map +1 -1
  13. package/dist/packages/docs/convert.d.ts.map +1 -1
  14. package/dist/packages/docs/convert.js +246 -218
  15. package/dist/packages/docs/convert.js.map +1 -1
  16. package/dist/packages/docs/create-document.d.ts.map +1 -1
  17. package/dist/packages/docs/create-document.js +43 -3
  18. package/dist/packages/docs/create-document.js.map +1 -1
  19. package/dist/packages/docs/export.d.ts +9 -8
  20. package/dist/packages/docs/export.d.ts.map +1 -1
  21. package/dist/packages/docs/export.js +23 -36
  22. package/dist/packages/docs/export.js.map +1 -1
  23. package/dist/packages/docs/parse-colors.d.ts +37 -0
  24. package/dist/packages/docs/parse-colors.d.ts.map +1 -0
  25. package/dist/packages/docs/parse-colors.js +507 -0
  26. package/dist/packages/docs/parse-colors.js.map +1 -0
  27. package/dist/packages/docs/parse-css.d.ts +98 -0
  28. package/dist/packages/docs/parse-css.d.ts.map +1 -0
  29. package/dist/packages/docs/parse-css.js +1592 -0
  30. package/dist/packages/docs/parse-css.js.map +1 -0
  31. package/dist/packages/docs/parse-helpers.d.ts +45 -0
  32. package/dist/packages/docs/parse-helpers.d.ts.map +1 -0
  33. package/dist/packages/docs/parse-helpers.js +214 -0
  34. package/dist/packages/docs/parse-helpers.js.map +1 -0
  35. package/dist/packages/docs/parse-inline.d.ts +41 -0
  36. package/dist/packages/docs/parse-inline.d.ts.map +1 -0
  37. package/dist/packages/docs/parse-inline.js +473 -0
  38. package/dist/packages/docs/parse-inline.js.map +1 -0
  39. package/dist/packages/docs/parse-layout.d.ts +57 -0
  40. package/dist/packages/docs/parse-layout.d.ts.map +1 -0
  41. package/dist/packages/docs/parse-layout.js +295 -0
  42. package/dist/packages/docs/parse-layout.js.map +1 -0
  43. package/dist/packages/docs/parse-special.d.ts +51 -0
  44. package/dist/packages/docs/parse-special.d.ts.map +1 -0
  45. package/dist/packages/docs/parse-special.js +251 -0
  46. package/dist/packages/docs/parse-special.js.map +1 -0
  47. package/dist/packages/docs/parse-units.d.ts +68 -0
  48. package/dist/packages/docs/parse-units.d.ts.map +1 -0
  49. package/dist/packages/docs/parse-units.js +275 -0
  50. package/dist/packages/docs/parse-units.js.map +1 -0
  51. package/dist/packages/docs/parse.d.ts.map +1 -1
  52. package/dist/packages/docs/parse.js +957 -2800
  53. package/dist/packages/docs/parse.js.map +1 -1
  54. package/dist/packages/slides/common.d.ts +7 -0
  55. package/dist/packages/slides/common.d.ts.map +1 -1
  56. package/dist/packages/slides/convert.d.ts.map +1 -1
  57. package/dist/packages/slides/convert.js +92 -7
  58. package/dist/packages/slides/convert.js.map +1 -1
  59. package/dist/packages/slides/parse.d.ts.map +1 -1
  60. package/dist/packages/slides/parse.js +723 -40
  61. package/dist/packages/slides/parse.js.map +1 -1
  62. package/dist/packages/slides/transform.d.ts.map +1 -1
  63. package/dist/packages/slides/transform.js +12 -7
  64. package/dist/packages/slides/transform.js.map +1 -1
  65. package/package.json +1 -1
@@ -0,0 +1,295 @@
1
+ import { getElementStyles } from "./parse-css";
2
+ export function isGridOrFlexContainer(element, cssContext) {
3
+ const styles = getElementStyles(element, cssContext);
4
+ return styles.display === "grid" || styles.display === "flex";
5
+ }
6
+ /**
7
+ * GENERALIZED: Check if an element is a horizontal flex container.
8
+ * A horizontal flex container has display: flex with flex-direction: row (or unset, since row is default).
9
+ * This is used to detect containers where flex items should be visually separated
10
+ * with a separator character (like " • ") to represent the CSS gap.
11
+ *
12
+ * @param element - The element to check
13
+ * @param cssContext - CSS context for style resolution
14
+ * @returns true if this is a horizontal flex container, false otherwise
15
+ */
16
+ export function isHorizontalFlexContainer(element, cssContext) {
17
+ const styles = getElementStyles(element, cssContext);
18
+ // Must be a flex container
19
+ if (styles.display !== "flex") {
20
+ return false;
21
+ }
22
+ // Check flex-direction - horizontal if "row" or "row-reverse" or not set (default is row)
23
+ // Vertical (column) containers should NOT have separators between items
24
+ const direction = styles.flexDirection?.toLowerCase();
25
+ if (direction === "column" || direction === "column-reverse") {
26
+ return false;
27
+ }
28
+ // Also check inline styles for flex-direction override
29
+ const inlineStyle = element.getAttribute("style") || "";
30
+ const directionMatch = inlineStyle.match(/flex-direction\s*:\s*([^;]+)/i);
31
+ if (directionMatch) {
32
+ const inlineDirection = directionMatch[1].trim().toLowerCase();
33
+ if (inlineDirection === "column" || inlineDirection === "column-reverse") {
34
+ return false;
35
+ }
36
+ }
37
+ return true;
38
+ }
39
+ /**
40
+ * Check if an SVG element is purely decorative (background pattern, decoration, etc).
41
+ * Decorative SVGs should NOT be converted to chart placeholders.
42
+ *
43
+ * Detection criteria (style-based, not class-name-based per skill rules):
44
+ * 1. Fixed/absolute positioning (background elements)
45
+ * 2. Very low opacity (< 0.5)
46
+ * 3. Contains only pattern definitions (<defs>, <pattern>, <linearGradient>)
47
+ * 4. Is a background overlay (pointer-events: none)
48
+ * 5. Very small viewBox (icons < 50x50)
49
+ */
50
+ export function isDecorativeSvg(svgElement, parentElement, cssContext) {
51
+ // Check parent container styles
52
+ const parentStyles = getElementStyles(parentElement, cssContext);
53
+ const parentInlineStyle = parentElement.getAttribute("style") || "";
54
+ // Check SVG's own styles
55
+ const svgInlineStyle = svgElement.getAttribute("style") || "";
56
+ // 1. Check for fixed/absolute positioning (typically background elements)
57
+ const positionMatch = parentInlineStyle.match(/position\s*:\s*(fixed|absolute)/i) ||
58
+ svgInlineStyle.match(/position\s*:\s*(fixed|absolute)/i);
59
+ if (positionMatch) {
60
+ return true;
61
+ }
62
+ // 2. Check for low opacity (decorative overlays)
63
+ const parentOpacityMatch = parentInlineStyle.match(/opacity\s*:\s*([0-9.]+)/i);
64
+ const svgOpacityMatch = svgInlineStyle.match(/opacity\s*:\s*([0-9.]+)/i);
65
+ const opacityAttr = svgElement.getAttribute("opacity");
66
+ const opacity = parseFloat(parentOpacityMatch?.[1] || svgOpacityMatch?.[1] || opacityAttr || "1");
67
+ if (opacity < 0.5) {
68
+ return true;
69
+ }
70
+ // 3. Check for pointer-events: none (non-interactive background)
71
+ if (parentInlineStyle.includes("pointer-events: none") ||
72
+ svgInlineStyle.includes("pointer-events: none") ||
73
+ parentStyles.display === "none") {
74
+ return true;
75
+ }
76
+ // 4. Check if SVG contains only definitions (patterns, gradients) - no actual shapes
77
+ const hasOnlyDefs = svgElement.children.length > 0 &&
78
+ Array.from(svgElement.children).every((child) => ["defs", "style", "title", "desc"].includes(child.tagName.toLowerCase()));
79
+ if (hasOnlyDefs) {
80
+ return true;
81
+ }
82
+ // 5. Check for very small viewBox (likely an icon, not a chart)
83
+ // Charts must be at least 100x50 to match export.ts isChartSvg()
84
+ const viewBox = svgElement.getAttribute("viewBox");
85
+ if (viewBox) {
86
+ const parts = viewBox.split(/\s+/).map(Number);
87
+ if (parts.length >= 4) {
88
+ const width = parts[2] || 0;
89
+ const height = parts[3] || 0;
90
+ // Charts must be at least 100x50 - anything smaller is decorative
91
+ if (width > 0 && height > 0 && (width < 100 || height < 50)) {
92
+ return true;
93
+ }
94
+ }
95
+ }
96
+ else {
97
+ // No viewBox - check width/height attributes
98
+ const widthAttr = svgElement.getAttribute("width");
99
+ const heightAttr = svgElement.getAttribute("height");
100
+ if (widthAttr && heightAttr) {
101
+ const width = parseFloat(widthAttr) || 0;
102
+ const height = parseFloat(heightAttr) || 0;
103
+ // Charts must be at least 100x50
104
+ if (width > 0 && height > 0 && (width < 100 || height < 50)) {
105
+ return true;
106
+ }
107
+ }
108
+ }
109
+ // 6. Check if SVG is purely a pattern/gradient container
110
+ // These typically have <rect> with fill="url(#pattern)" or only <circle>/<path> with very low complexity
111
+ const shapes = svgElement.querySelectorAll("rect, circle, ellipse, path, polygon, polyline, line");
112
+ if (shapes.length > 0) {
113
+ // Count shapes that use pattern/gradient fills (decorative)
114
+ let decorativeShapeCount = 0;
115
+ for (const shape of shapes) {
116
+ const fill = shape.getAttribute("fill") || "";
117
+ const stroke = shape.getAttribute("stroke") || "";
118
+ if (fill.includes("url(#") || stroke.includes("url(#")) {
119
+ decorativeShapeCount++;
120
+ }
121
+ }
122
+ // If all shapes use pattern/gradient fills, it's likely decorative
123
+ if (decorativeShapeCount === shapes.length && shapes.length <= 5) {
124
+ return true;
125
+ }
126
+ }
127
+ // 7. Check if this appears to be a progress circle (small circular skills indicator)
128
+ // These have circle elements with stroke-dasharray for progress
129
+ const circles = svgElement.querySelectorAll("circle");
130
+ if (circles.length > 0 && circles.length <= 2) {
131
+ const hasStrokeDasharray = Array.from(circles).some((c) => c.getAttribute("stroke-dasharray"));
132
+ if (hasStrokeDasharray) {
133
+ // This is a progress indicator, not a chart - treat as decorative for now
134
+ // In the future, we could extract the percentage
135
+ return true;
136
+ }
137
+ }
138
+ // 8. Check if parent is a centered flex container (typical hero image pattern)
139
+ // Hero images typically have: display: flex; align-items: center; justify-content: center
140
+ // These contain illustrative SVGs which should be included as images, not filtered
141
+ // We no longer filter these - they are legitimate content images
142
+ // (Previously we filtered centered flex containers, but hero images should be included)
143
+ // 9. SVGs with sufficient size should be included as images
144
+ // We only filter out truly decorative elements (icons, patterns, progress circles)
145
+ // Large SVGs (illustrations, charts, diagrams) should all be included
146
+ return false;
147
+ }
148
+ /**
149
+ * Check if an element is a two-column CSS grid layout.
150
+ * Detects patterns like: display: grid; grid-template-columns: Xpx 1fr
151
+ * Returns the sidebar width percentage if it's a two-column layout, undefined otherwise.
152
+ */
153
+ export function isTwoColumnGridLayout(element, cssContext) {
154
+ const styles = getElementStyles(element, cssContext);
155
+ // Must be a grid container
156
+ if (styles.display !== "grid") {
157
+ return undefined;
158
+ }
159
+ // Check for two-column pattern (e.g., "280px 1fr", "300px auto", "25% 75%")
160
+ const gridCols = styles.gridTemplateColumns;
161
+ if (!gridCols) {
162
+ return undefined;
163
+ }
164
+ // Parse grid-template-columns to detect two-column sidebar layout
165
+ // Common patterns:
166
+ // - "280px 1fr" (fixed sidebar + fluid main)
167
+ // - "300px auto" (fixed sidebar + auto main)
168
+ // - "25% 1fr" (percentage sidebar + fluid main)
169
+ const parts = gridCols.trim().split(/\s+/);
170
+ if (parts.length !== 2) {
171
+ return undefined;
172
+ }
173
+ const [first, second] = parts;
174
+ // Check if first column is a fixed width or small percentage (sidebar)
175
+ // and second column is flexible (1fr, auto, or larger percentage)
176
+ const firstIsSidebar = (first.endsWith("px") && parseInt(first, 10) <= 400) ||
177
+ (first.endsWith("%") && parseFloat(first) <= 35);
178
+ const secondIsMain = second === "1fr" ||
179
+ second === "auto" ||
180
+ (second.endsWith("%") && parseFloat(second) >= 50) ||
181
+ (second.endsWith("fr") && parseFloat(second) >= 1);
182
+ if (firstIsSidebar && secondIsMain) {
183
+ // Calculate sidebar width percentage
184
+ if (first.endsWith("px")) {
185
+ // Assume ~1100px total width for typical documents
186
+ const pxWidth = parseInt(first, 10);
187
+ return Math.round((pxWidth / 1100) * 100);
188
+ }
189
+ else if (first.endsWith("%")) {
190
+ return parseFloat(first);
191
+ }
192
+ return 25; // Default 25% for other cases
193
+ }
194
+ return undefined;
195
+ }
196
+ /**
197
+ * Find the sidebar and main content elements in a two-column grid container.
198
+ * Returns the first two direct children as [sidebar, main] or undefined.
199
+ */
200
+ export function findTwoColumnChildren(container) {
201
+ const children = Array.from(container.children).filter((child) => child.nodeType === Node.ELEMENT_NODE);
202
+ if (children.length < 2) {
203
+ return undefined;
204
+ }
205
+ // First child is sidebar (aside, div, etc.), second is main content
206
+ return [children[0], children[1]];
207
+ }
208
+ /**
209
+ * GENERALIZED: Detect if an element is a flex container with equal-width columns.
210
+ * This handles layouts like:
211
+ * display: flex; with children having flex: 1 (equal width)
212
+ *
213
+ * Returns the column children if detected, undefined otherwise.
214
+ * Each child will become a column in a DOCX table.
215
+ */
216
+ export function detectFlexEqualColumns(element, cssContext) {
217
+ const styles = getElementStyles(element, cssContext);
218
+ // Must be a flex container
219
+ if (styles.display !== "flex") {
220
+ return undefined;
221
+ }
222
+ // Get direct children
223
+ const children = Array.from(element.children).filter((child) => child.nodeType === Node.ELEMENT_NODE);
224
+ // Need at least 2 children for multi-column layout
225
+ if (children.length < 2 || children.length > 12) {
226
+ return undefined;
227
+ }
228
+ // Check if children have flex: 1 or similar equal-width pattern
229
+ // Also check inline styles since class-based flex: 1 is common
230
+ let hasEqualFlexChildren = true;
231
+ for (const child of children) {
232
+ const childStyles = getElementStyles(child, cssContext);
233
+ const inlineStyle = child.getAttribute("style") || "";
234
+ // Check for flex: 1 in CSS or inline styles
235
+ const hasFlex1 = childStyles.flex === "1" ||
236
+ inlineStyle.includes("flex:") ||
237
+ inlineStyle.includes("flex: 1");
238
+ // Also detect if class has flex: 1 (we can't directly read this, but
239
+ // children in a flex container with no explicit width typically share space)
240
+ // For now, assume if parent is flex and has 2+ children, they share space
241
+ // If any child has explicit width that's not equal, skip
242
+ // (We're being permissive here - assuming equal columns if parent is flex)
243
+ }
244
+ // Return children as columns if this looks like an equal-column flex layout
245
+ return children;
246
+ }
247
+ /**
248
+ * Detect if an element uses CSS Grid with equal-width columns.
249
+ * Patterns:
250
+ * display: grid; grid-template-columns: 1fr 1fr
251
+ * display: grid; grid-template-columns: repeat(2, 1fr)
252
+ * display: grid; grid-template-columns: repeat(3, 1fr)
253
+ *
254
+ * Returns the column children if detected, undefined otherwise.
255
+ * Only matches equal-width patterns (all 1fr), not sidebar patterns (280px 1fr).
256
+ */
257
+ export function detectGridEqualColumns(element, cssContext) {
258
+ const styles = getElementStyles(element, cssContext);
259
+ // Must be a grid container
260
+ if (styles.display !== "grid") {
261
+ // Also check inline styles for grid
262
+ const inlineStyle = element.getAttribute("style") || "";
263
+ if (!inlineStyle.includes("display") || !inlineStyle.includes("grid")) {
264
+ return undefined;
265
+ }
266
+ }
267
+ // Check grid-template-columns
268
+ const gridCols = styles.gridTemplateColumns || "";
269
+ const inlineStyle = element.getAttribute("style") || "";
270
+ // Extract grid-template-columns from inline style if not in CSS context
271
+ let colValue = gridCols;
272
+ if (!colValue) {
273
+ const colMatch = inlineStyle.match(/grid-template-columns:\s*([^;]+)/);
274
+ if (colMatch) {
275
+ colValue = colMatch[1].trim();
276
+ }
277
+ }
278
+ if (!colValue)
279
+ return undefined;
280
+ // Check if it's an equal-width pattern
281
+ // "1fr 1fr", "1fr 1fr 1fr", "repeat(2, 1fr)", "repeat(3, 1fr)"
282
+ const repeatMatch = colValue.match(/repeat\(\s*(\d+)\s*,\s*1fr\s*\)/);
283
+ const frOnlyMatch = colValue.match(/^(\s*1fr\s*)+$/);
284
+ if (!repeatMatch && !frOnlyMatch) {
285
+ return undefined;
286
+ }
287
+ // Get direct children
288
+ const children = Array.from(element.children).filter((child) => child.nodeType === Node.ELEMENT_NODE);
289
+ // Need at least 2 children for multi-column layout
290
+ if (children.length < 2 || children.length > 12) {
291
+ return undefined;
292
+ }
293
+ return children;
294
+ }
295
+ //# sourceMappingURL=parse-layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-layout.js","sourceRoot":"","sources":["../../../packages/docs/parse-layout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import type { CssContext } from "./parse-css";
2
+ export interface TimelineItem {
3
+ date: string;
4
+ title?: string;
5
+ description?: string;
6
+ isCurrent: boolean;
7
+ accentColor?: string;
8
+ }
9
+ /**
10
+ * Detect if an element is a "skill item" by its structure.
11
+ * Pattern: The element has a direct child that contains exactly 2 text elements (name + percentage).
12
+ * The element should have exactly 1-2 direct children (header + optional progress bar).
13
+ *
14
+ * Returns { name, percentage } if detected, undefined otherwise.
15
+ */
16
+ export declare function detectSkillItem(element: Element): {
17
+ name: string;
18
+ percentage: string;
19
+ } | undefined;
20
+ /**
21
+ * Detect if an element is a "language item" with proficiency dots/indicators.
22
+ * Pattern: container with text (language name) and a child with multiple small indicators.
23
+ *
24
+ * Returns { name, filledCount, totalCount } if detected, undefined otherwise.
25
+ */
26
+ export declare function detectLanguageItem(element: Element, cssContext: CssContext): {
27
+ name: string;
28
+ filledCount: number;
29
+ totalCount: number;
30
+ } | undefined;
31
+ /**
32
+ * Detect if an element is a progress bar container.
33
+ * Patterns:
34
+ * 1. Div containing a child with a width percentage in inline style (progress-bar fill)
35
+ * 2. Div with .progress, .progress-bar, .goal-progress class
36
+ *
37
+ * Returns { percentage, label? } if detected, undefined otherwise.
38
+ */
39
+ export declare function detectProgressBar(element: Element, cssContext: CssContext): {
40
+ percentage: number;
41
+ label?: string;
42
+ } | undefined;
43
+ /**
44
+ * Detect if an element is a timeline container.
45
+ * Pattern: div with class "timeline" or containing children with class "timeline-item".
46
+ * Also detects horizontal timelines and milestone lists.
47
+ *
48
+ * Returns array of TimelineItem if detected, undefined otherwise.
49
+ */
50
+ export declare function detectTimeline(element: Element, cssContext: CssContext): TimelineItem[] | undefined;
51
+ //# sourceMappingURL=parse-special.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-special.d.ts","sourceRoot":"","sources":["../../../packages/docs/parse-special.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAiClG;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAoElJ;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAqD9H;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,GAAG,YAAY,EAAE,GAAG,SAAS,CAwFnG"}
@@ -0,0 +1,251 @@
1
+ import { getElementStyles } from "./parse-css";
2
+ import { extractHexColor } from "./parse-colors";
3
+ import { getTextContent } from "./parse-helpers";
4
+ /**
5
+ * Detect if an element is a "skill item" by its structure.
6
+ * Pattern: The element has a direct child that contains exactly 2 text elements (name + percentage).
7
+ * The element should have exactly 1-2 direct children (header + optional progress bar).
8
+ *
9
+ * Returns { name, percentage } if detected, undefined otherwise.
10
+ */
11
+ export function detectSkillItem(element) {
12
+ const children = Array.from(element.children);
13
+ // Skill items typically have 1-2 direct children:
14
+ // - A header div with name + percentage
15
+ // - Optionally a progress bar container
16
+ if (children.length === 0 || children.length > 3)
17
+ return undefined;
18
+ // Look for the header child that contains name + percentage
19
+ for (const child of children) {
20
+ // Skip if this child has too many children (not a header)
21
+ if (child.children.length !== 2)
22
+ continue;
23
+ const directChildren = Array.from(child.children).filter((c) => c.children.length === 0 && c.textContent?.trim());
24
+ // Must have exactly 2 leaf text elements
25
+ if (directChildren.length !== 2)
26
+ continue;
27
+ const text1 = directChildren[0].textContent?.trim() || "";
28
+ const text2 = directChildren[1].textContent?.trim() || "";
29
+ // Check if one is a percentage (number followed by %)
30
+ if (text2.match(/^\d+%$/)) {
31
+ return { name: text1, percentage: text2 };
32
+ }
33
+ if (text1.match(/^\d+%$/)) {
34
+ return { name: text2, percentage: text1 };
35
+ }
36
+ }
37
+ return undefined;
38
+ }
39
+ /**
40
+ * Detect if an element is a "language item" with proficiency dots/indicators.
41
+ * Pattern: container with text (language name) and a child with multiple small indicators.
42
+ *
43
+ * Returns { name, filledCount, totalCount } if detected, undefined otherwise.
44
+ */
45
+ export function detectLanguageItem(element, cssContext) {
46
+ const children = Array.from(element.children);
47
+ if (children.length < 2)
48
+ return undefined;
49
+ let languageName = "";
50
+ let filledCount = 0;
51
+ let totalCount = 0;
52
+ for (const child of children) {
53
+ const childTagName = child.tagName.toLowerCase();
54
+ // GENERALIZED: Skip headings - they're not language names
55
+ // This prevents title-block patterns (h1 + metadata div) from being detected
56
+ if (childTagName.match(/^h[1-6]$/)) {
57
+ return undefined;
58
+ }
59
+ // Check if this is a text element (language name)
60
+ // Must be a simple span or similar inline element, not a complex structure
61
+ if (child.children.length === 0 && child.textContent?.trim()) {
62
+ const text = child.textContent.trim();
63
+ // GENERALIZED: Language names are typically short (1-3 words)
64
+ // Skip if the text is too long (like a title or paragraph)
65
+ if (text.length > 50 || text.split(/\s+/).length > 5) {
66
+ return undefined;
67
+ }
68
+ languageName = text;
69
+ continue;
70
+ }
71
+ // Check if this is a container with multiple similar small children (dots/indicators)
72
+ const indicators = Array.from(child.children);
73
+ if (indicators.length >= 3 && indicators.length <= 10) {
74
+ // Check if they look like indicators (similar structure)
75
+ const allSpans = indicators.every((ind) => ind.tagName.toLowerCase() === "span");
76
+ if (allSpans) {
77
+ totalCount = indicators.length;
78
+ // Count "filled" indicators by checking for background color or specific styling
79
+ for (const indicator of indicators) {
80
+ const styles = getElementStyles(indicator, cssContext);
81
+ const bgColor = styles.backgroundColor;
82
+ // A "filled" indicator typically has a non-white/non-transparent background
83
+ // or has more than just border styling
84
+ if (bgColor && bgColor !== "transparent" && bgColor !== "inherit") {
85
+ const hexBg = extractHexColor(bgColor);
86
+ // Check if it's a "filled" color (not white/very light)
87
+ if (hexBg && hexBg !== "FFFFFF" && !hexBg.startsWith("FF")) {
88
+ filledCount++;
89
+ }
90
+ else if (hexBg) {
91
+ // Light color means filled if rgba has low opacity
92
+ // For now, count any background as potentially filled
93
+ // We'll need to be smarter about this
94
+ const alpha = bgColor.match(/rgba.*,\s*([0-9.]+)\s*\)/)?.[1];
95
+ if (!alpha || parseFloat(alpha) > 0.15) {
96
+ filledCount++;
97
+ }
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ if (languageName && totalCount > 0) {
105
+ return { name: languageName, filledCount, totalCount };
106
+ }
107
+ return undefined;
108
+ }
109
+ /**
110
+ * Detect if an element is a progress bar container.
111
+ * Patterns:
112
+ * 1. Div containing a child with a width percentage in inline style (progress-bar fill)
113
+ * 2. Div with .progress, .progress-bar, .goal-progress class
114
+ *
115
+ * Returns { percentage, label? } if detected, undefined otherwise.
116
+ */
117
+ export function detectProgressBar(element, cssContext) {
118
+ const children = Array.from(element.children);
119
+ if (children.length === 0 || children.length > 4)
120
+ return undefined;
121
+ // Check if this is a progress bar wrapper (has a child with width% inline style)
122
+ for (const child of children) {
123
+ const childEl = child;
124
+ const inlineStyle = childEl.getAttribute("style") || "";
125
+ const className = childEl.getAttribute("class") || "";
126
+ // Pattern 1: Child with width percentage in inline style and background color
127
+ // e.g., <div class="progress-bar" style="width: 65%; background-color: ...">
128
+ const widthMatch = inlineStyle.match(/width:\s*(\d+(?:\.\d+)?)%/);
129
+ if (widthMatch) {
130
+ const childStyles = getElementStyles(childEl, cssContext);
131
+ const hasBgColor = childStyles.backgroundColor &&
132
+ childStyles.backgroundColor !== "transparent" &&
133
+ childStyles.backgroundColor !== "inherit";
134
+ const hasProgressClass = className.match(/progress|bar|fill|gauge/i);
135
+ if (hasBgColor || hasProgressClass) {
136
+ const percentage = Math.round(parseFloat(widthMatch[1]));
137
+ // Look for a label in sibling elements or parent's siblings
138
+ let label;
139
+ const parentEl = element.parentElement;
140
+ if (parentEl) {
141
+ for (const sibling of parentEl.children) {
142
+ if (sibling !== element) {
143
+ const text = getTextContent(sibling).trim();
144
+ if (text && text.length < 100) {
145
+ label = text;
146
+ break;
147
+ }
148
+ }
149
+ }
150
+ }
151
+ return { percentage, label };
152
+ }
153
+ }
154
+ // Pattern 2: Child has a progress-related class but no width — check its children
155
+ if (className.match(/progress/i) && childEl.children.length > 0) {
156
+ for (const grandchild of childEl.children) {
157
+ const gcStyle = grandchild.getAttribute("style") || "";
158
+ const gcWidthMatch = gcStyle.match(/width:\s*(\d+(?:\.\d+)?)%/);
159
+ if (gcWidthMatch) {
160
+ return { percentage: Math.round(parseFloat(gcWidthMatch[1])) };
161
+ }
162
+ }
163
+ }
164
+ }
165
+ return undefined;
166
+ }
167
+ /**
168
+ * Detect if an element is a timeline container.
169
+ * Pattern: div with class "timeline" or containing children with class "timeline-item".
170
+ * Also detects horizontal timelines and milestone lists.
171
+ *
172
+ * Returns array of TimelineItem if detected, undefined otherwise.
173
+ */
174
+ export function detectTimeline(element, cssContext) {
175
+ const className = element.getAttribute("class") || "";
176
+ const children = Array.from(element.children);
177
+ // Direct timeline container
178
+ const isTimeline = className.match(/\btimeline\b/i);
179
+ // Or a wrapper that contains a timeline child
180
+ let timelineEl = null;
181
+ if (isTimeline) {
182
+ timelineEl = element;
183
+ }
184
+ else {
185
+ // Check direct children for a timeline element
186
+ for (const child of children) {
187
+ const childClass = child.getAttribute("class") || "";
188
+ if (childClass.match(/\btimeline\b/i)) {
189
+ timelineEl = child;
190
+ break;
191
+ }
192
+ }
193
+ }
194
+ if (!timelineEl)
195
+ return undefined;
196
+ // Extract accent color from CSS context (timeline-date color)
197
+ let accentColor;
198
+ const dateEl = timelineEl.querySelector(".timeline-date, .timeline-h-date");
199
+ if (dateEl) {
200
+ const dateStyles = getElementStyles(dateEl, cssContext);
201
+ if (dateStyles.color) {
202
+ accentColor = extractHexColor(dateStyles.color);
203
+ }
204
+ }
205
+ const items = [];
206
+ // Pattern 1: Vertical timeline with .timeline-item children
207
+ const timelineItems = timelineEl.querySelectorAll(".timeline-item");
208
+ if (timelineItems.length > 0) {
209
+ for (const item of timelineItems) {
210
+ const itemEl = item;
211
+ const itemClass = itemEl.getAttribute("class") || "";
212
+ const isCurrent = itemClass.includes("current");
213
+ const dateEl = itemEl.querySelector(".timeline-date");
214
+ const date = dateEl ? getTextContent(dateEl).trim() : "";
215
+ const contentEl = itemEl.querySelector(".timeline-content");
216
+ let title;
217
+ let description;
218
+ if (contentEl) {
219
+ const h5 = contentEl.querySelector("h5, h4, h3, strong");
220
+ if (h5)
221
+ title = getTextContent(h5).trim();
222
+ const p = contentEl.querySelector("p");
223
+ if (p)
224
+ description = getTextContent(p).trim();
225
+ }
226
+ if (date || title) {
227
+ items.push({ date: date || "", title, description, isCurrent, accentColor });
228
+ }
229
+ }
230
+ return items.length > 0 ? items : undefined;
231
+ }
232
+ // Pattern 2: Horizontal timeline with .timeline-h-item children
233
+ const hItems = timelineEl.querySelectorAll(".timeline-h-item");
234
+ if (hItems.length > 0) {
235
+ for (const item of hItems) {
236
+ const itemEl = item;
237
+ const itemClass = itemEl.getAttribute("class") || "";
238
+ const isCurrent = itemClass.includes("current");
239
+ const dateEl = itemEl.querySelector(".timeline-h-date");
240
+ const labelEl = itemEl.querySelector(".timeline-h-label");
241
+ const date = dateEl ? getTextContent(dateEl).trim() : "";
242
+ const title = labelEl ? getTextContent(labelEl).trim() : undefined;
243
+ if (date || title) {
244
+ items.push({ date: date || "", title, isCurrent, accentColor });
245
+ }
246
+ }
247
+ return items.length > 0 ? items : undefined;
248
+ }
249
+ return undefined;
250
+ }
251
+ //# sourceMappingURL=parse-special.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-special.js","sourceRoot":"","sources":["../../../packages/docs/parse-special.ts"],"names":[],"mappings":"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"}