Skip to content

How to write a renamer plugin (renamer v2)

Lloyd Brookes edited this page May 3, 2021 · 1 revision

Overview and replace method

A renamer plugin is a module which exports a function accepting a base class as input, returning a class extending that base. Below is the most simple possible plugin module. The class must define a replace method which receives each filePath (e.g. /user/Lloyd/Pictures/something.jpg) as input and returns a modified path. This trivial example appends a jpg extension to each file.

module.exports = PluginBase => class Example extends PluginBase {
  replace (filePath) {
    return filePath + '.jpg'
  }
}

The full signature of the replace method looks like this.

  /**
   * @param {string} filePath - The current file path being processed
   * @param {object} options - The current options (in camel-case), e.g. `options.find`, `options.replace` plus any custom options.
   * @param {number} index - The index of the current filePath within the full list of input files.
   * @param {string[]} files - The full list of input files to process (after glob expressions have been expanded).
   * @returns {string} - The modified or unmodified file path.
   */
  replace (filePath, options, index, files) {
    // do work
  }

Custom options

You can pass variables into the replace method by defining command-line options. To do this, you add an optionDefinitions method which returns one or more option definition objects. In this example, we define an --ext-name option which expects a string argument. The options object passed to the replace method will contain (in camel-case) all option values set on the command-line.

module.exports = PluginBase => class Example extends PluginBase {
  optionDefinitions () {
    return [
      {
        name: 'ext-name',
        type: String,
        description: 'The extension to append to each file.'
      }
    ]
  }

  replace (filePath, options) {
    return filePath + options.extName
  }
}

Description

The finishing touch is to give your plugin a description which will be printed in the "replace chain" section of renamer --help.

module.exports = PluginBase => class Example extends PluginBase {
  description () {
    return 'Appends a file extension.'
  }
  
  optionDefinitions () {
    return [
      {
        name: 'ext-name',
        description: 'The extension to append to each file.'
      }
    ]
  }
  replace (filePath, options) {
    return filePath + options.extName
  }
}

Colour and formatting

Chalk template literal syntax can be used anywhere within the string returned by description() and/or each description or typeLabel property of the objects returned by optionDefinitions(). For example

description () {
  return 'This description has {red.underline underlined red text} in it.'
}

Similar example in the option definitions.

optionDefinitions () {
  return [{
    name: 'ext-name',
    description: 'The {blue.italic extension} to append to each file.'
  }]
}

Use and sharing

If your plugin module is saved locally, you can load it via its path. This command will show your plugin description and custom options in the usage guide.

$ renamer --plugin ./example-plugin.js --help

To share your plugin with the world, publish it to npm. Be sure to add renamer-plugin to the keywords array in package.json to help us find your plugin in this list. Other users can install and use your plugin like so.

$ npm install -g renamer-example-plugin
$ renamer --plugin renamer-example-plugin --help

Plugin template

A plugin template containing some trivial example content. Don't forget to give the class a better name than Plugin.

module.exports = PluginBase => class Plugin extends PluginBase {
  /**
   * An optional description which will be printed in the "replace chain" section of `renamer --help`.
   * @returns {string}
   */
  description () {
    return 'Plugin description.'
  }

  /**
   * Zero or more custom option definitions.
   * @see https://github.com/75lb/command-line-args/blob/master/doc/option-definition.md
   * @returns {OptionDefinition[]}
   */
  optionDefinitions () {
    return []
  }

  /**
   * This method is mandatory and should modify the incoming file path as required, returning the new path.
   * @param {string} filePath - The current file path being processed
   * @param {object} options - The current options (in camel-case), e.g. `options.find`, `options.replace` plus any custom options.
   * @param {number} index - The index of the current filePath within the full list of input files.
   * @param {string[]} files - The full list of input files to process (after glob expressions have been expanded).
   * @returns {string} - The modified or unmodified file path.
   */
  replace (filePath, options, index, files) {
    const path = require('path')
    const file = path.parse(filePath)
    const newName = file.name + '_example'
    return path.join(file.dir, newName + file.ext)
  }
}