All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nawforce.pkgforce.pkgs.TriHierarchy.scala Maven / Gradle / Ivy

/*
 * Copyright (c) 2022 FinancialForce.com, inc. All rights reserved.
 */

package com.nawforce.pkgforce.pkgs

import com.nawforce.pkgforce.names.TypeNameFuncs.TypeNameFuncs
import com.nawforce.pkgforce.names.{EncodedName, Name, TypeName}
import com.nawforce.pkgforce.path.PathLike

import scala.collection.immutable.ArraySeq

abstract class TriHierarchy {
  type TOrg <: TriOrg
  type TPackage <: TriPackage
  type TModule <: TriModule

  trait TriOrg {
    self: TOrg =>

    /** Packages in org in deploy order, the last entry is the unmanaged package identified by
      * namespace = None
      */
    val packages: ArraySeq[TPackage]

    /** Packages in org by namespace */
    lazy val packagesByNamespace: Map[Option[Name], TPackage] =
      packages.map(pkg => (pkg.namespace, pkg)).toMap

    /** All orgs have an unmanaged package, it has to be the last entry in 'packages'. */
    lazy val unmanaged: TPackage = packages.last
  }

  trait TriPackage {
    self: TPackage =>

    /** The parent org that this package belongs to */
    val org: TOrg

    /** Namespace for the package, None=unmanaged */
    val namespace: Option[Name]

    /** Was this package loaded from gulped metadata */
    val isGulped: Boolean

    /** The packages this package depends on */
    val basePackages: ArraySeq[TPackage]

    /** The modules in this package in deploy order */
    val modules: ArraySeq[TModule]

    /** Package modules in reverse deploy order. */
    lazy val orderedModules: ArraySeq[TModule] = modules.reverse

    /** Is this a ghost package, aka it has no modules. */
    lazy val isGhosted: Boolean = modules.isEmpty

    /* Find first module in search order (may not be in this package) */
    def firstModule: Option[TModule] = {
      orderedModules.headOption
        .orElse(basePackages.headOption.flatMap(_.firstModule))
    }

    /* Check if a type is ghosted in this package */
    def isGhostedType(typeName: TypeName): Boolean = {
      if (typeName.outer.contains(TypeName.Schema)) {
        val encName = EncodedName(typeName.name)
        basePackages.filter(_.isGhosted).exists(_.namespace == encName.namespace)
      } else {
        basePackages.filter(_.isGhosted).exists(_.namespace.contains(typeName.outerName)) ||
        typeName.params.exists(isGhostedType)
      }
    }

    /** Check if a field name is ghosted in this package. */
    def isGhostedFieldName(name: Name): Boolean = {
      EncodedName(name).namespace match {
        case None     => false
        case Some(ns) => basePackages.filter(_.isGhosted).exists(_.namespace.contains(ns))
      }
    }

    override def toString: String = s"Package(${namespace.map(_.toString).getOrElse("")})"
  }

  trait TriModule {
    self: TModule =>

    /** The parent package that this module belongs to */
    val pkg: TPackage

    /** The modules that this module depends on deploy order */
    val dependents: ArraySeq[TModule]

    /** The module (& owning package namespace) */
    lazy val namespace: Option[Name] = pkg.namespace

    /** The package the parent package depends on in reverse deploy order */
    lazy val basePackages: ArraySeq[TPackage] = pkg.basePackages.reverse

    /** The modules that this module depends on in reverse deploy order */
    lazy val baseModules: ArraySeq[TModule] = dependents.reverse

    /** Test if a file is visible to this module, i.e. in scope & not ignored */
    def isVisibleFile(path: PathLike): Boolean

    /* Transitive Modules (dependent modules for this modules & its dependents) */
    def transitiveModules: Set[TModule] = {
      namespace
        .map(_ => dependents.toSet ++ dependents.flatMap(_.transitiveModules))
        .getOrElse(baseModules.toSet)
    }

    /* Find next module in search order */
    def nextModule: Option[TModule] = {
      baseModules.headOption.orElse(basePackages.headOption.flatMap(_.firstModule))
    }

    /* Check if a type name is ghosted in this module */
    def isGhostedType(typeName: TypeName): Boolean = pkg.isGhostedType(typeName)

    /* Check if a field name is ghosted in this module */
    def isGhostedFieldName(name: Name): Boolean = pkg.isGhostedFieldName(name)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy