
scala.build.preprocessing.MarkdownPreprocessor.scala Maven / Gradle / Ivy
package scala.build.preprocessing
import java.nio.charset.StandardCharsets
import scala.build.EitherCps.{either, value}
import scala.build.Logger
import scala.build.errors.BuildException
import scala.build.input.{
Inputs,
MarkdownFile,
ScalaCliInvokeData,
SingleElement,
VirtualMarkdownFile
}
import scala.build.internal.markdown.{MarkdownCodeBlock, MarkdownCodeWrapper}
import scala.build.internal.{AmmUtil, Name}
import scala.build.options.{BuildOptions, BuildRequirements, SuppressWarningOptions}
import scala.build.preprocessing.ScalaPreprocessor.ProcessingOutput
case object MarkdownPreprocessor extends Preprocessor {
def preprocess(
input: SingleElement,
logger: Logger,
maybeRecoverOnError: BuildException => Option[BuildException],
allowRestrictedFeatures: Boolean,
suppressWarningOptions: SuppressWarningOptions
)(using ScalaCliInvokeData): Option[Either[BuildException, Seq[PreprocessedSource]]] =
input match {
case markdown: MarkdownFile =>
val res = either {
val content = value(PreprocessingUtil.maybeRead(markdown.path))
val preprocessed = value {
MarkdownPreprocessor.preprocess(
Right(markdown.path),
content,
markdown.subPath,
ScopePath.fromPath(markdown.path),
logger,
maybeRecoverOnError,
allowRestrictedFeatures,
suppressWarningOptions
)
}
preprocessed
}
Some(res)
case markdown: VirtualMarkdownFile =>
val content = new String(markdown.content, StandardCharsets.UTF_8)
val res = either {
val preprocessed = value {
MarkdownPreprocessor.preprocess(
Left(markdown.source),
content,
markdown.wrapperPath,
markdown.scopePath,
logger,
maybeRecoverOnError,
allowRestrictedFeatures,
suppressWarningOptions
)
}
preprocessed
}
Some(res)
case _ =>
None
}
private def preprocess(
reportingPath: Either[String, os.Path],
content: String,
subPath: os.SubPath,
scopePath: ScopePath,
logger: Logger,
maybeRecoverOnError: BuildException => Option[BuildException],
allowRestrictedFeatures: Boolean,
suppressWarningOptions: SuppressWarningOptions
)(using ScalaCliInvokeData): Either[BuildException, List[PreprocessedSource.InMemory]] = either {
def preprocessSnippets(
maybeWrapper: Option[MarkdownCodeWrapper.WrappedMarkdownCode],
generatedSourceNameSuffix: String
): Either[BuildException, Option[PreprocessedSource.InMemory]] =
either {
maybeWrapper
.map { wrappedMarkdown =>
val processingOutput: ProcessingOutput =
value {
ScalaPreprocessor.processSources(
content = wrappedMarkdown.code,
extractedDirectives = wrappedMarkdown.directives,
path = reportingPath,
scopeRoot = scopePath / os.up,
logger = logger,
allowRestrictedFeatures = allowRestrictedFeatures,
suppressWarningOptions = suppressWarningOptions,
maybeRecoverOnError = maybeRecoverOnError
)
}.getOrElse(ProcessingOutput.empty)
val processedCode = processingOutput.updatedContent.getOrElse(wrappedMarkdown.code)
PreprocessedSource.InMemory(
originalPath = reportingPath.map(subPath -> _),
relPath = os.rel / (subPath / os.up) / s"${subPath.last}$generatedSourceNameSuffix",
processedCode.getBytes(StandardCharsets.UTF_8),
wrapperParamsOpt = None,
options = Some(processingOutput.opts),
optionsWithTargetRequirements = processingOutput.optsWithReqs,
requirements = Some(processingOutput.globalReqs),
processingOutput.scopedReqs,
mainClassOpt = None,
scopePath = scopePath,
directivesPositions = processingOutput.directivesPositions
)
}
}
val codeBlocks: Seq[MarkdownCodeBlock] =
value(MarkdownCodeBlock.findCodeBlocks(subPath, content, maybeRecoverOnError))
val preprocessedMarkdown: PreprocessedMarkdown =
value(MarkdownCodeBlockProcessor.process(
codeBlocks,
reportingPath,
scopePath,
logger,
maybeRecoverOnError
))
val (mainScalaCode, rawScalaCode, testScalaCode) =
MarkdownCodeWrapper(subPath, preprocessedMarkdown)
val maybeMainFile = value(preprocessSnippets(mainScalaCode, ".scala"))
val maybeRawFile = value(preprocessSnippets(rawScalaCode, ".raw.scala"))
val maybeTestFile = value(preprocessSnippets(testScalaCode, ".test.scala"))
maybeMainFile.toList ++ maybeTestFile ++ maybeRawFile
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy