hexo/node_modules/hexo-front-matter/lib/front_matter.js

182 lines
3.9 KiB
JavaScript
Raw Normal View History

2023-09-25 15:58:56 +08:00
'use strict';
const yaml = require('js-yaml');
const rPrefixSep = /^(-{3,}|;{3,})/;
const rFrontMatter = /^(-{3,}|;{3,})\n([\s\S]+?)\n\1\n?([\s\S]*)/;
const rFrontMatterNew = /^([\s\S]+?)\n(-{3,}|;{3,})\n?([\s\S]*)/;
function split(str) {
if (typeof str !== 'string') throw new TypeError('str is required!');
const matchOld = str.match(rFrontMatter);
if (matchOld) {
return {
data: matchOld[2],
content: matchOld[3] || '',
separator: matchOld[1],
prefixSeparator: true
};
}
if (rPrefixSep.test(str)) return { content: str };
const matchNew = str.match(rFrontMatterNew);
if (matchNew) {
return {
data: matchNew[1],
content: matchNew[3] || '',
separator: matchNew[2],
prefixSeparator: false
};
}
return { content: str };
}
function parse(str, options) {
if (typeof str !== 'string') throw new TypeError('str is required!');
const splitData = split(str);
const raw = splitData.data;
if (!raw) return { _content: str };
let data;
if (splitData.separator.startsWith(';')) {
data = parseJSON(raw);
} else {
data = parseYAML(raw, options);
}
if (!data) return { _content: str };
// Convert timezone
Object.keys(data).forEach(key => {
const item = data[key];
if (item instanceof Date) {
data[key] = new Date(item.getTime() + (item.getTimezoneOffset() * 60 * 1000));
}
});
data._content = splitData.content;
return data;
}
function parseYAML(str, options) {
const result = yaml.load(escapeYAML(str), options);
if (typeof result !== 'object') return;
return result;
}
function parseJSON(str) {
try {
return JSON.parse(`{${str}}`);
} catch (err) {
return; // eslint-disable-line
}
}
function escapeYAML(str) {
if (typeof str !== 'string') throw new TypeError('str is required!');
return str.replace(/\n(\t+)/g, (match, tabs) => {
let result = '\n';
for (let i = 0, len = tabs.length; i < len; i++) {
result += ' ';
}
return result;
});
}
function stringify(obj, options = {}) {
if (!obj) throw new TypeError('obj is required!');
const { _content: content = '' } = obj;
delete obj._content;
if (!Object.keys(obj).length) return content;
const { mode, prefixSeparator } = options;
const separator = options.separator || (mode === 'json' ? ';;;' : '---');
let result = '';
if (prefixSeparator) result += `${separator}\n`;
if (mode === 'json') {
result += stringifyJSON(obj);
} else {
result += stringifyYAML(obj, options);
}
result += `${separator}\n${content}`;
return result;
}
function stringifyYAML(obj, options) {
const keys = Object.keys(obj);
const data = {};
const nullKeys = [];
const dateKeys = [];
let key, value, i, len;
for (i = 0, len = keys.length; i < len; i++) {
key = keys[i];
value = obj[key];
if (value == null) {
nullKeys.push(key);
} else if (value instanceof Date) {
dateKeys.push(key);
} else {
data[key] = value;
}
}
let result = yaml.dump(data, options);
if (dateKeys.length) {
for (i = 0, len = dateKeys.length; i < len; i++) {
key = dateKeys[i];
result += `${key}: ${formatDate(obj[key])}\n`;
}
}
if (nullKeys.length) {
for (i = 0, len = nullKeys.length; i < len; i++) {
result += `${nullKeys[i]}:\n`;
}
}
return result;
}
function stringifyJSON(obj) {
return JSON.stringify(obj, null, ' ')
// Remove indention
.replace(/\n {2}/g, () => '\n')
// Remove prefixing and trailing braces
.replace(/^{\n|}$/g, '');
}
function doubleDigit(num) {
return num.toString().padStart(2, '0');
}
function formatDate(date) {
return `${date.getFullYear()}-${doubleDigit(date.getMonth() + 1)}-${doubleDigit(date.getDate())} ${doubleDigit(date.getHours())}:${doubleDigit(date.getMinutes())}:${doubleDigit(date.getSeconds())}`;
}
module.exports = {
parse,
split,
escape: escapeYAML,
stringify
};