md2cv 1.1.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.ja.md +69 -1
  3. package/README.md +77 -11
  4. package/dist/cli/index.d.ts +17 -1
  5. package/dist/cli/index.d.ts.map +1 -1
  6. package/dist/cli/index.js +140 -34
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/generator/common.d.ts +86 -0
  9. package/dist/generator/common.d.ts.map +1 -0
  10. package/dist/generator/common.js +326 -0
  11. package/dist/generator/common.js.map +1 -0
  12. package/dist/generator/index.d.ts +39 -12
  13. package/dist/generator/index.d.ts.map +1 -1
  14. package/dist/generator/index.js +65 -41
  15. package/dist/generator/index.js.map +1 -1
  16. package/dist/generator/resume_en.d.ts +4 -15
  17. package/dist/generator/resume_en.d.ts.map +1 -1
  18. package/dist/generator/resume_en.js +23 -319
  19. package/dist/generator/resume_en.js.map +1 -1
  20. package/dist/generator/resume_ja.d.ts +4 -15
  21. package/dist/generator/resume_ja.d.ts.map +1 -1
  22. package/dist/generator/resume_ja.js +18 -260
  23. package/dist/generator/resume_ja.js.map +1 -1
  24. package/dist/generator/rirekisho/components.d.ts.map +1 -1
  25. package/dist/generator/rirekisho/components.js +1 -1
  26. package/dist/generator/rirekisho/components.js.map +1 -1
  27. package/dist/generator/rirekisho/index.js.map +1 -1
  28. package/dist/generator/rirekisho/layout.d.ts.map +1 -1
  29. package/dist/generator/rirekisho/layout.js +16 -7
  30. package/dist/generator/rirekisho/layout.js.map +1 -1
  31. package/dist/generator/rirekisho/styles.d.ts.map +1 -1
  32. package/dist/generator/rirekisho/styles.js +9 -14
  33. package/dist/generator/rirekisho/styles.js.map +1 -1
  34. package/dist/generator/rirekisho/types.d.ts +2 -2
  35. package/dist/generator/rirekisho/types.d.ts.map +1 -1
  36. package/dist/index.d.ts +3 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +3 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/parser/index.d.ts.map +1 -1
  41. package/dist/parser/index.js +224 -107
  42. package/dist/parser/index.js.map +1 -1
  43. package/dist/parser/lsp.d.ts +58 -0
  44. package/dist/parser/lsp.d.ts.map +1 -0
  45. package/dist/parser/lsp.js +265 -0
  46. package/dist/parser/lsp.js.map +1 -0
  47. package/dist/template/definitions/en.d.ts +17 -0
  48. package/dist/template/definitions/en.d.ts.map +1 -0
  49. package/dist/template/definitions/en.js +204 -0
  50. package/dist/template/definitions/en.js.map +1 -0
  51. package/dist/template/definitions/index.d.ts +6 -0
  52. package/dist/template/definitions/index.d.ts.map +1 -0
  53. package/dist/template/definitions/index.js +6 -0
  54. package/dist/template/definitions/index.js.map +1 -0
  55. package/dist/template/definitions/ja.d.ts +17 -0
  56. package/dist/template/definitions/ja.d.ts.map +1 -0
  57. package/dist/template/definitions/ja.js +243 -0
  58. package/dist/template/definitions/ja.js.map +1 -0
  59. package/dist/template/generator.d.ts +61 -0
  60. package/dist/template/generator.d.ts.map +1 -0
  61. package/dist/template/generator.js +219 -0
  62. package/dist/template/generator.js.map +1 -0
  63. package/dist/template/index.d.ts +6 -0
  64. package/dist/template/index.d.ts.map +1 -0
  65. package/dist/template/index.js +6 -0
  66. package/dist/template/index.js.map +1 -0
  67. package/dist/types/config.d.ts +126 -15
  68. package/dist/types/config.d.ts.map +1 -1
  69. package/dist/types/config.js +94 -1
  70. package/dist/types/config.js.map +1 -1
  71. package/dist/types/index.d.ts +2 -0
  72. package/dist/types/index.d.ts.map +1 -1
  73. package/dist/types/index.js +2 -0
  74. package/dist/types/index.js.map +1 -1
  75. package/dist/types/position.d.ts +42 -0
  76. package/dist/types/position.d.ts.map +1 -0
  77. package/dist/types/position.js +32 -0
  78. package/dist/types/position.js.map +1 -0
  79. package/dist/types/result.d.ts.map +1 -1
  80. package/dist/types/result.js.map +1 -1
  81. package/dist/types/sections.d.ts +39 -24
  82. package/dist/types/sections.d.ts.map +1 -1
  83. package/dist/types/sections.js +30 -2
  84. package/dist/types/sections.js.map +1 -1
  85. package/dist/types/template.d.ts +68 -0
  86. package/dist/types/template.d.ts.map +1 -0
  87. package/dist/types/template.js +12 -0
  88. package/dist/types/template.js.map +1 -0
  89. package/dist/validator/index.d.ts.map +1 -1
  90. package/dist/validator/index.js +1 -2
  91. package/dist/validator/index.js.map +1 -1
  92. package/examples/example-cv-ja.md +1 -1
  93. package/package.json +53 -5
