diff --git a/package-lock.json b/package-lock.json index 76f36f2..55c2885 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,10 +14,11 @@ "@koj/config": "^1.2.11", "@vercel/ncc": "^0.34.0", "emoji-flags": "^1.3.0", + "front-matter": "^4.0.2", "fs-extra": "^10.1.0", "markdown-to-txt": "^2.0.1", "prettier": "^2.7.1", - "truncate-sentences": "^1.0.0" + "truncate-sentences": "^2.0.0" }, "devDependencies": { "@semantic-release/changelog": "^6.0.1", @@ -5097,7 +5098,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "dependencies": { "sprintf-js": "~1.0.2" } @@ -6128,6 +6128,14 @@ "readable-stream": "^2.0.0" } }, + "node_modules/front-matter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", + "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", + "dependencies": { + "js-yaml": "^3.13.1" + } + }, "node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -8450,7 +8458,6 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -8481,14 +8488,6 @@ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, - "node_modules/json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha512-i/J297TW6xyj7sDFa7AmBPkQvLIxWr2kKPWI26tXydnZrzVAocNqn5DMNT1Mzk0vit1V5UkRM7C1KdVNp7Lmcg==", - "dependencies": { - "jsonify": "~0.0.0" - } - }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -8517,14 +8516,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha512-trvBk1ki43VZptdBI5rIlG4YOzyeH/WefQt5rj1grasPn4iiZWKet8nkgc4GlsAylaztn0qZfUYOiTsASJFdNA==", - "engines": { - "node": "*" - } - }, "node_modules/jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -9058,15 +9049,16 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/natural": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/natural/-/natural-0.6.3.tgz", - "integrity": "sha512-78fcEdNN6Y4pv8SOLPDhJTlUG+8IiQzNx0nYpl0k7q00K4ZZuds+wDWfSa6eeiPcSQDncvV44WWGsi70/ZP3+w==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/natural/-/natural-5.2.3.tgz", + "integrity": "sha512-fsGGpbU15YBc2oQCEsi0t7ZeF3VmKyxDhgWucQTPk4zaDFzeZtquRbZt4xlznN2ZUlH88215HcThMYaDHFM48Q==", "dependencies": { "afinn-165": "^1.0.2", "apparatus": "^0.0.10", - "json-stable-stringify": "^1.0.1", + "safe-stable-stringify": "^2.2.0", "sylvester": "^0.0.12", - "underscore": "^1.3.1" + "underscore": "^1.9.1", + "wordnet-db": "^3.1.11" }, "engines": { "node": ">=0.4.10" @@ -12066,6 +12058,14 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/safe-stable-stringify": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.1.tgz", + "integrity": "sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA==", + "engines": { + "node": ">=10" + } + }, "node_modules/semantic-release": { "version": "19.0.5", "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-19.0.5.tgz", @@ -12390,8 +12390,7 @@ "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "node_modules/stack-utils": { "version": "2.0.6", @@ -12698,11 +12697,11 @@ } }, "node_modules/truncate-sentences": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/truncate-sentences/-/truncate-sentences-1.0.0.tgz", - "integrity": "sha512-Q+BUmkm/xq1Es2dVK9B0L36XnrC/Zp3BVPHLydR70iOEMd3Sr+CMaLgtPwDvPuV0qY3Jye2vvMLRfOU5ZA1Y0g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/truncate-sentences/-/truncate-sentences-2.0.0.tgz", + "integrity": "sha512-DrREvlBJUaJ1gIEXCVdSZJGyNT2NU3c6QJD43hHycwf2/I2u5Bj7twzIyF2gTADWttWPzQdHiGy5TsjNgBwbAA==", "dependencies": { - "natural": "^0.6.3" + "natural": "^5.2.3" } }, "node_modules/ts-jest": { @@ -12811,9 +12810,9 @@ } }, "node_modules/underscore": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz", - "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==" + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" }, "node_modules/unique-string": { "version": "2.0.0", @@ -12957,6 +12956,14 @@ "node": ">= 8" } }, + "node_modules/wordnet-db": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/wordnet-db/-/wordnet-db-3.1.14.tgz", + "integrity": "sha512-zVyFsvE+mq9MCmwXUWHIcpfbrHHClZWZiVOzKSxNJruIcFn2RbY55zkhiAMMxM8zCVSmtNiViq8FsAZSFpMYag==", + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -16821,7 +16828,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "requires": { "sprintf-js": "~1.0.2" } @@ -17590,6 +17596,14 @@ "readable-stream": "^2.0.0" } }, + "front-matter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", + "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", + "requires": { + "js-yaml": "^3.13.1" + } + }, "fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -19300,7 +19314,6 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -19322,14 +19335,6 @@ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha512-i/J297TW6xyj7sDFa7AmBPkQvLIxWr2kKPWI26tXydnZrzVAocNqn5DMNT1Mzk0vit1V5UkRM7C1KdVNp7Lmcg==", - "requires": { - "jsonify": "~0.0.0" - } - }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -19350,11 +19355,6 @@ "universalify": "^2.0.0" } }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha512-trvBk1ki43VZptdBI5rIlG4YOzyeH/WefQt5rj1grasPn4iiZWKet8nkgc4GlsAylaztn0qZfUYOiTsASJFdNA==" - }, "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -19779,15 +19779,16 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "natural": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/natural/-/natural-0.6.3.tgz", - "integrity": "sha512-78fcEdNN6Y4pv8SOLPDhJTlUG+8IiQzNx0nYpl0k7q00K4ZZuds+wDWfSa6eeiPcSQDncvV44WWGsi70/ZP3+w==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/natural/-/natural-5.2.3.tgz", + "integrity": "sha512-fsGGpbU15YBc2oQCEsi0t7ZeF3VmKyxDhgWucQTPk4zaDFzeZtquRbZt4xlznN2ZUlH88215HcThMYaDHFM48Q==", "requires": { "afinn-165": "^1.0.2", "apparatus": "^0.0.10", - "json-stable-stringify": "^1.0.1", + "safe-stable-stringify": "^2.2.0", "sylvester": "^0.0.12", - "underscore": "^1.3.1" + "underscore": "^1.9.1", + "wordnet-db": "^3.1.11" } }, "natural-compare": { @@ -21829,6 +21830,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safe-stable-stringify": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.1.tgz", + "integrity": "sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA==" + }, "semantic-release": { "version": "19.0.5", "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-19.0.5.tgz", @@ -22091,8 +22097,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "stack-utils": { "version": "2.0.6", @@ -22323,11 +22328,11 @@ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==" }, "truncate-sentences": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/truncate-sentences/-/truncate-sentences-1.0.0.tgz", - "integrity": "sha512-Q+BUmkm/xq1Es2dVK9B0L36XnrC/Zp3BVPHLydR70iOEMd3Sr+CMaLgtPwDvPuV0qY3Jye2vvMLRfOU5ZA1Y0g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/truncate-sentences/-/truncate-sentences-2.0.0.tgz", + "integrity": "sha512-DrREvlBJUaJ1gIEXCVdSZJGyNT2NU3c6QJD43hHycwf2/I2u5Bj7twzIyF2gTADWttWPzQdHiGy5TsjNgBwbAA==", "requires": { - "natural": "^0.6.3" + "natural": "^5.2.3" } }, "ts-jest": { @@ -22383,9 +22388,9 @@ "optional": true }, "underscore": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz", - "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==" + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" }, "unique-string": { "version": "2.0.0", @@ -22497,6 +22502,11 @@ "isexe": "^2.0.0" } }, + "wordnet-db": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/wordnet-db/-/wordnet-db-3.1.14.tgz", + "integrity": "sha512-zVyFsvE+mq9MCmwXUWHIcpfbrHHClZWZiVOzKSxNJruIcFn2RbY55zkhiAMMxM8zCVSmtNiViq8FsAZSFpMYag==" + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", diff --git a/package.json b/package.json index 35e1b35..e8c7243 100644 --- a/package.json +++ b/package.json @@ -45,10 +45,11 @@ "@koj/config": "^1.2.11", "@vercel/ncc": "^0.34.0", "emoji-flags": "^1.3.0", + "front-matter": "^4.0.2", "fs-extra": "^10.1.0", "markdown-to-txt": "^2.0.1", "prettier": "^2.7.1", - "truncate-sentences": "^1.0.0" + "truncate-sentences": "^2.0.0" }, "jest": { "preset": "ts-jest", diff --git a/src/index.ts b/src/index.ts index 99d148b..606a42f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,9 +5,12 @@ import markdownToTxt from "markdown-to-txt"; import { join } from "path"; import { format } from "prettier"; import truncate from "truncate-sentences"; +import frontMatter from "front-matter"; interface Note { slug: string; + path: string; + source: string; title?: string; excerpt?: string; date: Date; @@ -22,52 +25,51 @@ interface Note { * @returns Parsed note */ const parseNoteFile = async (dirName: string, year: string, file: string): Promise => { - const contents = await readFile(join(".", dirName, year, file), "utf8"); - const dateInput = - (contents.split("\n").find((line) => line.startsWith("date: ")) || "").replace("date: ", "") || - execSync(`git log --format=%aD ${dirName}/${year}/${file} | tail -1`).toString().trim(); - const date = new Date(dateInput); - const title = - (contents.split("\n").find((line) => line.startsWith("title: ")) || "").replace( - "title: ", - "" - ) || - ( - (contents.split("\n").find((line) => line.startsWith("# ")) || "").split("# ")[1] || "" - ).trim() || - undefined; + const path = join(".", dirName, year, file); + const source = `https://github.com/${process.env.GITHUB_REPOSITORY}/blob/${process.env.GITHUB_REF_NAME}/${path}`; + const contents = await readFile(path, "utf8"); + const { attributes, body } = frontMatter<{ + date?: unknown; + title?: unknown; + excerpt?: unknown; + description?: unknown; + summary?: unknown; + }>(contents); + + const date: Date = + "date" in attributes && typeof attributes.date === "string" + ? new Date(attributes.date) + : "date" in attributes && attributes.date instanceof Date + ? attributes.date + : // Use git file creation date if no date is specified + new Date( + execSync(`git log --format=%aD ${dirName}/${year}/${file} | tail -1`).toString().trim() + ); + + const title = ( + "title" in attributes && typeof attributes.title === "string" + ? attributes.title + : body.match(/^# (.*)/m)?.[2] + )?.trim(); + if (!title) throw new Error(`Unable to parse title in ${path}`); + const excerpt = - (contents.split("\n").find((line) => line.startsWith("excerpt: ")) || "").replace( - "excerpt: ", - "" - ) || - (contents.split("\n").find((line) => line.startsWith("description: ")) || "").replace( - "description: ", - "" - ) || - (contents.split("\n").find((line) => line.startsWith("summary: ")) || "").replace( - "summary: ", - "" - ) || - (title - ? ((contents.split(title)[1] || "").includes("---\n") - ? (contents.split(title)[1] || "").split("---\n").pop() || "" - : contents.split(title)[1] || "" - ) - .trim() - .split("\n") - .find((line) => line.length > 10) || - ((contents.split(title)[1] || "").includes("---\n") - ? (contents.split(title)[1] || "").split("---\n").pop() || "" - : contents.split(title)[1] || "" - ).trim() - : undefined); + "excerpt" in attributes && typeof attributes.excerpt === "string" + ? attributes.excerpt + : "description" in attributes && typeof attributes.description === "string" + ? attributes.description + : "summary" in attributes && typeof attributes.summary === "string" + ? attributes.summary + : body.split(title)[1].trim(); + return { slug: file, + path, + source, title: title, date, excerpt: excerpt ? truncate(markdownToTxt(excerpt), 500) : undefined, - words: contents.split(" ").length, + words: body.split(" ").length, }; };