UNPKG

@lunaticmuch/front-matter-manipulator

Version:

A utility for parsing and manipulating documents with Front Matter

144 lines (127 loc) 5.32 kB
import chalk from 'chalk'; import getFiles from '../util/getFiles.js'; import getDescendantProp from '../util/getDescendantProp.js'; import getFieldPermutations from '../util/getFieldPermutations.js'; import isMissing from '../util/isMissing.js'; import parseFile from '../util/parseFile.js'; import updateDescendantProp from '../util/updateDescendantProp.js'; import write from './write.js'; import filterByField from '../util/filterByField.js'; /** @namespace Update */ /** * Optional replacement function to be run for each match * @memberof Update * @callback replacementCallback - Function to run to rename the field * @param {string} value - The field's current value * @param {string} field - The current field permutation * @param {string} filePath - The current file's path * @return {string} replacement - The replacement value * @example * var fmp = require("front-matter-manipulator") * function replacement(field, filePath) { * if (field.indexOf(0) > -1) { // Update if array index 0 * replacement = "newKey" * } * } * * fmp.rename("**‏/*.md", "categories", replacement, options) */ /** * Updates the given key value pair's value * @memberof Update * @param {string} patterns - A file path or glob pattern to search for files to modify * @param {string} field - The name of the field you wish to update * @param {(string|replacementCallback)} replacement - The new value of the field * @param {Object} options - Configuration options * @param {string} options.ignore - A file path or glob pattern to search for files not to modify. Defaults to "node_modules". * @param {string} options.exclude - Exclude files that have a certain values. Formatted as a comma delimited list of key value pairs. * @param {string} options.include - Only include files that have a certain values. Formatted as a comma delimited list of key value pairs. * @returns {Array[Object]} files * @example * var fmp = require("front-matter-manipulator") * * fmp.update("_posts/example-post.md", "draft", "true") * @example * var fmp = require("front-matter-manipulator") * var options = { * ignore: "_posts/subdirectory/*.md", * include: "layout=post", * exclude: "featured=true" * } * * fmp.rename("**‏/*.md", "draft", "true", options) */ export default function update(patterns, field, replacement, options) { if (!patterns) throw new Error('Missing value for "patterns". Please provide a file path or glob pattern'); if (!field) throw new Error('Missing value for "field"'); if (!replacement) throw new Error('Missing value for "replacement"'); if (options.exclude) { let filters = options.exclude.split(','); options.exclude = filters.map(function (f) { return f.split('='); }); } else { options.exclude = []; } if (options.include) { let filters = options.include.split(','); options.include = filters.map(function (f) { return f.split('='); }); } else { options.include = []; } var files = getFiles(patterns, options.ignore); if (files.length > 0) { var rawMatches = files.reduce(function (results, f) { if (!isMissing(f.file)) { var matter = parseFile(f.file); f.data = matter.data; f.content = matter.content; results.push(f); } return results; }, []); if (options.exclude.length > 0) { rawMatches = rawMatches.map(function (f) { return filterByField(options.exclude, f.data, true); }); } if (options.include.length > 0) { rawMatches = rawMatches.map(function (f) { return filterByField(options.include, f.data); }); } var cleanData = rawMatches.filter(function (n) { return !isMissing(n); }); return cleanData.map(f => { var output = []; var data = f.data; var permutations = getFieldPermutations(field, data); var keyValues = permutations.map(function (p) { if (p) var value = getDescendantProp(data, p); return { permutation: p, value: value }; }).filter(function (f) { return !isMissing(f.value); }); keyValues.forEach(function (p) { var newVal = replacement; if (options.regex) { var regex = new RegExp(replacement); newVal = regex.exec(p.value); } else if (typeof replacement === 'function') { newVal = replacement(p.value, p.permutation, f.path); } if (typeof replacement !== 'function' || newVal !== replacement) updateDescendantProp(data, p.permutation, newVal); if (options.dryRun && !options.silent && options.cli || options.verbose && options.cli) { console.log(chalk`{blue Updated {bold ${f.path}}: ${p.value} => {bold ${newVal}}}`); } }); output = write(f.path, f.content, data, options); return output; }); } }