Skip to content

How to write a replace chain plugin

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

These docs are for renamer v3. See this page for renamer v2 docs.

To perform a rename using JavaScript you must write a replace chain plugin (described here).

A plugin is a module exporting a class which, at the minimum, defines a replace method. Here is a simple example which appends the text [v1] to the end of the filename (e.g. image.jpg would become image [v1].jpg). Save this module as the file suffix.mjs.

import path from 'path'

class Suffix {
  replace (filePath) {
    const file = path.parse(filePath)
    const newName = file.name + ' [v1]' + file.ext
    return path.join(file.dir, newName)
  }
}

export default Suffix

The replace method takes the old file path as input and must return a new path. Here is the full method signature.

  /**
   * @param {string} filePath - The current file path being processed
   * @param {object} options - The current renamer 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 being processed (after glob expressions have been expanded).
   * @returns {string} - The modified or unmodified file path.
   */
  replace (filePath, options, index, files) {
    // craft and return the new filename
  }

Custom options

What if we want to add the suffix [v2] instead of [v1]? We can pass variables into the replace method by defining command-line options.

To do this, add an optionDefinitions method which returns one or more option definition objects. In this example, we define an --suffix option which expects a string argument. From here, the options object passed to the replace method will contain the --suffix value set on the command-line.

import path from 'path'

class Suffix {
  optionDefinitions () {
    return [
      {
        name: 'suffix',
        type: String,
        description: 'The suffix to append to each file.',
        defaultValue: ''
      }
    ]
  }

  replace (filePath, options) {
    const file = path.parse(filePath)
    const newName = file.name + options.suffix + file.ext
    return path.join(file.dir, newName)
  }
}

export default Suffix

Use the plugin to add the suffix [v2].

$ renamer --chain suffix.mjs --suffix ' v2' pics/* --dry-run

Dry run

✔︎ pic1.jpg → pic1 v2.jpg
✔︎ pic2.jpg → pic2 v2.jpg

Rename complete: 2 of 3 files renamed.

Description

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

class Suffix {
  description () {
    return 'Adds a suffix to the file name.'
  }

  ...
}

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 --chain ./example-plugin.js --help

If the plugin is installed (via npm or yarn), load it via its module name.

$ renamer --chain example-plugin --help

To share your plugin, 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 renamer-example-plugin
$ renamer --chain renamer-example-plugin --help

Plugin template

Here is the full plugin example which you can use as a template.

import path from 'path'

class Suffix {
  /**
   * An optional description which will be printed in the "replace chain" section of `renamer --help`.
   * @returns {string}
   */
  description () {
    return 'Adds a suffix to the file name.'
  }

  /**
   * Zero or more custom option definitions.
   * @see https://github.com/75lb/command-line-args/blob/master/doc/option-definition.md
   * @returns {OptionDefinition[]}
   */
  optionDefinitions () {
    return [
      {
        name: 'suffix',
        type: String,
        description: 'The suffix to append to each file.',
        defaultValue: ''
      }
    ]
  }

  /**
   * 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 renamer 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 being processed (after glob expressions have been expanded).
   * @returns {string} - The modified or unmodified file path.
   */
  replace (filePath, options) {
    const file = path.parse(filePath)
    const newName = file.name + options.suffix + file.ext
    return path.join(file.dir, newName)
  }
}

export default Suffix