feat: initial prototype
Node.js CI / Lint and Test (push) Failing after 58s

This commit is contained in:
2025-10-07 11:38:38 -07:00
parent 2bfbe921ea
commit 9896bff829
11 changed files with 5725 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
name: Node.js CI
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
lint:
name: Lint and Test
steps:
- name: Checkout Source Files
uses: actions/checkout@v4
- name: Use Node.js v22
uses: actions/setup-node@v4
with:
node-version: 22
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 9
- name: Install Dependencies
run: pnpm install
- name: Lint Source Files
run: pnpm run lint
- name: Verify Build
run: pnpm run build
- name: Run Tests
run: pnpm run test
+6
View File
@@ -0,0 +1,6 @@
prod
node_modules
review.md
content/**/*
!.gitkeep
fcc-review-pages.pdf
+6
View File
@@ -0,0 +1,6 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": ["typescript"],
}
+1
View File
@@ -0,0 +1 @@
This directory is where your markdown files go.
+11
View File
@@ -0,0 +1,11 @@
import NaomisConfig from '@nhcarrigan/eslint-config';
export default [
...NaomisConfig,
{
rules: {
"no-console" : "off",
"no-await-in-loop": "off"
}
}
];
+29
View File
@@ -0,0 +1,29 @@
{
"name": "fcc-review-generator",
"version": "1.0.0",
"description": "A quick tool that aggregates all of the review pages from freeCodeCamp into a single page.",
"main": "index.js",
"type": "module",
"scripts": {
"postinstall": "pnpx puppeteer browsers install chrome",
"start": "tsx src/index.ts",
"build": "tsc",
"test": "echo \"Error: no test specified\" && exit 1",
"lint": "eslint src --max-warnings 0"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.18.0",
"devDependencies": {
"@nhcarrigan/eslint-config": "5.2.0",
"@nhcarrigan/typescript-config": "4.0.0",
"@types/node": "24.7.0",
"eslint": "9.37.0",
"tsx": "4.20.6",
"typescript": "5.9.3"
},
"dependencies": {
"md-to-pdf": "5.2.4"
}
}
+5486
View File
File diff suppressed because it is too large Load Diff
+46
View File
@@ -0,0 +1,46 @@
/* eslint-disable @typescript-eslint/naming-convention -- The settings are snake case. */
/**
* @copyright NHCarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import type { PdfConfig } from "md-to-pdf/dist/lib/config.js";
export const options: Partial<PdfConfig> = {
pdf_options: {
displayHeaderFooter: true,
footerTemplate: `<section>
<div class="flexy"><p><a href='https://chat.nhcarrigan.com'>Join Naomi's Discord</a></p><p>Page <span class="pageNumber"></span>
of <span class="totalPages"></span></p></div>
</section>`,
format: "Legal",
headerTemplate: ` <style>
section {
margin: 0 auto;
font-family: system-ui;
font-size: 11px;
width: 100%;
}
.flexy {
display: flex;
flex-direction: row;
justify-content: space-evenly;
align-items: center;
width: 100%;
}
.centre {
text-align: center;
}
</style>
<section class="centre">
<span>Naomi's freeCodeCamp Review</span>
</section>`,
margin: {
bottom: "0.75in",
left: "0.75in",
right: "0.75in",
top: "0.75in",
},
},
};
+15
View File
@@ -0,0 +1,15 @@
/**
* @copyright NHCarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
export const starterText = `# Naomi's freeCodeCamp Review
Hello! This PDF contains all of the review pages (unless I missed one) from freeCodeCamp's full stack developer curriculum.
Before we dive in, a quick disclaimer: This is not an officially sanctioned document, and I make no warranty that the information in this document will be kept up to date. This version was created on ${new Date().toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric" })}.
Questions? Comments? Document is out of date and you want to scream at me about it? https://chat.nhcarrigan.com
HERE WE GO!\n\n`;
+80
View File
@@ -0,0 +1,80 @@
/**
* @copyright NHCarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import {
readFile,
appendFile,
writeFile,
readdir,
unlink,
} from "node:fs/promises";
import { join } from "node:path";
import { mdToPdf } from "md-to-pdf";
import { options } from "./config/options.js";
import { starterText } from "./config/text.js";
const readDirectoryRecursively = async(
directory: string,
): Promise<Array<string>> => {
const dirents = await readdir(directory, { withFileTypes: true });
const files = await Promise.all(
dirents.map(async(dirent) => {
const result = join(directory, dirent.name);
return dirent.isDirectory()
? await readDirectoryRecursively(result)
: result;
}),
);
return files.flat();
};
const rollupFiles = async(
inputDirectory: string,
outputFile: string,
): Promise<void> => {
try {
await writeFile(outputFile, `${starterText}\n`);
const files = await readDirectoryRecursively(inputDirectory);
for (const file of files) {
if (file === ".gitkeep") {
continue;
}
if (file.endsWith(".md")) {
const content = await readFile(file, "utf8");
const strippedFrontmatter = content.
replace(/^---\n[\S\s]*?\n---\n/, "").
trim();
// Title is in front matter
const title = /^title: (?<title>.*)/m.exec(content)?.groups?.title;
console.log(title);
const strippedFccHeadings = strippedFrontmatter.
replace(/^#+ --.*--/, "").
trim();
await appendFile(
outputFile,
`---\n\n# ${title ?? "Unknown"}\n${strippedFccHeadings}\n\n`,
);
}
}
console.log(`Successfully rolled up files into ${outputFile}`);
} catch (error) {
console.error("Error rolling up files:", error);
}
};
const createPdf = async(inputPath: string): Promise<void> => {
const pdf = await mdToPdf({ path: inputPath }, options);
console.log("PDF created!");
await writeFile("./fcc-review-pages.pdf", pdf.content);
console.log("PDF written to disk!");
};
const inputDirectory = "./content";
const outputFilePath = "./review.md";
await rollupFiles(inputDirectory, outputFilePath);
await createPdf(outputFilePath);
await unlink(outputFilePath);
+7
View File
@@ -0,0 +1,7 @@
{
"extends": "@nhcarrigan/typescript-config",
"compilerOptions": {
"outDir": "./prod",
"rootDir": "./src"
},
}