pidgin/nest

Parents b6ca8b56840c
Children 14a004a99ec9
Add a script to add lastmod date to content frontmatter
--- a/package-lock.json Wed May 29 23:07:11 2019 +0100
+++ b/package-lock.json Thu Jun 06 01:03:11 2019 +0100
@@ -850,9 +850,9 @@
}
},
"js-yaml": {
- "version": "3.12.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz",
- "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==",
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@@ -998,6 +998,12 @@
"url-parse": "^1.4.4"
}
},
+ "moment": {
+ "version": "2.24.0",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
+ "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
+ "dev": true
+ },
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
--- a/package.json Wed May 29 23:07:11 2019 +0100
+++ b/package.json Thu Jun 06 01:03:11 2019 +0100
@@ -2,6 +2,7 @@
"private": true,
"dependencies": {
"js-beautify": "^1.8.9",
+ "js-yaml": "^3.13.1",
"svgo": "^1.1.1"
},
"devDependencies": {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/update-lastmod.js Thu Jun 06 01:03:11 2019 +0100
@@ -0,0 +1,159 @@
+/**
+ * For each content page:
+ * * reads last change date form mercurial
+ * * writes last edite date to front matter
+ */
+
+/*****************************************************************************
+ * Imports
+ *****************************************************************************/
+
+const fs = require('fs').promises
+const path = require('path')
+const { spawn } = require('child_process')
+
+const front = require('front-matter')
+const yaml = require('js-yaml')
+
+/*****************************************************************************
+ * Set Up
+ *****************************************************************************/
+
+const mdRegex = /\.md$/
+const hgLogArgs = ['log', '--follow', '--pager', 'never', '--color', 'never']
+const yamlDumpSettings = { indent: 4 }
+
+/*****************************************************************************
+ * Execution
+ *****************************************************************************/
+
+getMdPaths(path.join(__dirname, '../hugo/content/')).then(paths =>
+ paths.map(async function(file) {
+ const [commits, { attributes, body }] = await Promise.all([
+ getCommits(file),
+ getFrontMatter(file),
+ ])
+ const lastmod = commits[0].date
+ const newFrontString = yaml
+ .dump({ ...attributes, lastmod }, yamlDumpSettings)
+ .trim()
+
+ const output = `---\n${newFrontString}\n---\n\n${body}`
+
+ await fs.writeFile(file, output)
+ console.log(`Updated: ${file}`)
+ })
+)
+
+/*****************************************************************************
+ * Mercurial
+ *****************************************************************************/
+
+/**
+ * Get an orderd array commits for a file
+ * @param {string} file the file path
+ */
+function getCommits(file) {
+ return new Promise((resolve, reject) => {
+ const log = spawn('hg', [...hgLogArgs, file])
+ const commits = []
+
+ log.stdout.on('data', data => {
+ commits.push(
+ ...data
+ .toString()
+ .split('\n\n')
+ .filter(Boolean)
+ .map(parseCommit)
+ .filter(filterCommits)
+ )
+ })
+
+ log.on('close', code => {
+ if (code !== 0) {
+ return reject(
+ new Error(`Unexpected return code from hg log ${code}`)
+ )
+ }
+
+ resolve(commits.sort((a, b) => a.date - b.date).reverse())
+ })
+ })
+}
+
+/**
+ * Converts the raw commit data from log into a a commit object
+ * @param {string} commitString raw commit from hg output
+ */
+function parseCommit(commitString) {
+ const commit = {}
+
+ commitString
+ .split('\n')
+ .filter(Boolean)
+ .forEach(line => {
+ const [, key, value] = /(\w+):\s+(.+)/.exec(line)
+
+ switch (key) {
+ case 'parent':
+ case 'bookmark':
+ if (!commit[key]) {
+ commit[key] = []
+ }
+
+ commit[key].push(value)
+ break
+ case 'date':
+ commit[key] = new Date(value)
+ break
+ default:
+ commit[key] = value
+ }
+ })
+
+ return commit
+}
+
+/**
+ * Filters out commits that contain an automation flag
+ * @param {commit}
+ */
+const filterCommits = ({ summary }) =>
+ !/^\[(Automated|Auto|Minor)\]/i.test(summary)
+
+/*****************************************************************************
+ * Helpers
+ *****************************************************************************/
+
+/**
+ * reads and parses a markdown file for frontmatter
+ * @param {string} file path to markdown file
+ */
+async function getFrontMatter(file) {
+ return fs.readFile(file, 'utf8').then(contents => front(contents))
+}
+
+/**
+ * creates a list of all markdown files in a directory
+ * @param {string} directory directory to search for markdown files
+ */
+async function getMdPaths(directory) {
+ let output = []
+ let items = (await fs.readdir(directory)).map(i => path.join(directory, i))
+
+ while (items.length) {
+ const item = items.pop()
+ const stat = await fs.stat(item)
+
+ if (stat.isDirectory()) {
+ const nueveau = (await fs.readdir(item)).map(i =>
+ path.join(item, i)
+ )
+ items.push(...nueveau)
+ } else if (stat.isFile() && mdRegex.test(item)) {
+ output.push(item)
+ }
+ }
+
+ return output.sort()
+}