feat: ship it let's gooooooooo
Node.js CI / Lint and Test (push) Successful in 40s

This commit is contained in:
2025-04-08 17:25:10 -07:00
parent daed9f26ab
commit abe0c7f94c
15 changed files with 6335 additions and 14 deletions
+267
View File
@@ -0,0 +1,267 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { readFile, writeFile, copyFile, stat, mkdir } from "node:fs/promises";
import { join } from "node:path";
// eslint-disable-next-line import/no-extraneous-dependencies -- Since this is a dev script, there are no production dependencies.
import { parse, stringify } from "yaml";
import type { Resume } from "./interfaces/resume.js";
const htmlBeginning = `<!DOCTYPE html>
<html lang="en">
<head>
<title>Naomi Carrigan</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="This is Naomi's full work history!" />
<script
src="https://cdn.nhcarrigan.com/headers/index.js"
async
defer
></script>
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<main>`;
const htmlEnd = ` </main>
</body>
<script src="./dates.js"></script>
</html>`;
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- parse does not accept a generic.
const yaml = (await parse(
await readFile(join(process.cwd(), "src", "source.yaml"), "utf8"),
)) as Resume;
const currentEmployment = yaml.employment.
filter((item) => {
return item.end_date === "Present";
}).
sort((a, b) => {
return (
new Date(`5${b.start_date}`).getTime()
- new Date(`5${a.start_date}`).getTime()
);
});
const currentVolunteer = yaml.volunteer.
filter((item) => {
return item.end_date === "Present";
}).
sort((a, b) => {
return (
new Date(`5${b.start_date}`).getTime()
- new Date(`5${a.start_date}`).getTime()
);
});
const pastEmployment = yaml.employment.
filter((item) => {
return item.end_date !== "Present";
}).
sort((a, b) => {
return (
new Date(`5${b.end_date}`).getTime()
- new Date(`5${a.end_date}`).getTime()
);
});
const pastVolunteer = yaml.volunteer.
filter((item) => {
return item.end_date !== "Present";
}).
sort((a, b) => {
return (
new Date(`5${b.end_date}`).getTime()
- new Date(`5${a.end_date}`).getTime()
);
});
yaml.employment = [ ...currentEmployment, ...pastEmployment ];
yaml.volunteer = [ ...currentVolunteer, ...pastVolunteer ];
yaml.certifications.sort((a, b) => {
return new Date(`5${b.date}`).getTime() - new Date(`5${a.date}`).getTime();
});
yaml.education.sort((a, b) => {
return (
new Date(`5${b.end_date}`).getTime() - new Date(`5${a.end_date}`).getTime()
);
});
yaml.projects.sort((a, b) => {
return new Date(`5${b.date}`).getTime() - new Date(`5${a.date}`).getTime();
});
yaml.publications.sort((a, b) => {
return new Date(b.date).getTime() - new Date(a.date).getTime();
});
const heading = `<h1>${yaml.name}</h1>
<p class="info">${yaml.contact}</p>
<p>${yaml.summary}</p>
<p id="links">
<a href="#employment">Employment</a> |
<a href="#volunteer">Volunteer Work</a> |
<a href="#education">Education</a> |
<a href="#certifications">Certifications</a> |
<a href="#projects">Projects</a> |
<a href="#publications">Publications</a> |
</p>
<p id="formats">
Get this resume in <a href="./resume.yaml">YAML</a> or <a href="./resume.json">JSON</a> format. You can also <span style="text-decoration: underline" onclick="window.print();return false;">print</span> the resume (and optionally save as a PDF).
</p>
<p class="cta">
Interested in hiring me?
<a href="https://testimonials.nhcarrigan.com" target="_blank"
>See what past clients have to say</a
>.`;
const employment = `<section id="employment">
<h2>Employment</h2>
${yaml.employment.
map((item) => {
return `<div class="card">
<p class="title">${item.title}</p>
<div>
<span class="company">${item.company}</span>
<span class="type">${item.type}</span>
</div>
<span class="date">${item.start_date} - ${item.end_date}</span>
${
item.prior_positions
? `<hr />
${item.prior_positions.
map((position, index) => {
return `<p class="subtitle${String(index + 1)}">${position.title}</p>
<p class="subdate${String(index + 1)}">${position.start_date} - ${
position.end_date
}</p>`;
}).
join("<hr/>")}`
: ""
}
<p class="description">${item.description}</p>
</div>`;
}).
join("\n")}
</section>`;
const volunteer = `<section id="volunteer">
<h2>Volunteer Work</h2>
${yaml.volunteer.
map((item) => {
return `<div class="card">
<p class="title">${item.title}</p>
<div>
<span class="company">${item.company}</span>
</div>
<span class="date">${item.start_date} - ${item.end_date}</span>
<p class="description">${item.description}</p>
</div>`;
}).
join("\n")}
</section>`;
const education = `<section id="education">
<h2>Education</h2>
${yaml.education.
map((item) => {
return `<div class="card">
<p class="title">${item.title}</p>
<div>
<span class="company">${item.institution}</span>
<span class="type">${item.type}</span>
</div>
<span class="date">${item.start_date} - ${item.end_date}</span>
<p class="description">${item.description}</p>
</div>`;
}).
join("\n")}
</section>`;
const certifications = `<section id="certifications">
<h2>Certifications</h2>
${yaml.certifications.
map((item) => {
return `<div class="card">
<p class="title">${item.title}</p>
<div>
<span class="company">${item.issuer}</span>
</div>
<span class="date">${item.date}</span>
</div>`;
}).
join("\n")}
</section>`;
const projects = `<section id="projects">
<h2>Projects</h2>
${yaml.projects.
map((item) => {
return `<div class="card">
<p class="title">${item.title}</p>
<div>
<span class="company">${item.company}</span>
</div>
<span class="date">${item.date}</span>
<p class="description">${item.description}</p>
</div>`;
}).
join("\n")}
</section>`;
const publications = `<section id="publications">
<h2>Publications</h2>
${yaml.publications.
map((item) => {
return `<div class="card">
<p class="title">${item.title}</p>
<div>
<span class="company">${item.company}</span>
</div>
<span class="date">${item.date}</span>
<p class="description">${item.description}</p>
</div>`;
}).
join("\n")}
</section>`;
const directoryStatus = await stat(join(process.cwd(), "site")).
then((status) => {
return status.isDirectory();
}).
catch(() => {
return false;
});
if (!directoryStatus) {
await mkdir(join(process.cwd(), "site"));
}
await writeFile(
join(process.cwd(), "site", "index.html"),
htmlBeginning
+ heading
+ employment
+ volunteer
+ education
+ certifications
+ projects
+ publications
+ htmlEnd,
"utf8",
);
await writeFile(
join(process.cwd(), "site", "resume.yaml"),
stringify(yaml),
"utf8",
);
await writeFile(
join(process.cwd(), "site", "resume.json"),
JSON.stringify(yaml, null, 2),
"utf8",
);
await copyFile(
join(process.cwd(), "src", "static", "style.css"),
join(process.cwd(), "site", "style.css"),
);
await copyFile(
join(process.cwd(), "src", "static", "dates.js"),
join(process.cwd(), "site", "dates.js"),
);