TL;DR: You need to get the root name (without the extension) and append the new extension. Then, it only depends on how tolerant you are.

The other day I figured I needed a function to change the file extension (from a .jpg to a .nfo). Since I haven't found a ready made function to do this, I decided to create my own (it's also a good exercise for my neurons...). The function ended up having the following steps:

  1. Prerequisite: the function input parameters are the file name (not the full path) and the new extension
  2. Isolate the extension
  3. Replace the extension and
  4. Rebuild the path from components

I ended up with the following code (typescript):

let path = require('path')

export function changeExtension(filename: string, extension: string): string {
  let ext: string = path.extname(filename)
  let root: string = filename.substring(0, filename.length - ext.length)

  ext = extension.startsWith('.') ? extension : extension.length > 0 ? `.${extension}` : ''
  return `${root}${ext}`
}

The only interesting bit is the next-to-last instruction where the new extension is covered. Here we cater for extensions including or not the dot as well as for empty extensions.

Several enhancements can be made to the function:

  • Since we're using the path module, we can extend it to accept full paths
  • We can also use the path.basename() with 2 parameters (the path and the extension) rather than substring operations.

HTH,