Skip to content

Commit

Permalink
Fixes #142.
Browse files Browse the repository at this point in the history
Adds `date: "git Last Modified"` support to use last git commit as `page.date` variable.
  • Loading branch information
zachleat committed Feb 17, 2022
1 parent 65ca928 commit 8f35e55
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 24 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"@sindresorhus/slugify": "^1.1.2",
"browser-sync": "^2.27.7",
"chokidar": "^3.5.3",
"cross-spawn": "^7.0.3",
"debug": "^4.3.3",
"dependency-graph": "^0.11.0",
"ejs": "^3.1.6",
Expand Down
58 changes: 35 additions & 23 deletions src/Template.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ const mkdir = util.promisify(fs.mkdir);
const os = require("os");
const path = require("path");
const normalize = require("normalize-path");
const isPlainObject = require("./Util/IsPlainObject");
const lodashGet = require("lodash/get");
const lodashSet = require("lodash/set");
const { DateTime } = require("luxon");

const isPlainObject = require("./Util/IsPlainObject");
const ConsoleLogger = require("./Util/ConsoleLogger");
const getDateFromGitLastUpdated = require("./Util/DateGitLastUpdated");

const TemplateData = require("./TemplateData");
const TemplateContent = require("./TemplateContent");
const TemplatePath = require("./TemplatePath");
Expand All @@ -19,7 +22,6 @@ const TemplateLayout = require("./TemplateLayout");
const TemplateFileSlug = require("./TemplateFileSlug");
const ComputedData = require("./ComputedData");
const Pagination = require("./Plugins/Pagination");
const ConsoleLogger = require("./Util/ConsoleLogger");
const TemplateBehavior = require("./TemplateBehavior");

const TemplateContentPrematureUseError = require("./Errors/TemplateContentPrematureUseError");
Expand Down Expand Up @@ -1016,30 +1018,40 @@ class Template extends TemplateContent {
// YAML does its own date parsing
debug("getMappedDate: YAML parsed it: %o", data.date);
return data.date;
} else {
// string
if (data.date.toLowerCase() === "last modified") {
return this._getDateInstance("ctimeMs");
} else if (data.date.toLowerCase() === "created") {
return this._getDateInstance("birthtimeMs");
} else {
// try to parse with Luxon
let date = DateTime.fromISO(data.date, { zone: "utc" });
if (!date.isValid) {
throw new Error(
`date front matter value (${data.date}) is invalid for ${this.inputPath}`
);
}
debug(
"getMappedDate: Luxon parsed %o: %o and %o",
data.date,
date,
date.toJSDate()
);
}

return date.toJSDate();
// special strings
if (data.date.toLowerCase() === "git last modified") {
let d = getDateFromGitLastUpdated(this.inputPath);
if (d) {
return d;
}

// return now if this file is not yet available in `git`
return Date.now();
}
if (data.date.toLowerCase() === "last modified") {
return this._getDateInstance("ctimeMs");
}
if (data.date.toLowerCase() === "created") {
return this._getDateInstance("birthtimeMs");
}

// try to parse with Luxon
let date = DateTime.fromISO(data.date, { zone: "utc" });
if (!date.isValid) {
throw new Error(
`date front matter value (${data.date}) is invalid for ${this.inputPath}`
);
}
debug(
"getMappedDate: Luxon parsed %o: %o and %o",
data.date,
date,
date.toJSDate()
);

return date.toJSDate();
} else {
let filepathRegex = this.inputPath.match(/(\d{4}-\d{2}-\d{2})/);
if (filepathRegex !== null) {
Expand Down
28 changes: 28 additions & 0 deletions src/Util/DateGitLastUpdated.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const spawn = require("cross-spawn");

/* Thank you to Vuepress!
* https://github.com/vuejs/vuepress/blob/89440ce552675859189ed4ab254ce19c4bba5447/packages/%40vuepress/plugin-last-updated/index.js
* MIT licensed: https://github.com/vuejs/vuepress/blob/89440ce552675859189ed4ab254ce19c4bba5447/LICENSE
*/
function getGitLastUpdatedTimeStamp(filePath) {
return (
parseInt(
spawn
.sync(
"git",
// Formats https://www.git-scm.com/docs/git-log#_pretty_formats
// %at author date, UNIX timestamp
["log", "-1", "--format=%at", filePath]
)
.stdout.toString("utf-8")
) * 1000
);
}

// return a Date
module.exports = function (inputPath) {
let timestamp = getGitLastUpdatedTimeStamp(inputPath);
if (timestamp) {
return new Date(timestamp);
}
};
12 changes: 12 additions & 0 deletions test/EleventyTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const test = require("ava");
const Eleventy = require("../src/Eleventy");
const EleventyWatchTargets = require("../src/EleventyWatchTargets");
const TemplateConfig = require("../src/TemplateConfig");
const DateGitLastUpdated = require("../src/Util/DateGitLastUpdated");

test("Eleventy, defaults inherit from config", async (t) => {
let elev = new Eleventy();
Expand Down Expand Up @@ -412,3 +413,14 @@ test("Unicode in front matter `tags`, issue #670", async (t) => {

t.is(results[0].content.trim(), "2,all,Cañon City,");
});

test("#142: date 'git Last Modified' populates page.date", async (t) => {
let elev = new Eleventy("./test/stubs-142/", "./test/stubs-142/_site");

let results = await elev.toJSON();
let [result] = results;

// This doesn’t test the validity of the function, only that it populates page.date.
let comparisonDate = DateGitLastUpdated("./test/stubs-142/index.njk");
t.is(result.content.trim(), "" + comparisonDate.getTime());
});
2 changes: 1 addition & 1 deletion test/stubs-142/index.njk
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
date: git Last Modified
---
{{ page.date }}
{{ page.date.getTime() }}

0 comments on commit 8f35e55

Please sign in to comment.