@@ -56,10 +56,10 @@ body {
56
56
  font-family: var(--rirekisho-font-family);
57
57
  font-size: var(--rirekisho-font-size-base);
58
58
  color: var(--rirekisho-color-text);
59
- background: var(--rirekisho-color-background);
59
+ background: transparent;
60
60
  }
61
61
 
62
- /* Layout */
62
+ /* Layout - landscape orientation */
63
63
  .spread {
64
64
  width: ${mm(paper.width)};
65
65
  height: ${mm(paper.height)};
@@ -68,6 +68,7 @@ body {
68
68
  padding: ${mm(margin)} ${mm(margin)} ${mm(marginBottom)} ${mm(margin)};
69
69
  overflow: hidden;
70
70
  background: var(--rirekisho-color-background);
71
+ box-shadow: 0 2mm 12mm rgba(0, 0, 0, 0.5);
71
72
  }
72
73
 
73
74
  .spread-content {
@@ -352,26 +353,20 @@ td, th {
352
353
  .spread {
353
354
  page-break-after: always;
354
355
  page-break-before: avoid;
356
+ box-shadow: none;
355
357
  }
356
358
  }
357
359
 
358
360
  @media screen {
359
361
  html {
360
- height: 100%;
361
- }
362
-
363
- body {
364
362
  background: #888;
365
- min-height: 100%;
366
- display: flex;
367
- align-items: center;
368
- justify-content: center;
369
- padding: 20mm;
370
363
  }
371
364
 
372
- .spread {
373
- box-shadow: 0 2mm 12mm rgba(0, 0, 0, 0.5);
374
- flex-shrink: 0;
365
+ body {
366
+ background: transparent;
367
+ display: inline-block;
368
+ margin: 0;
369
+ padding: 0;
375
370
  }
376
371
  }
377
372
  `;
@@ -1 +1 @@
1
- {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/generator/rirekisho/styles.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/generator/rirekisho/styles.ts"],"names":[],"mappings":"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"}
@@ -12,9 +12,9 @@ export interface RirekishoOptions {
12
12
  readonly chronologicalOrder?: ChronologicalOrder;
13
13
  readonly hideMotivation?: boolean;
14
14
  /** Base64 encoded photo data URI (e.g., "data:image/png;base64,...") */
15
- readonly photoDataUri?: string | undefined;
15
+ readonly photoDataUri?: string;
16
16
  /** Custom CSS stylesheet content to append after default styles */
17
- readonly customStylesheet?: string | undefined;
17
+ readonly customStylesheet?: string;
18
18
  }
19
19
  /** Input data for the Rirekisho generator */
20
20
  export interface RirekishoInput {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/generator/rirekisho/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/generator/rirekisho/types.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,9 +2,11 @@
2
2
  * md2cv - CV/Resume Generator
3
3
  * Transforms Markdown CVs into PDF and HTML
4
4
  */
5
- export { createCLIProgram, main } from './cli/index.js';
5
+ export { createCLIProgram, main, runInit } from './cli/index.js';
6
6
  export * from './generator/index.js';
7
7
  export * from './parser/index.js';
8
+ export * from './parser/lsp.js';
9
+ export * from './template/index.js';
8
10
  export * from './types/index.js';
9
11
  export * from './validator/index.js';
10
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACxD,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACjE,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -2,9 +2,11 @@
2
2
  * md2cv - CV/Resume Generator
3
3
  * Transforms Markdown CVs into PDF and HTML
4
4
  */
5
- export { createCLIProgram, main } from './cli/index.js';
5
+ export { createCLIProgram, main, runInit } from './cli/index.js';
6
6
  export * from './generator/index.js';
7
7
  export * from './parser/index.js';
8
+ export * from './parser/lsp.js';
9
+ export * from './template/index.js';
8
10
  export * from './types/index.js';
9
11
  export * from './validator/index.js';
10
12
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACxD,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACjE,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,EAIH,KAAK,UAAU,EACf,KAAK,MAAM,EACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAIH,KAAK,UAAU,EAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAOH,KAAK,aAAa,EAMrB,MAAM,sBAAsB,CAAC;AAE9B;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;IAC5C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAspBD;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,CA+B9E;AAED,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,MAAM,EACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAOL,KAAK,aAAa,EAMnB,MAAM,sBAAsB,CAAC;AAE9B;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;IAC5C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AA4zBD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,GACf,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,CAqChC;AAED,eAAe,aAAa,CAAC"}
@@ -34,11 +34,43 @@ function extractText(node) {
34
34
  }
35
35
  return '';
36
36
  }
37
+ /**
38
+ * Remove HTML comments from the beginning of content
39
+ * This allows templates to have comments before frontmatter
40
+ * Note: This handles nested comment markers within comments
41
+ */
42
+ function stripLeadingHtmlComments(content) {
43
+ let result = content.trimStart();
44
+ // Keep removing HTML comments from the beginning
45
+ while (result.startsWith('<!--')) {
46
+ // Find the matching closing --> by counting nesting
47
+ let depth = 0;
48
+ let endIndex = -1;
49
+ for (let i = 0; i < result.length - 2; i++) {
50
+ if (result.substring(i, i + 4) === '<!--') {
51
+ depth++;
52
+ i += 3; // Skip past <!--
53
+ }
54
+ else if (result.substring(i, i + 3) === '-->') {
55
+ depth--;
56
+ if (depth === 0) {
57
+ endIndex = i;
58
+ break;
59
+ }
60
+ i += 2; // Skip past -->
61
+ }
62
+ }
63
+ if (endIndex === -1)
64
+ break;
65
+ result = result.substring(endIndex + 3).trimStart();
66
+ }
67
+ return result;
68
+ }
37
69
  /**
38
70
  * Parse frontmatter delimiter type
39
71
  */
40
72
  function parseFrontmatterDelimiter(content) {
41
- const trimmed = content.trimStart();
73
+ const trimmed = stripLeadingHtmlComments(content);
42
74
  if (trimmed.startsWith('---'))
43
75
  return '---';
44
76
  if (trimmed.startsWith('+++'))
@@ -55,7 +87,9 @@ function validateFrontmatterDelimiters(content, errors) {
55
87
  if (!delimiter) {
56
88
  return true;
57
89
  }
58
- const lines = content.split('\n');
90
+ // Strip leading HTML comments before checking delimiters
91
+ const strippedContent = stripLeadingHtmlComments(content);
92
+ const lines = strippedContent.split('\n');
59
93
  let foundStart = false;
60
94
  let foundEnd = false;
61
95
  for (let i = 0; i < lines.length; i++) {
@@ -125,7 +159,9 @@ function parseListItems(listNode) {
125
159
  const items = [];
126
160
  for (const item of listNode.children) {
127
161
  if (item.type === 'listItem' && item.children) {
128
- const text = item.children.map((child) => extractText(child)).join('');
162
+ const text = item.children
163
+ .map((child) => extractText(child))
164
+ .join('');
129
165
  items.push(text.trim());
130
166
  }
131
167
  }
@@ -273,22 +309,107 @@ function parseEducationBlock(code) {
273
309
  const parsed = parseYaml(code);
274
310
  // Handle both single object and array
275
311
  const items = Array.isArray(parsed) ? parsed : [parsed];
276
- return items.map((item) => {
312
+ return items
313
+ .map((item) => {
277
314
  const obj = item;
315
+ const school = safeString(obj.school);
316
+ const degree = safeOptionalString(obj.degree);
317
+ const start = parseYearMonth(safeOptionalString(obj.start));
318
+ const end = parseYearMonth(safeOptionalString(obj.end));
319
+ // Skip entries missing required fields (degree is optional for rirekisho format)
320
+ if (!school || !start || !end) {
321
+ return null;
322
+ }
323
+ const location = safeOptionalString(obj.location);
324
+ const details = Array.isArray(obj.details)
325
+ ? obj.details.map((d) => {
326
+ // Handle YAML parsing objects like { "GPA": "3.8/4.0" } as "GPA: 3.8/4.0"
327
+ if (typeof d === 'object' && d !== null) {
328
+ const entries = Object.entries(d);
329
+ if (entries.length > 0) {
330
+ return entries
331
+ .map(([k, v]) => `${k}: ${safeString(v)}`)
332
+ .join(', ');
333
+ }
334
+ return '';
335
+ }
336
+ return safeString(d);
337
+ })
338
+ : undefined;
278
339
  return {
279
- school: safeString(obj.school),
280
- degree: safeOptionalString(obj.degree),
281
- location: safeOptionalString(obj.location),
282
- start: parseYearMonth(safeOptionalString(obj.start)),
283
- end: parseYearMonth(safeOptionalString(obj.end)),
284
- details: Array.isArray(obj.details) ? obj.details.map((d) => safeString(d)) : undefined,
340
+ school,
341
+ degree,
342
+ start,
343
+ end,
344
+ ...(location !== undefined && { location }),
345
+ ...(details !== undefined && {
346
+ details: details,
347
+ }),
285
348
  };
286
- });
349
+ })
350
+ .filter((entry) => entry !== null);
287
351
  }
288
352
  catch {
289
353
  return [];
290
354
  }
291
355
  }
356
+ /**
357
+ * Parse a project entry from YAML
358
+ */
359
+ function parseProjectEntry(proj) {
360
+ const name = safeString(proj.name);
361
+ const start = parseYearMonth(safeOptionalString(proj.start));
362
+ const end = parseYearMonth(safeOptionalString(proj.end));
363
+ // Skip entries missing required fields
364
+ if (!name || !start || !end) {
365
+ return null;
366
+ }
367
+ const bullets = Array.isArray(proj.bullets)
368
+ ? proj.bullets.map((b) => safeString(b))
369
+ : undefined;
370
+ return {
371
+ name,
372
+ start,
373
+ end,
374
+ ...(bullets !== undefined && { bullets }),
375
+ };
376
+ }
377
+ /**
378
+ * Parse a role entry from YAML
379
+ */
380
+ function parseRoleEntry(role) {
381
+ const title = safeString(role.title || role.role);
382
+ const start = parseYearMonth(safeOptionalString(role.start));
383
+ const end = parseEndDate(safeOptionalString(role.end));
384
+ // Skip entries missing required fields
385
+ if (!title || !start || !end) {
386
+ return null;
387
+ }
388
+ const team = safeOptionalString(role.team);
389
+ const summary = parseSummary(role.summary);
390
+ const highlights = Array.isArray(role.highlights)
391
+ ? role.highlights.map((h) => safeString(h))
392
+ : undefined;
393
+ const projects = [];
394
+ if (Array.isArray(role.projects)) {
395
+ for (const projItem of role.projects) {
396
+ const proj = projItem;
397
+ const projectEntry = parseProjectEntry(proj);
398
+ if (projectEntry) {
399
+ projects.push(projectEntry);
400
+ }
401
+ }
402
+ }
403
+ return {
404
+ title,
405
+ start,
406
+ end,
407
+ ...(team !== undefined && { team }),
408
+ ...(summary !== undefined && { summary }),
409
+ ...(highlights !== undefined && { highlights }),
410
+ ...(projects.length > 0 && { projects }),
411
+ };
412
+ }
292
413
  /**
293
414
  * Parse resume:experience code block
294
415
  */
@@ -297,74 +418,40 @@ function parseExperienceBlock(code) {
297
418
  const parsed = parseYaml(code);
298
419
  // Handle both single object and array
299
420
  const items = Array.isArray(parsed) ? parsed : [parsed];
300
- return items.map((item) => {
421
+ const entries = [];
422
+ for (const item of items) {
301
423
  const obj = item;
424
+ const company = safeString(obj.company);
302
425
  const roles = [];
303
426
  // Support both nested roles array and flat role definition
304
427
  if (Array.isArray(obj.roles)) {
305
428
  for (const roleItem of obj.roles) {
306
429
  const role = roleItem;
307
- const projects = [];
308
- if (Array.isArray(role.projects)) {
309
- for (const projItem of role.projects) {
310
- const proj = projItem;
311
- projects.push({
312
- name: safeString(proj.name),
313
- start: parseYearMonth(safeOptionalString(proj.start)),
314
- end: parseYearMonth(safeOptionalString(proj.end)),
315
- bullets: Array.isArray(proj.bullets)
316
- ? proj.bullets.map((b) => safeString(b))
317
- : undefined,
318
- });
319
- }
430
+ const roleEntry = parseRoleEntry(role);
431
+ if (roleEntry) {
432
+ roles.push(roleEntry);
320
433
  }
321
- roles.push({
322
- title: safeString(role.title),
323
- team: safeOptionalString(role.team),
324
- start: parseYearMonth(safeOptionalString(role.start)),
325
- end: parseEndDate(safeOptionalString(role.end)),
326
- summary: parseSummary(role.summary),
327
- highlights: Array.isArray(role.highlights)
328
- ? role.highlights.map((h) => safeString(h))
329
- : undefined,
330
- projects: projects.length > 0 ? projects : undefined,
331
- });
332
434
  }
333
435
  }
334
- else if (obj.role) {
335
- // Flat role definition (role, team, start, end at top level)
336
- const projects = [];
337
- if (Array.isArray(obj.projects)) {
338
- for (const projItem of obj.projects) {
339
- const proj = projItem;
340
- projects.push({
341
- name: safeString(proj.name),
342
- start: parseYearMonth(safeOptionalString(proj.start)),
343
- end: parseYearMonth(safeOptionalString(proj.end)),
344
- bullets: Array.isArray(proj.bullets)
345
- ? proj.bullets.map((b) => safeString(b))
346
- : undefined,
347
- });
348
- }
436
+ else if (obj.role || obj.title) {
437
+ // Flat role definition (role/title, team, start, end at top level)
438
+ const roleEntry = parseRoleEntry(obj);
439
+ if (roleEntry) {
440
+ roles.push(roleEntry);
349
441
  }
350
- roles.push({
351
- title: safeString(obj.role),
352
- team: safeOptionalString(obj.team),
353
- start: parseYearMonth(safeOptionalString(obj.start)),
354
- end: parseEndDate(safeOptionalString(obj.end)),
355
- summary: parseSummary(obj.summary),
356
- highlights: Array.isArray(obj.highlights)
357
- ? obj.highlights.map((h) => safeString(h))
358
- : undefined,
359
- projects: projects.length > 0 ? projects : undefined,
360
- });
361
442
  }
362
- return {
363
- company: safeString(obj.company),
364
- location: safeOptionalString(obj.location),
365
- roles,
366
- };
367
- });
443
+ // Skip entries missing required fields
444
+ if (!company || roles.length === 0) {
445
+ continue;
446
+ }
447
+ const location = safeOptionalString(obj.location);
448
+ entries.push({
449
+ company,
450
+ roles: roles,
451
+ ...(location !== undefined && { location }),
452
+ });
453
+ }
454
+ return entries;
368
455
  }
369
456
  catch {
370
457
  return [];
@@ -378,67 +465,80 @@ function parseCertificationsBlock(code) {
378
465
  const parsed = parseYaml(code);
379
466
  // Handle both single object and array
380
467
  const items = Array.isArray(parsed) ? parsed : [parsed];
381
- return items.map((item) => {
468
+ return items
469
+ .map((item) => {
382
470
  const obj = item;
471
+ const name = safeString(obj.name);
472
+ const date = parseYearMonth(safeOptionalString(obj.date));
473
+ // Skip entries missing required fields
474
+ if (!name || !date) {
475
+ return null;
476
+ }
477
+ const issuer = safeOptionalString(obj.issuer);
478
+ const url = safeOptionalString(obj.url);
383
479
  return {
384
- name: safeString(obj.name),
385
- issuer: safeOptionalString(obj.issuer),
386
- date: parseYearMonth(safeOptionalString(obj.date)),
387
- url: safeOptionalString(obj.url),
480
+ name,
481
+ date,
482
+ ...(issuer !== undefined && { issuer }),
483
+ ...(url !== undefined && { url }),
388
484
  };
389
- });
485
+ })
486
+ .filter((entry) => entry !== null);
390
487
  }
391
488
  catch {
392
489
  return [];
393
490
  }
394
491
  }
492
+ function parseSkillEntry(catObj) {
493
+ const category = safeString(catObj.category);
494
+ const items = Array.isArray(catObj.items)
495
+ ? catObj.items.map((i) => safeString(i))
496
+ : undefined;
497
+ const description = safeOptionalString(catObj.description);
498
+ const level = safeOptionalString(catObj.level);
499
+ return {
500
+ category,
501
+ ...(items !== undefined && { items }),
502
+ ...(description !== undefined && { description }),
503
+ ...(level !== undefined && { level }),
504
+ };
505
+ }
395
506
  function parseSkillsBlock(code) {
507
+ const defaultResult = {
508
+ entries: [],
509
+ columns: 3,
510
+ format: 'grid',
511
+ };
396
512
  try {
397
513
  const parsed = parseYaml(code);
398
514
  // Check if it's the new format with columns and items at top level
399
515
  if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
400
516
  const obj = parsed;
517
+ const columns = typeof obj.columns === 'number' ? obj.columns : 3;
401
518
  // Format 1: Simple items list (grid format)
402
- if (Array.isArray(obj.items) && obj.items.every((i) => typeof i === 'string')) {
403
- const columns = typeof obj.columns === 'number' ? obj.columns : undefined;
519
+ if (Array.isArray(obj.items) &&
520
+ obj.items.every((i) => typeof i === 'string')) {
404
521
  const items = obj.items.map((i) => safeString(i));
405
522
  // Convert to single SkillEntry with empty category
406
523
  return {
407
- entries: [{ category: '', items, description: undefined, level: undefined }],
524
+ entries: [{ category: '', items }],
408
525
  columns,
409
526
  format: 'grid',
410
527
  };
411
528
  }
412
529
  // Format 2 & 3: Categorized skills
413
530
  if (Array.isArray(obj.categories)) {
414
- const columns = typeof obj.columns === 'number' ? obj.columns : undefined;
415
- const entries = obj.categories.map((cat) => {
416
- const catObj = cat;
417
- return {
418
- category: safeString(catObj.category),
419
- items: Array.isArray(catObj.items) ? catObj.items.map((i) => safeString(i)) : [],
420
- description: safeOptionalString(catObj.description),
421
- level: safeOptionalString(catObj.level),
422
- };
423
- });
531
+ const entries = obj.categories.map((cat) => parseSkillEntry(cat));
424
532
  return { entries, columns, format: 'categorized' };
425
533
  }
426
534
  }
427
535
  // Legacy format: array of { category, items, level }
428
536
  const items = Array.isArray(parsed) ? parsed : [parsed];
429
- const entries = items.map((item) => {
430
- const obj = item;
431
- return {
432
- category: safeString(obj.category),
433
- items: Array.isArray(obj.items) ? obj.items.map((i) => safeString(i)) : [],
434
- description: safeOptionalString(obj.description),
435
- level: safeOptionalString(obj.level),
436
- };
437
- });
438
- return { entries, columns: undefined, format: undefined };
537
+ const entries = items.map((item) => parseSkillEntry(item));
538
+ return { entries, columns: 3, format: 'categorized' };
439
539
  }
440
540
  catch {
441
- return { entries: [], columns: undefined, format: undefined };
541
+ return defaultResult;
442
542
  }
443
543
  }
444
544
  /**
@@ -469,13 +569,18 @@ function parseLanguagesBlock(code) {
469
569
  const parsed = parseYaml(code);
470
570
  // Handle both single object and array
471
571
  const items = Array.isArray(parsed) ? parsed : [parsed];
472
- return items.map((item) => {
572
+ return items
573
+ .map((item) => {
473
574
  const obj = item;
474
- return {
475
- language: safeString(obj.language),
476
- level: safeOptionalString(obj.level),
477
- };
478
- });
575
+ const language = safeString(obj.language);
576
+ const level = safeOptionalString(obj.level);
577
+ // Skip entries missing required fields
578
+ if (!language || !level) {
579
+ return null;
580
+ }
581
+ return { language, level };
582
+ })
583
+ .filter((entry) => entry !== null);
479
584
  }
480
585
  catch {
481
586
  return [];
@@ -535,7 +640,14 @@ function parseSectionContent(nodes) {
535
640
  return { type: 'certifications', entries: certificationEntries };
536
641
  }
537
642
  if (skillEntries.length > 0) {
538
- return { type: 'skills', entries: skillEntries, options: { columns: skillsColumns, format: skillsFormat } };
643
+ return {
644
+ type: 'skills',
645
+ entries: skillEntries,
646
+ options: {
647
+ columns: skillsColumns ?? 3,
648
+ format: skillsFormat ?? 'grid',
649
+ },
650
+ };
539
651
  }
540
652
  if (competencyEntries.length > 0) {
541
653
  return { type: 'competencies', entries: competencyEntries };
@@ -586,7 +698,9 @@ function parseSections(tree) {
586
698
  }
587
699
  }
588
700
  // Start new section
589
- currentTitle = node.children.map((c) => extractText(c)).join('');
701
+ currentTitle = node.children
702
+ .map((c) => extractText(c))
703
+ .join('');
590
704
  currentNodes = [];
591
705
  }
592
706
  else if (currentTitle !== null) {
@@ -615,9 +729,12 @@ export function parseMarkdown(markdown) {
615
729
  if (!validateFrontmatterDelimiters(markdown, errors)) {
616
730
  return failure(errors);
617
731
  }
732
+ // Strip leading HTML comments before parsing
733
+ // This allows templates to have comments before frontmatter
734
+ const processedMarkdown = stripLeadingHtmlComments(markdown);
618
735
  try {
619
736
  const processor = createProcessor();
620
- const tree = processor.parse(markdown);
737
+ const tree = processor.parse(processedMarkdown);
621
738
  // Extract metadata
622
739
  const metadata = extractMetadata(tree, errors);
623
740
  if (!metadata) {