extendJsonFile (file, newData) {
    if (newData !== void 0 && Object(newData) === newData && Object.keys(newData).length > 0) {
      const filePath = this.resolve.app(file)

      // Try to parse the JSON with Node native tools.
      // It will soft-fail and log a warning if the JSON isn't parseable
      //  which usually means we are dealing with an extended JSON flavour,
      //  for example JSON with comments or JSON5.
      // Notable examples are TS 'tsconfig.json' or VSCode 'settings.json'
      // TODO: use parseJSONC/stringifyJSONC from confbox
      try {
        const existingData = fs.existsSync(filePath) ? parseJSON(fs.readFileSync(filePath, 'utf-8')) : {}
        const data = merge({}, existingData, newData)

        fs.writeFileSync(
          this.resolve.app(file),
          // if file exists, preserve indentation, otherwise use 2 spaces
          stringifyJSON(data, { indent: Object.keys(existingData).length > 0 ? undefined : 2 }),
          'utf-8'
        )
      }
      catch (_) {
        warn()
        warn(`Extension(${ this.extId }): extendJsonFile() - "${ filePath }" doesn't conform to JSON format: this could happen if you are trying to update flavoured JSON files (eg. JSON with Comments or JSON5). Skipping...`)
        warn(`Extension(${ this.extId }): extendJsonFile() - The extension tried to apply these updates to "${ filePath }" file: ${ JSON.stringify(newData) }`)
        warn()
      }
    }
  }
Extend a JSON file with new props (deep merge).
If specifying existing props, it will override them.

@param {string} file (relative path to app root folder)
@param {object} newData (Object to merge in)