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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/generator/common.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,eAAe,EACf,aAAa,EACb,aAAa,EACb,cAAc,EACd,UAAU,EACV,aAAa,EACd,MAAM,sBAAsB,CAAC;AAE9B;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;CAC7C;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,SAAS,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAOzE,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ/C;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,GAAG,MAAM,CAAC;IAC3C,aAAa,CAAC,GAAG,EAAE,IAAI,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IACzD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,aAyB7B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,aAW7B,CAAC;AAEF;;GAEG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,IAAI,GAAG,SAAS,EACvB,GAAG,EAAE,IAAI,GAAG,SAAS,GAAG,SAAS,EACjC,SAAS,EAAE,aAAa,GACvB,MAAM,CAMR;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,SAAS,EAAE,aAAa,GACvB,MAAM,CAoCR;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,SAAS,kBAAkB,EAAE,EACtC,SAAS,EAAE,aAAa,GACvB,MAAM,CAWR;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,aAAa,GACvB,MAAM,CA0CR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,GAAE,MAA+B,GACvC,MAAM,CAcR;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,GAAG,MAAM,CAWzE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,SAAS,eAAe,EAAE,GAClC,MAAM,CAMR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,SAAS,eAAe,EAAE,EACnC,SAAS,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7D,MAAM,CAwER;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,aAAa,GACvB,MAAM,CAoCR"}
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Common utilities for CV/Resume generators
3
+ * Shared between English and Japanese CV generators
4
+ */
5
+ /**
6
+ * Page size dimensions in mm
7
+ * CV uses portrait orientation (width < height)
8
+ */
9
+ export const PAGE_SIZES = {
10
+ a3: { width: 297, height: 420 },
11
+ a4: { width: 210, height: 297 },
12
+ b4: { width: 257, height: 364 },
13
+ b5: { width: 182, height: 257 },
14
+ letter: { width: 215.9, height: 279.4 },
15
+ };
16
+ /**
17
+ * Default number of columns for skills grid
18
+ */
19
+ export const DEFAULT_SKILLS_COLUMNS = 3;
20
+ /**
21
+ * Escape HTML special characters
22
+ */
23
+ export function escapeHtml(text) {
24
+ if (text == null)
25
+ return '';
26
+ return text
27
+ .replace(/&/g, '&amp;')
28
+ .replace(/</g, '&lt;')
29
+ .replace(/>/g, '&gt;')
30
+ .replace(/"/g, '&quot;')
31
+ .replace(/'/g, '&#039;');
32
+ }
33
+ /**
34
+ * English date formatter
35
+ */
36
+ export const enDateFormatter = {
37
+ formatDate(date) {
38
+ if (!date)
39
+ return '';
40
+ const months = [
41
+ 'Jan',
42
+ 'Feb',
43
+ 'Mar',
44
+ 'Apr',
45
+ 'May',
46
+ 'Jun',
47
+ 'Jul',
48
+ 'Aug',
49
+ 'Sep',
50
+ 'Oct',
51
+ 'Nov',
52
+ 'Dec',
53
+ ];
54
+ return `${months[date.getMonth()]} ${date.getFullYear()}`;
55
+ },
56
+ formatEndDate(end) {
57
+ if (!end)
58
+ return '';
59
+ if (end === 'present')
60
+ return 'Present';
61
+ return this.formatDate(end);
62
+ },
63
+ itemSeparator: ', ',
64
+ };
65
+ /**
66
+ * Japanese date formatter
67
+ */
68
+ export const jaDateFormatter = {
69
+ formatDate(date) {
70
+ if (!date)
71
+ return '';
72
+ return `${date.getFullYear()}年${date.getMonth() + 1}月`;
73
+ },
74
+ formatEndDate(end) {
75
+ if (!end)
76
+ return '';
77
+ if (end === 'present')
78
+ return '現在';
79
+ return this.formatDate(end);
80
+ },
81
+ itemSeparator: '、',
82
+ };
83
+ /**
84
+ * Format date range using the provided formatter
85
+ */
86
+ export function formatDateRange(start, end, formatter) {
87
+ const startStr = formatter.formatDate(start);
88
+ const endStr = formatter.formatEndDate(end);
89
+ if (startStr && endStr)
90
+ return `${startStr} - ${endStr}`;
91
+ if (startStr)
92
+ return startStr;
93
+ return '';
94
+ }
95
+ /**
96
+ * Render education section
97
+ */
98
+ export function renderEducation(entries, formatter) {
99
+ return entries
100
+ .map((entry) => {
101
+ const dateRange = formatDateRange(entry.start, entry.end, formatter);
102
+ let html = '<div class="entry">';
103
+ html += '<div class="entry-header">';
104
+ html += `<span class="entry-title">${escapeHtml(entry.school)}</span>`;
105
+ if (dateRange) {
106
+ html += `<span class="entry-date">${escapeHtml(dateRange)}</span>`;
107
+ }
108
+ html += '</div>';
109
+ const subtitleParts = [];
110
+ if (entry.degree) {
111
+ subtitleParts.push(escapeHtml(entry.degree));
112
+ }
113
+ if (entry.location) {
114
+ subtitleParts.push(escapeHtml(entry.location));
115
+ }
116
+ if (subtitleParts.length > 0) {
117
+ html += `<div class="entry-subtitle">${subtitleParts.join(' — ')}</div>`;
118
+ }
119
+ const nonEmptyDetails = entry.details?.filter((d) => d && d.trim()) ?? [];
120
+ if (nonEmptyDetails.length > 0) {
121
+ html += '<ul>';
122
+ for (const detail of nonEmptyDetails) {
123
+ html += `<li>${escapeHtml(detail)}</li>`;
124
+ }
125
+ html += '</ul>';
126
+ }
127
+ html += '</div>';
128
+ return html;
129
+ })
130
+ .join('\n');
131
+ }
132
+ /**
133
+ * Render certifications section
134
+ */
135
+ export function renderCertifications(entries, formatter) {
136
+ return entries
137
+ .map((entry) => {
138
+ let html = `<div class="cert-item">• ${escapeHtml(entry.name)}`;
139
+ if (entry.date) {
140
+ html += ` (${escapeHtml(formatter.formatDate(entry.date))})`;
141
+ }
142
+ html += '</div>';
143
+ return html;
144
+ })
145
+ .join('\n');
146
+ }
147
+ /**
148
+ * Render skills section - supports grid and categorized formats
149
+ */
150
+ export function renderSkills(entries, options, formatter) {
151
+ const isCategorized = options.format === 'categorized' ||
152
+ entries.some((e) => e.category && (e.description || (e.items && e.items.length > 0)));
153
+ if (isCategorized && entries.some((e) => e.category)) {
154
+ return entries
155
+ .filter((e) => e.category)
156
+ .map((entry) => {
157
+ const content = entry.description ||
158
+ (entry.items?.join(formatter.itemSeparator) ?? '');
159
+ return `<div class="skill-category">• <span class="skill-category-name">${escapeHtml(entry.category)}:</span> ${escapeHtml(content)}</div>`;
160
+ })
161
+ .join('\n');
162
+ }
163
+ const allItems = [];
164
+ for (const entry of entries) {
165
+ if (entry.items) {
166
+ for (const item of entry.items) {
167
+ allItems.push(item);
168
+ }
169
+ }
170
+ }
171
+ if (allItems.length === 0) {
172
+ return '';
173
+ }
174
+ const columns = options.columns ?? DEFAULT_SKILLS_COLUMNS;
175
+ const colsClass = columns === 3 ? 'skills-grid--cols-3' : '';
176
+ const colsStyle = columns !== 3 ? `grid-template-columns: repeat(${columns}, 1fr);` : '';
177
+ let html = `<div class="skills-grid ${colsClass}"${colsStyle ? ` style="${colsStyle}"` : ''}>`;
178
+ for (const item of allItems) {
179
+ html += `<div class="skill-item">• ${escapeHtml(item)}</div>`;
180
+ }
181
+ html += '</div>';
182
+ return html;
183
+ }
184
+ /**
185
+ * Render skills from list content as grid
186
+ */
187
+ export function renderSkillsList(items, columns = DEFAULT_SKILLS_COLUMNS) {
188
+ if (items.length === 0) {
189
+ return '';
190
+ }
191
+ const colsClass = columns === 3 ? 'skills-grid--cols-3' : '';
192
+ const colsStyle = columns !== 3 ? `grid-template-columns: repeat(${columns}, 1fr);` : '';
193
+ let html = `<div class="skills-grid ${colsClass}"${colsStyle ? ` style="${colsStyle}"` : ''}>`;
194
+ for (const item of items) {
195
+ html += `<div class="skill-item">• ${escapeHtml(item)}</div>`;
196
+ }
197
+ html += '</div>';
198
+ return html;
199
+ }
200
+ /**
201
+ * Render languages section
202
+ */
203
+ export function renderLanguages(entries) {
204
+ return entries
205
+ .map((entry) => {
206
+ let html = `<span class="lang-item">${escapeHtml(entry.language)}`;
207
+ if (entry.level) {
208
+ html += ` (${escapeHtml(entry.level)})`;
209
+ }
210
+ html += '</span>';
211
+ return html;
212
+ })
213
+ .join(' • ');
214
+ }
215
+ /**
216
+ * Render core competencies section
217
+ */
218
+ export function renderCompetencies(entries) {
219
+ return entries
220
+ .map((entry) => {
221
+ return `<div class="competency-entry"><span class="competency-header">${escapeHtml(entry.header)}:</span> ${escapeHtml(entry.description)}</div>`;
222
+ })
223
+ .join('\n');
224
+ }
225
+ /**
226
+ * Render experience section
227
+ */
228
+ export function renderExperience(entries, formatter, options) {
229
+ const includeTeam = options?.includeTeam ?? true;
230
+ const includeProjects = options?.includeProjects ?? true;
231
+ return entries
232
+ .flatMap((entry) => {
233
+ return entry.roles.map((role) => {
234
+ const dateRange = formatDateRange(role.start, role.end, formatter);
235
+ let html = '<div class="entry">';
236
+ html += '<div class="entry-header">';
237
+ html += `<span class="entry-title">${escapeHtml(entry.company)} —— ${escapeHtml(role.title)}</span>`;
238
+ if (dateRange) {
239
+ html += `<span class="entry-date">${escapeHtml(dateRange)}</span>`;
240
+ }
241
+ html += '</div>';
242
+ if (includeTeam) {
243
+ const subtitleParts = [];
244
+ if (role.team) {
245
+ subtitleParts.push(escapeHtml(role.team));
246
+ }
247
+ if (entry.location) {
248
+ subtitleParts.push(escapeHtml(entry.location));
249
+ }
250
+ if (subtitleParts.length > 0) {
251
+ html += `<div class="entry-subtitle">${subtitleParts.join(' — ')}</div>`;
252
+ }
253
+ }
254
+ if (role.summary && role.summary.length > 0) {
255
+ html += '<div class="entry-summary">';
256
+ html += role.summary.map((s) => escapeHtml(s)).join(' ');
257
+ html += '</div>';
258
+ }
259
+ if (role.highlights && role.highlights.length > 0) {
260
+ html += '<ul>';
261
+ for (const highlight of role.highlights) {
262
+ html += `<li>${escapeHtml(highlight)}</li>`;
263
+ }
264
+ html += '</ul>';
265
+ }
266
+ if (includeProjects && role.projects && role.projects.length > 0) {
267
+ for (const project of role.projects) {
268
+ const projDateRange = formatDateRange(project.start, project.end, formatter);
269
+ html += '<div class="project">';
270
+ html += `<span class="project-name">${escapeHtml(project.name)}</span>`;
271
+ if (projDateRange) {
272
+ html += ` <span class="entry-date">(${escapeHtml(projDateRange)})</span>`;
273
+ }
274
+ if (project.bullets && project.bullets.length > 0) {
275
+ html += '<ul>';
276
+ for (const bullet of project.bullets) {
277
+ html += `<li>${escapeHtml(bullet)}</li>`;
278
+ }
279
+ html += '</ul>';
280
+ }
281
+ html += '</div>';
282
+ }
283
+ }
284
+ html += '</div>';
285
+ return html;
286
+ });
287
+ })
288
+ .join('\n');
289
+ }
290
+ /**
291
+ * Render section content
292
+ */
293
+ export function renderSectionContent(content, sectionId, formatter) {
294
+ switch (content.type) {
295
+ case 'text':
296
+ return `<p>${escapeHtml(content.text)}</p>`;
297
+ case 'list':
298
+ if (sectionId === 'skills') {
299
+ return renderSkillsList(content.items);
300
+ }
301
+ return ('<ul>' +
302
+ content.items.map((item) => `<li>${escapeHtml(item)}</li>`).join('\n') +
303
+ '</ul>');
304
+ case 'education':
305
+ return renderEducation(content.entries, formatter);
306
+ case 'experience':
307
+ return renderExperience(content.entries, formatter);
308
+ case 'certifications':
309
+ return renderCertifications(content.entries, formatter);
310
+ case 'skills':
311
+ return renderSkills(content.entries, content.options, formatter);
312
+ case 'competencies':
313
+ return renderCompetencies(content.entries);
314
+ case 'languages':
315
+ return renderLanguages(content.entries);
316
+ case 'table':
317
+ return ('<ul>' +
318
+ content.rows
319
+ .map((row) => `<li>${escapeHtml(row.content)}</li>`)
320
+ .join('\n') +
321
+ '</ul>');
322
+ default:
323
+ return '';
324
+ }
325
+ }
326
+ //# sourceMappingURL=common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/generator/common.ts"],"names":[],"mappings":"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"}
@@ -4,30 +4,57 @@
4
4
  */
5
5
  import type { Logger } from '../cli/index.js';
6
6
  import type { PaperSize, ResolvedConfig } from '../types/config.js';
7
- import type { CVMetadata } from '../types/metadata.js';
8
- import type { ParsedSection } from '../types/sections.js';
9
- import { generateCVEnHTML } from './resume_en.js';
10
- import { generateCVJaHTML } from './resume_ja.js';
7
+ import type { CVInput } from './common.js';
8
+ import { generateEnHtml } from './resume_en.js';
9
+ import { generateJaHtml } from './resume_ja.js';
11
10
  import { generateRirekishoHTML } from './rirekisho/index.js';
12
- export { generateCVEnHTML, generateCVJaHTML, generateRirekishoHTML };
11
+ export { generateEnHtml, generateJaHtml, generateRirekishoHTML };
13
12
  /**
14
- * Input for CV generation (internal type)
13
+ * Page size dimensions in mm (portrait orientation for CV)
15
14
  */
16
- interface CVInput {
17
- readonly metadata: CVMetadata;
18
- readonly sections: readonly ParsedSection[];
19
- }
15
+ export declare const PAGE_SIZES: Record<PaperSize, {
16
+ width: number;
17
+ height: number;
18
+ }>;
20
19
  /**
21
- * Page size dimensions in mm
20
+ * Page size dimensions in mm (landscape orientation for Rirekisho)
22
21
  */
23
- export declare const PAGE_SIZES: Record<PaperSize, {
22
+ export declare const PAGE_SIZES_LANDSCAPE: Record<PaperSize, {
24
23
  width: number;
25
24
  height: number;
26
25
  }>;
26
+ /**
27
+ * MIME types for supported image formats
28
+ */
29
+ export declare const IMAGE_MIME_TYPES: Record<string, string>;
30
+ /**
31
+ * Supported image file extensions (without leading dot)
32
+ */
33
+ export declare const SUPPORTED_IMAGE_EXTENSIONS: readonly string[];
34
+ /**
35
+ * Read image file and convert to base64 data URI
36
+ */
37
+ export declare function readPhotoAsDataUri(photoPath: string): string;
27
38
  /**
28
39
  * Escape HTML special characters
29
40
  */
30
41
  export declare function escapeHtml(text: string): string;
42
+ /**
43
+ * Input type for detectLanguage function
44
+ */
45
+ export interface DetectLanguageInput {
46
+ readonly metadata: {
47
+ name_ja?: string;
48
+ };
49
+ readonly sections: readonly {
50
+ title: string;
51
+ }[];
52
+ }
53
+ /**
54
+ * Detect language from CV content
55
+ * Checks for Japanese name or Japanese section titles
56
+ */
57
+ export declare function detectLanguage(cv: DetectLanguageInput): 'en' | 'ja';
31
58
  /**
32
59
  * Generate output files
33
60
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generator/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAIR,SAAS,EACT,cAAc,EACjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAG7D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,CAAC;AAErE;;GAEG;AACH,UAAU,OAAO;IACf,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;CAC7C;AAED;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,SAAS,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAOzE,CAAC;AAqCJ;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO/C;AAqOD;;GAEG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,OAAO,EACX,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,EAAE,CAAC,CA6EnB;AAED,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generator/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAKV,SAAS,EACT,cAAc,EACf,MAAM,oBAAoB,CAAC;AAM5B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAG7D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,qBAAqB,EAAE,CAAC;AAEjE;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,SAAS,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAOzE,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CACvC,SAAS,EACT;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAOlC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMnD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,EAAE,SAAS,MAAM,EAE5B,CAAC;AAE7B;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAY5D;AASD;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO/C;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACjD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,mBAAmB,GAAG,IAAI,GAAG,IAAI,CAgBnE;AA8OD;;GAEG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,OAAO,EACX,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,EAAE,CAAC,CAsFnB;AAED,eAAe,cAAc,CAAC"}
@@ -5,36 +5,50 @@
5
5
  import * as fs from 'fs';
6
6
  import * as path from 'path';
7
7
  import puppeteer from 'puppeteer';
8
- import { findSectionByTag, isSectionValidForFormat } from '../types/sections.js';
9
- import { generateCVEnHTML } from './resume_en.js';
10
- import { generateCVJaHTML } from './resume_ja.js';
8
+ import { findSectionByTag, isSectionValidForFormat, } from '../types/sections.js';
9
+ import { generateEnHtml } from './resume_en.js';
10
+ import { generateJaHtml } from './resume_ja.js';
11
11
  import { generateRirekishoHTML } from './rirekisho/index.js';
12
12
  // Re-export generators
13
- export { generateCVEnHTML, generateCVJaHTML, generateRirekishoHTML };
13
+ export { generateEnHtml, generateJaHtml, generateRirekishoHTML };
14
14
  /**
15
- * Page size dimensions in mm
15
+ * Page size dimensions in mm (portrait orientation for CV)
16
16
  */
17
17
  export const PAGE_SIZES = {
18
- a3: { width: 420, height: 297 },
18
+ a3: { width: 297, height: 420 },
19
19
  a4: { width: 210, height: 297 },
20
- b4: { width: 364, height: 257 },
21
- b5: { width: 176, height: 250 },
20
+ b4: { width: 257, height: 364 },
21
+ b5: { width: 182, height: 257 },
22
22
  letter: { width: 215.9, height: 279.4 },
23
23
  };
24
+ /**
25
+ * Page size dimensions in mm (landscape orientation for Rirekisho)
26
+ */
27
+ export const PAGE_SIZES_LANDSCAPE = {
28
+ a3: { width: 420, height: 297 },
29
+ a4: { width: 297, height: 210 },
30
+ b4: { width: 364, height: 257 },
31
+ b5: { width: 257, height: 182 },
32
+ letter: { width: 279.4, height: 215.9 },
33
+ };
24
34
  /**
25
35
  * MIME types for supported image formats
26
36
  */
27
- const IMAGE_MIME_TYPES = {
37
+ export const IMAGE_MIME_TYPES = {
28
38
  '.png': 'image/png',
29
39
  '.jpg': 'image/jpeg',
30
40
  '.jpeg': 'image/jpeg',
31
41
  '.tiff': 'image/tiff',
32
42
  '.tif': 'image/tiff',
33
43
  };
44
+ /**
45
+ * Supported image file extensions (without leading dot)
46
+ */
47
+ export const SUPPORTED_IMAGE_EXTENSIONS = Object.keys(IMAGE_MIME_TYPES).map((ext) => ext.slice(1));
34
48
  /**
35
49
  * Read image file and convert to base64 data URI
36
50
  */
37
- function readPhotoAsDataUri(photoPath) {
51
+ export function readPhotoAsDataUri(photoPath) {
38
52
  const ext = path.extname(photoPath).toLowerCase();
39
53
  const mimeType = IMAGE_MIME_TYPES[ext];
40
54
  if (!mimeType) {
@@ -63,14 +77,17 @@ export function escapeHtml(text) {
63
77
  }
64
78
  /**
65
79
  * Detect language from CV content
80
+ * Checks for Japanese name or Japanese section titles
66
81
  */
67
- function detectLanguage(cv) {
82
+ export function detectLanguage(cv) {
83
+ // Import isJapaneseText from sections to avoid duplication
84
+ const isJapanese = (text) => /[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF]/.test(text);
68
85
  // Check if name_ja exists or if sections have Japanese titles
69
86
  if (cv.metadata.name_ja)
70
87
  return 'ja';
71
88
  for (const section of cv.sections) {
72
89
  // Check for Japanese characters in title
73
- if (/[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF]/.test(section.title)) {
90
+ if (isJapanese(section.title)) {
74
91
  return 'ja';
75
92
  }
76
93
  }
@@ -79,19 +96,28 @@ function detectLanguage(cv) {
79
96
  /**
80
97
  * Default section order for CV format
81
98
  */
82
- const DEFAULT_CV_SECTION_ORDER = ['summary', 'experience', 'education', 'skills', 'certifications', 'languages', 'competencies', 'motivation'];
99
+ const DEFAULT_CV_SECTION_ORDER = [
100
+ 'summary',
101
+ 'experience',
102
+ 'education',
103
+ 'skills',
104
+ 'certifications',
105
+ 'languages',
106
+ 'competencies',
107
+ 'motivation',
108
+ ];
83
109
  /**
84
110
  * Resolve section ID from tag or ID
85
111
  * Returns the section ID if input matches a tag or is already an ID
86
112
  */
87
113
  function resolveSectionId(input, sections) {
88
114
  // First check if it's a direct section ID match
89
- const directMatch = sections.find(s => s.id === input);
115
+ const directMatch = sections.find((s) => s.id === input);
90
116
  if (directMatch) {
91
117
  return directMatch.id;
92
118
  }
93
119
  // Then check if it matches a section title (case-insensitive)
94
- const titleMatch = sections.find(s => s.title.toLowerCase() === input.toLowerCase());
120
+ const titleMatch = sections.find((s) => s.title.toLowerCase() === input.toLowerCase());
95
121
  if (titleMatch) {
96
122
  return titleMatch.id;
97
123
  }
@@ -99,7 +125,7 @@ function resolveSectionId(input, sections) {
99
125
  const def = findSectionByTag(input);
100
126
  if (def) {
101
127
  // Check if this section exists in the input
102
- const sectionExists = sections.find(s => s.id === def.id);
128
+ const sectionExists = sections.find((s) => s.id === def.id);
103
129
  if (sectionExists) {
104
130
  return def.id;
105
131
  }
@@ -111,12 +137,12 @@ function resolveSectionId(input, sections) {
111
137
  * If sectionOrder is provided, only include sections in that order
112
138
  * If not provided, use default order for CV or include all sections for rirekisho
113
139
  */
114
- function filterAndOrderSections(sections, format, sectionOrder, logger) {
140
+ function filterAndOrderSections(sections, format, logger, sectionOrder) {
115
141
  // Get all section IDs from input
116
- const allSectionIds = sections.map(s => s.id);
142
+ const allSectionIds = sections.map((s) => s.id);
117
143
  // Determine which sections are valid for this format
118
- const validSectionIds = allSectionIds.filter(id => isSectionValidForFormat(id, format));
119
- const invalidSectionIds = allSectionIds.filter(id => !isSectionValidForFormat(id, format));
144
+ const validSectionIds = allSectionIds.filter((id) => isSectionValidForFormat(id, format));
145
+ const invalidSectionIds = allSectionIds.filter((id) => !isSectionValidForFormat(id, format));
120
146
  let includedSectionIds;
121
147
  let skippedSectionIds;
122
148
  if (format === 'cv') {
@@ -125,13 +151,15 @@ function filterAndOrderSections(sections, format, sectionOrder, logger) {
125
151
  const resolvedOrder = [];
126
152
  for (const input of sectionOrder) {
127
153
  const resolvedId = resolveSectionId(input, sections);
128
- if (resolvedId && validSectionIds.includes(resolvedId) && !resolvedOrder.includes(resolvedId)) {
154
+ if (resolvedId &&
155
+ validSectionIds.includes(resolvedId) &&
156
+ !resolvedOrder.includes(resolvedId)) {
129
157
  resolvedOrder.push(resolvedId);
130
158
  }
131
159
  }
132
160
  // Use custom order - only include sections that are in sectionOrder AND valid for format
133
161
  includedSectionIds = resolvedOrder;
134
- skippedSectionIds = validSectionIds.filter(id => !resolvedOrder.includes(id));
162
+ skippedSectionIds = validSectionIds.filter((id) => !resolvedOrder.includes(id));
135
163
  }
136
164
  else {
137
165
  // Use default order for CV
@@ -166,7 +194,7 @@ function filterAndOrderSections(sections, format, sectionOrder, logger) {
166
194
  logger.info({ sections: invalidSectionIds }, `Sections skipped (not valid for ${format} format)`);
167
195
  }
168
196
  // Build ordered section list
169
- const sectionMap = new Map(sections.map(s => [s.id, s]));
197
+ const sectionMap = new Map(sections.map((s) => [s.id, s]));
170
198
  const orderedSections = [];
171
199
  for (const id of includedSectionIds) {
172
200
  const section = sectionMap.get(id);
@@ -178,20 +206,24 @@ function filterAndOrderSections(sections, format, sectionOrder, logger) {
178
206
  }
179
207
  /**
180
208
  * Generate HTML for CV format
209
+ * Note: chronologicalOrder is not yet implemented for CV format.
210
+ * CV format currently uses the order as defined in the markdown file.
181
211
  */
182
- function generateCVHTML(cv, paperSize, _chronologicalOrder, sectionOrder, logger, customStylesheet) {
212
+ function generateHtml(cv, paperSize, sectionOrder, logger, customStylesheet) {
183
213
  const language = detectLanguage(cv);
184
- // TODO: Add chronological order support for CV format
185
214
  // Filter and order sections if logger is provided
186
215
  let sections = cv.sections;
187
216
  if (logger) {
188
- sections = filterAndOrderSections(cv.sections, 'cv', sectionOrder, logger);
217
+ sections = filterAndOrderSections(cv.sections, 'cv', logger, sectionOrder);
189
218
  }
190
219
  const filteredCv = { ...cv, sections };
220
+ const options = customStylesheet
221
+ ? { paperSize, customStylesheet }
222
+ : { paperSize };
191
223
  if (language === 'ja') {
192
- return generateCVJaHTML(filteredCv, { paperSize, customStylesheet });
224
+ return generateJaHtml(filteredCv, options);
193
225
  }
194
- return generateCVEnHTML(filteredCv, { paperSize, customStylesheet });
226
+ return generateEnHtml(filteredCv, options);
195
227
  }
196
228
  /**
197
229
  * Generate PDF from HTML
@@ -208,15 +240,7 @@ async function generatePDF(html, paperSize, isRirekisho) {
208
240
  let pdfOptions;
209
241
  if (isRirekisho) {
210
242
  // Rirekisho uses landscape orientation with the specified paper size
211
- // PAGE_SIZES for rirekisho are already in landscape (width > height)
212
- const rirekishoSizes = {
213
- a3: { width: 420, height: 297 },
214
- a4: { width: 297, height: 210 },
215
- b4: { width: 364, height: 257 },
216
- b5: { width: 257, height: 182 },
217
- letter: { width: 279.4, height: 215.9 },
218
- };
219
- const rirekishoSize = rirekishoSizes[paperSize];
243
+ const rirekishoSize = PAGE_SIZES_LANDSCAPE[paperSize];
220
244
  await page.setViewport({
221
245
  width: Math.round(rirekishoSize.width * 3.78),
222
246
  height: Math.round(rirekishoSize.height * 3.78),
@@ -274,7 +298,7 @@ export async function generateOutput(cv, config, logger) {
274
298
  let html;
275
299
  if (format === 'rirekisho') {
276
300
  // Log sections for rirekisho
277
- const sections = filterAndOrderSections(cv.sections, 'rirekisho', undefined, logger);
301
+ const sections = filterAndOrderSections(cv.sections, 'rirekisho', logger);
278
302
  const filteredCv = { ...cv, sections };
279
303
  // Read photo file if provided (only for rirekisho)
280
304
  let photoDataUri;
@@ -286,12 +310,12 @@ export async function generateOutput(cv, config, logger) {
286
310
  paperSize: config.paperSize,
287
311
  chronologicalOrder,
288
312
  hideMotivation: config.hideMotivation,
289
- photoDataUri,
290
- customStylesheet,
313
+ ...(photoDataUri !== undefined && { photoDataUri }),
314
+ ...(customStylesheet !== undefined && { customStylesheet }),
291
315
  });
292
316
  }
293
317
  else {
294
- html = generateCVHTML(cv, config.paperSize, chronologicalOrder, config.sectionOrder, logger, customStylesheet);
318
+ html = generateHtml(cv, config.paperSize, config.sectionOrder, logger, customStylesheet);
295
319
  }
296
320
  const baseName = path.basename(config.output);
297
321
  const suffix = format === 'rirekisho' ? '_rirekisho' : '_cv';