/** * Copyright (c) 2017-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const shell = require('shelljs'); const TRUNCATE_MARKER = //; function blogPostHasTruncateMarker(content) { return TRUNCATE_MARKER.test(content); } function extractBlogPostBeforeTruncate(content) { return content.split(TRUNCATE_MARKER)[0]; } function removeExtension(pathStr) { return pathStr.replace(/\.[^/.]+$/, ''); } function getPath(pathStr, cleanUrl = false) { if (!pathStr || !cleanUrl || !pathStr.endsWith('.html')) { return pathStr; } return pathStr.endsWith('/index.html') ? pathStr.replace(/index\.html$/, '') : removeExtension(pathStr); } function idx(target, keyPaths) { return ( target && (Array.isArray(keyPaths) ? keyPaths.reduce((obj, key) => obj && obj[key], target) : target[keyPaths]) ); } function getGitLastUpdated(filepath) { const timestampAndAuthorRegex = /^(\d+), (.+)$/; function isTimestampAndAuthor(str) { return timestampAndAuthorRegex.test(str); } function getTimestampAndAuthor(str) { if (!str) { return null; } const temp = str.match(timestampAndAuthorRegex); return !temp || temp.length < 3 ? null : {timestamp: temp[1], author: temp[2]}; } // Wrap in try/catch in case the shell commands fail (e.g. project doesn't use Git, etc). try { // To differentiate between content change and file renaming / moving, use --summary // To follow the file history until before it is moved (when we create new version), use // --follow. const silentState = shell.config.silent; // Save old silent state. shell.config.silent = true; const result = shell .exec(`git log --follow --summary --format="%ct, %an" ${filepath}`) .stdout.trim(); shell.config.silent = silentState; // Format the log results to be // ['1234567890, Yangshun Tay', 'rename ...', '1234567880, // 'Joel Marcey', 'move ...', '1234567870', '1234567860'] const records = result .toString('utf-8') .replace(/\n\s*\n/g, '\n') .split('\n') .filter(String); const lastContentModifierCommit = records.find((item, index, arr) => { const currentItemIsTimestampAndAuthor = isTimestampAndAuthor(item); const isLastTwoItem = index + 2 >= arr.length; const nextItemIsTimestampAndAuthor = isTimestampAndAuthor(arr[index + 1]); return ( currentItemIsTimestampAndAuthor && (isLastTwoItem || nextItemIsTimestampAndAuthor) ); }); return lastContentModifierCommit ? getTimestampAndAuthor(lastContentModifierCommit) : null; } catch (error) { console.error(error); } return null; } function getGitLastUpdatedTime(filepath) { const commit = getGitLastUpdated(filepath); if (commit && commit.timestamp) { const date = new Date(parseInt(commit.timestamp, 10) * 1000); return date.toLocaleDateString(); } return null; } function getGitLastUpdatedBy(filepath) { const commit = getGitLastUpdated(filepath); return commit ? commit.author : null; } module.exports = { blogPostHasTruncateMarker, extractBlogPostBeforeTruncate, getGitLastUpdatedTime, getGitLastUpdatedBy, getPath, removeExtension, idx, };