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

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