scolladon/sfdx-git-delta

View on GitHub
src/post-processor/flowTranslationProcessor.ts

Summary

Maintainability
A
0 mins
Test Coverage
/* eslint-disable @typescript-eslint/no-explicit-any */
'use strict'
import { parse, join } from 'path'

import { pathExists } from 'fs-extra'

import {
  FLOW_XML_NAME,
  META_REGEX,
  METAFILE_SUFFIX,
  TRANSLATION_EXTENSION,
  TRANSLATION_TYPE,
} from '../constant/metadataConstants'
import { MetadataRepository } from '../metadata/MetadataRepository'
import type { Work } from '../types/work'
import { writeFile, readDir } from '../utils/fsHelper'
import { isSubDir, readFile, treatPathSep } from '../utils/fsUtils'
import {
  asArray,
  parseXmlFileToJson,
  xml2Json,
  convertJsonToXml,
} from '../utils/fxpHelper'
import { buildIgnoreHelper } from '../utils/ignoreHelper'
import { fillPackageWithParameter } from '../utils/packageHelper'

import BaseProcessor from './baseProcessor'

const EXTENSION = `.${TRANSLATION_EXTENSION}${METAFILE_SUFFIX}`

const getTranslationName = (translationPath: string) =>
  parse(translationPath.replace(META_REGEX, '')).name

const getDefaultTranslation = () => ({
  '?xml': { '@_version': '1.0', '@_encoding': 'UTF-8' },
  Translations: {
    '@_xmlns': 'http://soap.sforce.com/2006/04/metadata',
    flowDefinitions: [],
  },
})

export default class FlowTranslationProcessor extends BaseProcessor {
  protected readonly translations: Map<string, any>

  constructor(work: Work, metadata: MetadataRepository) {
    super(work, metadata)
    this.translations = new Map()
  }

  public override async process() {
    if (this._shouldProcess()) {
      await this._buildFlowDefinitionsMap()
      await this._handleFlowTranslation()
    }
  }

  async _buildFlowDefinitionsMap() {
    this.translations.clear()

    const allFiles = await readDir(this.config.source, this.work.config)
    const ignoreHelper = await buildIgnoreHelper(this.config)
    const translationPaths = allFiles.filter((file: string) =>
      file.endsWith(EXTENSION)
    )

    for (const translationPath of translationPaths) {
      if (
        !ignoreHelper.globalIgnore.ignores(translationPath) &&
        !isSubDir(this.config.output, translationPath)
      ) {
        await this._parseTranslationFile(translationPath)
      }
    }
  }

  protected async _handleFlowTranslation() {
    for (const translationPath of this.translations.keys()) {
      fillPackageWithParameter({
        store: this.work.diffs.package,
        type: TRANSLATION_TYPE,
        member: getTranslationName(translationPath),
      })
      if (this.config.generateDelta) {
        const jsonTranslation =
          await this._getTranslationAsJSON(translationPath)
        this._scrapTranslationFile(
          jsonTranslation,
          this.translations.get(translationPath)
        )
        const scrappedTranslation = convertJsonToXml(jsonTranslation)
        await writeFile(translationPath, scrappedTranslation, this.config)
      }
    }
  }

  protected _scrapTranslationFile(
    jsonTranslation: any,
    actualFlowDefinition: any
  ) {
    const flowDefinitions = asArray(
      jsonTranslation.Translations?.flowDefinitions
    )
    const fullNames = new Set(
      flowDefinitions.map((flowDef: any) => flowDef?.fullName)
    )
    const strippedActualFlowDefinition = actualFlowDefinition.filter(
      (flowDef: any) => !fullNames.has(flowDef?.fullName)
    )

    jsonTranslation.Translations.flowDefinitions = flowDefinitions.concat(
      strippedActualFlowDefinition
    )
  }

  protected async _parseTranslationFile(translationPath: string) {
    const translationJSON = await parseXmlFileToJson(
      { path: translationPath, oid: this.config.to },
      this.config
    )
    const flowDefinitions = asArray(
      translationJSON?.Translations?.flowDefinitions
    )
    flowDefinitions.forEach(flowDefinition =>
      this._addFlowPerTranslation({
        translationPath,
        flowDefinition,
      })
    )
  }

  protected _addFlowPerTranslation({
    translationPath,
    flowDefinition,
  }: {
    translationPath: string
    flowDefinition: any
  }) {
    const packagedElements = this.work.diffs.package.get(FLOW_XML_NAME)
    if (packagedElements?.has(flowDefinition?.fullName)) {
      if (!this.translations.has(translationPath)) {
        this.translations.set(translationPath, [])
      }
      this.translations.get(translationPath).push(flowDefinition)
    }
  }

  protected async _getTranslationAsJSON(translationPath: string) {
    const translationPathInOutputFolder = join(
      this.config.output,
      treatPathSep(translationPath)
    )
    const translationExist = await pathExists(translationPathInOutputFolder)

    let jsonTranslation = getDefaultTranslation()
    if (translationExist) {
      const xmlTranslation = await readFile(translationPathInOutputFolder)
      jsonTranslation = xml2Json(xmlTranslation)
    }

    return jsonTranslation
  }

  _shouldProcess() {
    return this.work.diffs.package.has(FLOW_XML_NAME)
  }
}