mirror of https://github.com/sbt/sbt.git
Merge pull request #7490 from adpi2/sbt2-remove-manifest
[sbt 2] Remove usage of Manifest in Structure.scala
This commit is contained in:
commit
a607e54188
|
|
@ -388,18 +388,15 @@ object Index {
|
|||
)(label: AttributeKey[_] => String): Map[String, AttributeKey[_]] = {
|
||||
val multiMap = settings.groupBy(label)
|
||||
val duplicates = multiMap.iterator
|
||||
.collect { case (k, xs) if xs.size > 1 => (k, xs.map(_.manifest)) }
|
||||
.collect {
|
||||
case (k, xs) if xs.size > 1 => (k, xs)
|
||||
}
|
||||
.collect { case (k, xs) if xs.size > 1 => (k, xs.map(_.tag)) }
|
||||
.collect { case (k, xs) if xs.size > 1 => (k, xs) }
|
||||
.toVector
|
||||
if duplicates.isEmpty then multiMap.collect { case (k, v) if validID(k) => (k, v.head) }.toMap
|
||||
else
|
||||
sys.error(
|
||||
duplicates map { case (k, tps) =>
|
||||
"'" + k + "' (" + tps.mkString(", ") + ")"
|
||||
} mkString ("Some keys were defined with the same name but different types: ", ", ", "")
|
||||
)
|
||||
val duplicateStr = duplicates
|
||||
.map { case (k, tps) => s"'$k' (${tps.mkString(", ")})" }
|
||||
.mkString(",")
|
||||
sys.error(s"Some keys were defined with the same name but different types: $duplicateStr")
|
||||
}
|
||||
|
||||
private[this] type TriggerMap = collection.mutable.HashMap[TaskId[?], Seq[TaskId[?]]]
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ object Previous {
|
|||
// private[sbt] def task: ScopedKey[Task[T]] = key.task
|
||||
|
||||
lazy val stamped: JsonFormat[T] =
|
||||
StampedFormat.withStamp(key.task.key.manifest.toString)(format)
|
||||
StampedFormat.withStamp(key.task.key.tag.toString)(format)
|
||||
|
||||
def setTask(newTask: ScopedKey[Task[T]]) = new Referenced(newTask, format)
|
||||
private[sbt] def read(streams: Streams): Option[T] =
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ package sbt
|
|||
import scala.annotation.targetName
|
||||
|
||||
import sbt.internal.util.Types.*
|
||||
import sbt.internal.util.{ AttributeKey, Settings, SourcePosition }
|
||||
import sbt.internal.util.{ AttributeKey, KeyTag, Settings, SourcePosition }
|
||||
import sbt.internal.util.TupleMapExtension.*
|
||||
import sbt.util.OptJsonWriter
|
||||
import sbt.ConcurrentRestrictions.Tag
|
||||
|
|
@ -259,11 +259,6 @@ object Scoped:
|
|||
implicit def inputScopedToKey[T](s: InputKey[T]): ScopedKey[InputTask[T]] =
|
||||
ScopedKey(s.scope, s.key)
|
||||
|
||||
private[sbt] def coerceTag[A1: ClassTag]: Manifest[A1] =
|
||||
summon[ClassTag[A1]] match
|
||||
case mf: Manifest[A1] => mf
|
||||
case tag => ManifestFactory.classType[A1](tag.runtimeClass)
|
||||
|
||||
/**
|
||||
* Mixin trait for adding convenience vocabulary associated with specifying the [[Scope]] of a setting.
|
||||
* Allows specification of the Scope or part of the [[Scope]] of a setting being referenced.
|
||||
|
|
@ -736,10 +731,12 @@ end TupleSyntax
|
|||
|
||||
object TupleSyntax extends TupleSyntax
|
||||
|
||||
import Scoped.{ coerceTag, extendScoped }
|
||||
import Scoped.extendScoped
|
||||
|
||||
/** Constructs InputKeys, which are associated with input tasks to define a setting. */
|
||||
object InputKey:
|
||||
private given [A: ClassTag]: KeyTag[InputTask[A]] =
|
||||
KeyTag.InputTask(summon[ClassTag[A]].runtimeClass)
|
||||
|
||||
def apply[A1: ClassTag](label: String): InputKey[A1] =
|
||||
apply[A1](label, "", KeyRanks.DefaultInputRank)
|
||||
|
|
@ -755,8 +752,6 @@ object InputKey:
|
|||
description: String,
|
||||
rank: Int,
|
||||
): InputKey[A1] =
|
||||
given mf: ClassTag[InputTask[A1]] =
|
||||
ManifestFactory.classType[InputTask[A1]](classOf[InputTask[A1]], coerceTag[A1])
|
||||
apply(AttributeKey[InputTask[A1]](label, description, rank))
|
||||
|
||||
def apply[A1: ClassTag](
|
||||
|
|
@ -773,8 +768,6 @@ object InputKey:
|
|||
extend1: Scoped,
|
||||
extendN: Scoped*
|
||||
): InputKey[A1] =
|
||||
given mf: ClassTag[InputTask[A1]] =
|
||||
ManifestFactory.classType[InputTask[A1]](classOf[InputTask[A1]], coerceTag[A1])
|
||||
apply(AttributeKey[InputTask[A1]](label, description, extendScoped(extend1, extendN), rank))
|
||||
|
||||
def apply[A1](akey: AttributeKey[InputTask[A1]]): InputKey[A1] =
|
||||
|
|
@ -784,27 +777,19 @@ end InputKey
|
|||
|
||||
/** Constructs TaskKeys, which are associated with tasks to define a setting. */
|
||||
object TaskKey:
|
||||
private given [A: ClassTag]: KeyTag[Task[A]] = KeyTag.Task(summon[ClassTag[A]].runtimeClass)
|
||||
|
||||
def apply[A1: ClassTag](label: String): TaskKey[A1] =
|
||||
apply[A1](
|
||||
label = label,
|
||||
description = "",
|
||||
rank = Int.MaxValue,
|
||||
)
|
||||
apply[A1](label = label, description = "", rank = Int.MaxValue)
|
||||
|
||||
def apply[A1: ClassTag](label: String, description: String): TaskKey[A1] =
|
||||
apply[A1](
|
||||
label = label,
|
||||
description = description,
|
||||
rank = Int.MaxValue,
|
||||
)
|
||||
apply[A1](label = label, description = description, rank = Int.MaxValue)
|
||||
|
||||
def apply[A1: ClassTag](
|
||||
label: String,
|
||||
description: String,
|
||||
rank: Int,
|
||||
): TaskKey[A1] =
|
||||
given mf: ClassTag[Task[A1]] =
|
||||
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], coerceTag[A1])
|
||||
apply(AttributeKey[Task[A1]](label, description, rank))
|
||||
|
||||
def apply[A1: ClassTag](
|
||||
|
|
@ -813,8 +798,6 @@ object TaskKey:
|
|||
extend1: Scoped,
|
||||
extendN: Scoped*
|
||||
): TaskKey[A1] =
|
||||
given mf: ClassTag[Task[A1]] =
|
||||
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], coerceTag[A1])
|
||||
apply(AttributeKey[Task[A1]](label, description, extendScoped(extend1, extendN)))
|
||||
|
||||
def apply[A1: ClassTag](
|
||||
|
|
@ -824,25 +807,18 @@ object TaskKey:
|
|||
extend1: Scoped,
|
||||
extendN: Scoped*
|
||||
): TaskKey[A1] =
|
||||
given mf: ClassTag[Task[A1]] =
|
||||
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], coerceTag[A1])
|
||||
apply(AttributeKey[Task[A1]](label, description, extendScoped(extend1, extendN), rank))
|
||||
|
||||
def apply[A1](akey: AttributeKey[Task[A1]]): TaskKey[A1] =
|
||||
Scoped.scopedTask(Scope.ThisScope, akey)
|
||||
|
||||
def local[A1: ClassTag]: TaskKey[A1] =
|
||||
given mf: ClassTag[Task[A1]] =
|
||||
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], coerceTag[A1])
|
||||
apply[A1](AttributeKey.local[Task[A1]])
|
||||
def local[A1: ClassTag]: TaskKey[A1] = apply[A1](AttributeKey.local[Task[A1]])
|
||||
|
||||
end TaskKey
|
||||
|
||||
/** Constructs SettingKeys, which are associated with a value to define a basic setting. */
|
||||
object SettingKey:
|
||||
def apply[A1: ClassTag: OptJsonWriter](
|
||||
label: String,
|
||||
): SettingKey[A1] =
|
||||
def apply[A1: ClassTag: OptJsonWriter](label: String): SettingKey[A1] =
|
||||
apply[A1](
|
||||
label = label,
|
||||
description = "",
|
||||
|
|
|
|||
|
|
@ -440,14 +440,14 @@ object BuiltinCommands {
|
|||
|
||||
private[this] def quiet[T](t: => T): Option[T] =
|
||||
try Some(t)
|
||||
catch { case _: Exception => None }
|
||||
catch case _: Exception => None
|
||||
|
||||
def settingsCommand: Command =
|
||||
showSettingLike(
|
||||
SettingsCommand,
|
||||
settingsPreamble,
|
||||
KeyRanks.MainSettingCutoff,
|
||||
key => !isTask(key.manifest)
|
||||
key => key.tag.isSetting
|
||||
)
|
||||
|
||||
def tasks: Command =
|
||||
|
|
@ -455,7 +455,7 @@ object BuiltinCommands {
|
|||
TasksCommand,
|
||||
tasksPreamble,
|
||||
KeyRanks.MainTaskCutoff,
|
||||
key => isTask(key.manifest)
|
||||
key => key.tag.isTaskOrInputTask
|
||||
)
|
||||
|
||||
def showSettingLike(
|
||||
|
|
@ -518,11 +518,6 @@ object BuiltinCommands {
|
|||
def withDescription(keys: Seq[AttributeKey[_]]): Seq[AttributeKey[_]] =
|
||||
keys.filter(_.description.isDefined)
|
||||
|
||||
def isTask(
|
||||
mf: ClassTag[_]
|
||||
)(using taskMF: ClassTag[Task[_]], inputMF: ClassTag[InputTask[_]]): Boolean =
|
||||
mf.runtimeClass == taskMF.runtimeClass || mf.runtimeClass == inputMF.runtimeClass
|
||||
|
||||
def topNRanked(n: Int) = (keys: Seq[AttributeKey[_]]) => sortByRank(keys).take(n)
|
||||
|
||||
def highPass(rankCutoff: Int) =
|
||||
|
|
|
|||
|
|
@ -8,26 +8,20 @@
|
|||
package sbt
|
||||
|
||||
import Def.ScopedKey
|
||||
import sbt.internal.util.KeyTag
|
||||
|
||||
final case class ScopedKeyData[A](scoped: ScopedKey[A], value: Any) {
|
||||
import sbt.internal.util.Types.const
|
||||
val key = scoped.key
|
||||
val scope = scoped.scope
|
||||
def typeName: String = fold(fmtMf("Task[%s]"), fmtMf("InputTask[%s]"), key.manifest.toString)
|
||||
def settingValue: Option[Any] = fold(const(None), const(None), Some(value))
|
||||
def typeName: String = key.tag.toString
|
||||
def settingValue: Option[Any] =
|
||||
key.tag match
|
||||
case KeyTag.Setting(_) => Some(value)
|
||||
case _ => None
|
||||
def description: String =
|
||||
fold(
|
||||
fmtMf("Task: %s"),
|
||||
fmtMf("Input task: %s"),
|
||||
"Setting: %s = %s" format (key.manifest.toString, value.toString)
|
||||
)
|
||||
def fold[T](targ: OptManifest[_] => T, itarg: OptManifest[_] => T, s: => T): T =
|
||||
key.manifest.runtimeClass match
|
||||
case TaskClass => targ(key.manifest.typeArguments.head)
|
||||
case InputTaskClass => itarg(key.manifest.typeArguments.head)
|
||||
case _ => s
|
||||
def fmtMf(s: String): OptManifest[_] => String = s format _
|
||||
|
||||
private val TaskClass = classOf[Task[_]]
|
||||
private val InputTaskClass = classOf[InputTask[_]]
|
||||
key.tag match
|
||||
case KeyTag.Task(typeArg) => s"Task: $typeArg"
|
||||
case KeyTag.InputTask(typeArg) => s"Input task: $typeArg"
|
||||
case KeyTag.Setting(typeArg) => s"Setting: $typeArg = $value"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
package sbt
|
||||
package internal
|
||||
|
||||
import sbt.internal.util.{ AttributeKey, complete, Relation, Settings, Types, Util }
|
||||
import sbt.internal.util.{ AttributeKey, complete, KeyTag, Relation, Settings, Types, Util }
|
||||
import sbt.util.Show
|
||||
import sbt.librarymanagement.Configuration
|
||||
|
||||
|
|
@ -352,40 +352,16 @@ private[sbt] object SettingCompletions {
|
|||
*/
|
||||
def configScalaID(c: String): String = Util.quoteIfKeyword(c.capitalize)
|
||||
|
||||
/** Applies a function on the underlying manifest for T for `key` depending if it is for a `Setting[T]`, `Task[T]`, or `InputTask[T]`. */
|
||||
@nowarn
|
||||
def keyType[S](key: AttributeKey[_])(
|
||||
onSetting: ClassTag[_] => S,
|
||||
onTask: ClassTag[_] => S,
|
||||
onInput: ClassTag[_] => S
|
||||
)(using tm: ClassTag[Task[_]], im: ClassTag[InputTask[_]]): S =
|
||||
def argTpe = key.manifest.typeArguments.head match
|
||||
case m: Manifest[_] => m
|
||||
case _ => sys.error(s"Manifest not found for ${key} typeArgument")
|
||||
val TaskClass = tm.runtimeClass
|
||||
val InputTaskClass = im.runtimeClass
|
||||
key.manifest.runtimeClass match
|
||||
case TaskClass => onTask(argTpe)
|
||||
case InputTaskClass => onInput(argTpe)
|
||||
case _ => onSetting(key.manifest)
|
||||
|
||||
/** For a Task[T], InputTask[T], or Setting[T], this returns the manifest for T. */
|
||||
def keyUnderlyingType(key: AttributeKey[_]): ClassTag[_] =
|
||||
keyType(key)(idFun, idFun, idFun)
|
||||
|
||||
/**
|
||||
* Returns a string representation of the underlying type T for a `key` representing a `Setting[T]`, `Task[T]`, or `InputTask[T]`.
|
||||
* This string representation is currently a cleaned up toString of the underlying ClassTag.
|
||||
*/
|
||||
def keyTypeString[T](key: AttributeKey[_]): String =
|
||||
val tagToString = (tag: ClassTag[_]) => complete.TypeString.cleanup(tag.toString)
|
||||
keyType(key)(tagToString, tagToString, tagToString)
|
||||
complete.TypeString.cleanup(key.tag.typeArg.toString)
|
||||
|
||||
/** True if the `key` represents a setting or task that may be appended using an assignment method such as `+=`. */
|
||||
def appendable(key: AttributeKey[_]): Boolean = {
|
||||
val underlying = keyUnderlyingType(key).runtimeClass
|
||||
appendableClasses.exists(_ isAssignableFrom underlying)
|
||||
}
|
||||
def appendable(key: AttributeKey[_]): Boolean =
|
||||
appendableClasses.exists(_.isAssignableFrom(key.tag.typeArg))
|
||||
|
||||
/** The simple name of the Global scope, which can be used to reference it in the default setting context. */
|
||||
final val GlobalID = Scope.Global.getClass.getSimpleName.stripSuffix("$")
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ object SettingQuery {
|
|||
def getJsonWriter[A](key: AttributeKey[A]): Either[String, JsonWriter[A]] =
|
||||
key.optJsonWriter match {
|
||||
case SomeJsonWriter(jw) => Right(jw)
|
||||
case NoJsonWriter() => Left(s"JsonWriter for ${key.manifest} not found")
|
||||
case NoJsonWriter() => Left(s"JsonWriter for ${key.tag} not found")
|
||||
}
|
||||
|
||||
def toJson[A: JsonWriter](x: A): JValue = Converter toJsonUnsafe x
|
||||
|
|
@ -128,7 +128,7 @@ object SettingQuery {
|
|||
for {
|
||||
key <- key
|
||||
json <- getSettingJsonValue(structure, key)
|
||||
} yield SettingQuerySuccess(json, key.key.manifest.toString)
|
||||
} yield SettingQuerySuccess(json, key.key.tag.toString)
|
||||
}
|
||||
|
||||
def handleSettingQuery(req: SettingQuery, structure: BuildStructure): SettingQueryResponse =
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap
|
|||
import sbt.Keys._
|
||||
import sbt.internal.Clean.ToSeqPath
|
||||
import sbt.internal.Continuous.FileStampRepository
|
||||
import sbt.internal.util.AttributeKey
|
||||
import sbt.internal.util.KeyTag
|
||||
import sbt.internal.{ Clean, Continuous, DynamicInput, WatchTransitiveDependencies }
|
||||
import sbt.nio.FileStamp.Formats._
|
||||
import sbt.nio.FileStamper.{ Hash, LastModified }
|
||||
|
|
@ -53,7 +53,7 @@ private[sbt] object Settings {
|
|||
|
||||
/**
|
||||
* This method checks if the setting is for a task with a return type in:
|
||||
* `File`, `Seq[File]`, `Path`, `Seq[Path`. If it does, then we inject a number of
|
||||
* `File`, `Seq[File]`, `Path`, `Seq[Path]`. If it does, then we inject a number of
|
||||
* task definition settings that allow the user to check if the output paths of
|
||||
* the task have changed. It also adds a custom clean task that will delete the
|
||||
* paths returned by the task, provided that they are in the task's target directory. We also
|
||||
|
|
@ -68,10 +68,11 @@ private[sbt] object Settings {
|
|||
setting: Def.Setting[_],
|
||||
fileOutputScopes: Set[Scope]
|
||||
): List[Def.Setting[_]] = {
|
||||
setting.key.key match {
|
||||
case ak: AttributeKey[_] if taskClass.isAssignableFrom(ak.manifest.runtimeClass) =>
|
||||
val attributeKey = setting.key.key
|
||||
attributeKey.tag match {
|
||||
case tag: KeyTag.Task[?] =>
|
||||
def default: List[Def.Setting[_]] = {
|
||||
val scope = setting.key.scope.copy(task = Select(ak))
|
||||
val scope = setting.key.scope.copy(task = Select(attributeKey))
|
||||
if (fileOutputScopes.contains(scope)) {
|
||||
val sk = setting.asInstanceOf[Def.Setting[Task[Any]]].key
|
||||
val scopedKey = Keys.dynamicFileOutputs in (sk.scope in sk.key)
|
||||
|
|
@ -93,15 +94,15 @@ private[sbt] object Settings {
|
|||
addTaskDefinition(Def.setting[Task[Seq[Path]]](key, init, setting.pos)) ::
|
||||
outputsAndStamps(taskKey)
|
||||
}
|
||||
ak.manifest.typeArguments match
|
||||
case (t: Manifest[_]) :: Nil if seqClass.isAssignableFrom(t.runtimeClass) =>
|
||||
t.typeArguments match {
|
||||
case p :: Nil if pathClass.isAssignableFrom(p.runtimeClass) => mkSetting[Seq[Path]]
|
||||
case _ => default
|
||||
}
|
||||
case (t: Manifest[_]) :: Nil if pathClass.isAssignableFrom(t.runtimeClass) =>
|
||||
mkSetting[Path]
|
||||
case _ => default
|
||||
if seqClass.isAssignableFrom(tag.typeArg) then
|
||||
// TODO fix this: maybe using the taskKey macro to convey the information
|
||||
// t.typeArguments match {
|
||||
// case p :: Nil if pathClass.isAssignableFrom(p.runtimeClass) => mkSetting[Seq[Path]]
|
||||
// case _ => default
|
||||
// }
|
||||
default
|
||||
else if pathClass.isAssignableFrom(tag.typeArg) then mkSetting[Path]
|
||||
else default
|
||||
case _ => Nil
|
||||
}
|
||||
}
|
||||
|
|
@ -161,7 +162,6 @@ private[sbt] object Settings {
|
|||
}) :: fileStamps(scopedKey) :: allFilesImpl(scope) :: changedInputFilesImpl(scope)
|
||||
}
|
||||
|
||||
private[this] val taskClass = classOf[Task[_]]
|
||||
private[this] val seqClass = classOf[Seq[_]]
|
||||
private[this] val pathClass = classOf[java.nio.file.Path]
|
||||
|
||||
|
|
|
|||
|
|
@ -12,15 +12,32 @@ import scala.reflect.ClassTag
|
|||
import sbt.util.OptJsonWriter
|
||||
import sjsonnew.*
|
||||
|
||||
// T must be invariant to work properly.
|
||||
enum KeyTag[A]:
|
||||
case Setting[A](typeArg: Class[?]) extends KeyTag[A]
|
||||
case Task[A](typeArg: Class[?]) extends KeyTag[A]
|
||||
case InputTask[A](typeArg: Class[?]) extends KeyTag[A]
|
||||
|
||||
override def toString: String = this match
|
||||
case Setting(typeArg) => typeArg.toString
|
||||
case Task(typeArg) => s"Task[$typeArg]"
|
||||
case InputTask(typeArg) => s"InputTask[$typeArg]"
|
||||
|
||||
def typeArg: Class[?]
|
||||
def isSetting: Boolean = isInstanceOf[Setting[?]]
|
||||
def isTaskOrInputTask: Boolean = !isSetting
|
||||
end KeyTag
|
||||
|
||||
object KeyTag:
|
||||
given [A: ClassTag]: KeyTag[A] = Setting[A](summon[ClassTag[A]].runtimeClass)
|
||||
|
||||
// A must be invariant to work properly.
|
||||
// Because it is sealed and the only instances go through AttributeKey.apply,
|
||||
// a single AttributeKey instance cannot conform to AttributeKey[T] for different Ts
|
||||
// a single AttributeKey instance cannot conform to AttributeKey[A] for different As
|
||||
|
||||
sealed trait AttributeKey[A]:
|
||||
|
||||
/** The runtime evidence for `A`. */
|
||||
def manifest: ClassTag[A]
|
||||
// def classTag: ClassTag[A]
|
||||
def tag: KeyTag[A]
|
||||
|
||||
/** The label is the identifier for the key and is camelCase by convention. */
|
||||
def label: String
|
||||
|
|
@ -59,37 +76,37 @@ private[sbt] abstract class SharedAttributeKey[A] extends AttributeKey[A]:
|
|||
override final def hashCode = label.hashCode
|
||||
override final def equals(o: Any) =
|
||||
(this eq o.asInstanceOf[AnyRef]) || (o match {
|
||||
case a: SharedAttributeKey[t] => a.label == this.label && a.manifest == this.manifest
|
||||
case a: SharedAttributeKey[t] => a.label == this.label && a.tag == this.tag
|
||||
case _ => false
|
||||
})
|
||||
final def isLocal: Boolean = false
|
||||
end SharedAttributeKey
|
||||
|
||||
object AttributeKey {
|
||||
def apply[A: ClassTag: OptJsonWriter](name: String): AttributeKey[A] =
|
||||
def apply[A: KeyTag: OptJsonWriter](name: String): AttributeKey[A] =
|
||||
make(name, None, Nil, Int.MaxValue)
|
||||
|
||||
def apply[A: ClassTag: OptJsonWriter](name: String, rank: Int): AttributeKey[A] =
|
||||
def apply[A: KeyTag: OptJsonWriter](name: String, rank: Int): AttributeKey[A] =
|
||||
make(name, None, Nil, rank)
|
||||
|
||||
def apply[A: ClassTag: OptJsonWriter](name: String, description: String): AttributeKey[A] =
|
||||
def apply[A: KeyTag: OptJsonWriter](name: String, description: String): AttributeKey[A] =
|
||||
apply(name, description, Nil)
|
||||
|
||||
def apply[A: ClassTag: OptJsonWriter](
|
||||
def apply[A: KeyTag: OptJsonWriter](
|
||||
name: String,
|
||||
description: String,
|
||||
rank: Int
|
||||
): AttributeKey[A] =
|
||||
apply(name, description, Nil, rank)
|
||||
|
||||
def apply[A: ClassTag: OptJsonWriter](
|
||||
def apply[A: KeyTag: OptJsonWriter](
|
||||
name: String,
|
||||
description: String,
|
||||
extend: Seq[AttributeKey[_]]
|
||||
): AttributeKey[A] =
|
||||
apply(name, description, extend, Int.MaxValue)
|
||||
|
||||
def apply[A: ClassTag: OptJsonWriter](
|
||||
def apply[A: KeyTag: OptJsonWriter](
|
||||
name: String,
|
||||
description: String,
|
||||
extend: Seq[AttributeKey[_]],
|
||||
|
|
@ -98,40 +115,39 @@ object AttributeKey {
|
|||
make(name, Some(description), extend, rank)
|
||||
|
||||
private[sbt] def copyWithRank[A](a: AttributeKey[A], rank: Int): AttributeKey[A] =
|
||||
make(a.label, a.description, a.extend, rank)(using a.manifest, a.optJsonWriter)
|
||||
make(a.label, a.description, a.extend, rank)(using a.tag, a.optJsonWriter)
|
||||
|
||||
private[this] def make[A](
|
||||
private[this] def make[A: KeyTag: OptJsonWriter](
|
||||
name: String,
|
||||
description0: Option[String],
|
||||
extend0: Seq[AttributeKey[_]],
|
||||
rank0: Int
|
||||
)(using mf: ClassTag[A], ojw: OptJsonWriter[A]): AttributeKey[A] =
|
||||
): AttributeKey[A] =
|
||||
new SharedAttributeKey[A]:
|
||||
require(
|
||||
name.headOption.exists(_.isLower),
|
||||
s"A named attribute key must start with a lowercase letter: $name"
|
||||
)
|
||||
|
||||
override def manifest: ClassTag[A] = mf
|
||||
override def tag: KeyTag[A] = summon
|
||||
override val label: String = Util.hyphenToCamel(name)
|
||||
override def description: Option[String] = description0
|
||||
override def extend: Seq[AttributeKey[_]] = extend0
|
||||
override def rank: Int = rank0
|
||||
override def optJsonWriter: OptJsonWriter[A] = ojw
|
||||
override def optJsonWriter: OptJsonWriter[A] = summon
|
||||
|
||||
private[sbt] def local[A](using ct: ClassTag[A], ojw: OptJsonWriter[A]): AttributeKey[A] =
|
||||
private[sbt] def local[A: KeyTag: OptJsonWriter]: AttributeKey[A] =
|
||||
new AttributeKey[A]:
|
||||
override def manifest: ClassTag[A] = ct
|
||||
override def tag: KeyTag[A] = summon
|
||||
override def label: String = LocalLabel
|
||||
override def description: Option[String] = None
|
||||
override def extend: Seq[AttributeKey[_]] = Nil
|
||||
override def toString = label
|
||||
override def isLocal: Boolean = true
|
||||
override def rank: Int = Int.MaxValue
|
||||
override val optJsonWriter: OptJsonWriter[A] = ojw
|
||||
override val optJsonWriter: OptJsonWriter[A] = summon
|
||||
|
||||
private[sbt] final val LocalLabel = "$" + "local"
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue