<commit_before>/*
 * Copyright 2013-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package laika.directive

import com.typesafe.config.{Config, ConfigFactory, ConfigParseOptions, ConfigValueFactory}
import laika.parse.core.Parser
import laika.parse.core.combinator.Parsers
import laika.parse.core.text.TextParsers
import laika.parse.core.text.TextParsers._
import laika.tree.Elements.InvalidElement
import laika.tree.Paths.Path

/**
  * @author <NAME>
  */
object ConfigHeaderParser {

  type ConfigHeaderParser = Parser[Either[InvalidElement, Config]]

  def withDefaultLineDelimiters(path: Path): ConfigHeaderParser = betweenLines("{%","%}")(path)

  def betweenLines(startDelim: String, endDelim: String)(path: Path): ConfigHeaderParser = {
    val parser = startDelim ~> TextParsers.delimitedBy(endDelim) <~ wsEol
    forTextParser(parser)(path)
  }

  def beforeLine(endDelim: String)(path: Path): ConfigHeaderParser = {
    val parser = TextParsers.delimitedBy(endDelim) <~ wsEol
    forTextParser(parser)(path)
  }

  def forTextParser (parser: Parser[String])(path: Path): ConfigHeaderParser = parser ^^ { str =>
    try {
      Right(ConfigFactory.parseString(str, ConfigParseOptions.defaults().setOriginDescription(s"path:$path")))
    }
    catch {
      case ex: Exception => Left(InvalidElement("Error parsing config header: "+ex.getMessage, s"{%$str%}"))
    }
  }

  def merged (parsers: Seq[Path => ConfigHeaderParser])(path: Path): ConfigHeaderParser =
    parsers.map(_(path)).reduce(_ | _)

  val fallback: Path => Parser[Either[InvalidElement, Config]] = { _ => Parsers.success(Right(ConfigFactory.empty)) }

  def merge (config: Config, values: Map[String, AnyRef]): Config = {
    import scala.collection.JavaConverters._
    val javaValues = values.mapValues {
      case m: Map[_,_]      => m.asJava
      case it: Iterable[_]  => it.asJava
      case other            => other
    }
    (config /: javaValues) { case (config, (name, value)) =>
      config.withValue(name, ConfigValueFactory.fromAnyRef(value)) // TODO - simply use fromMap?
    }
  }


}<commit_msg>simplify ConfigHeaderParser.merge<commit_after>/*
 * Copyright 2013-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package laika.directive

import com.typesafe.config.{Config, ConfigFactory, ConfigParseOptions}
import laika.parse.core.Parser
import laika.parse.core.combinator.Parsers
import laika.parse.core.text.TextParsers
import laika.parse.core.text.TextParsers._
import laika.tree.Elements.InvalidElement
import laika.tree.Paths.Path

/**
  * @author <NAME>
  */
object ConfigHeaderParser {

  type ConfigHeaderParser = Parser[Either[InvalidElement, Config]]

  def withDefaultLineDelimiters(path: Path): ConfigHeaderParser = betweenLines("{%","%}")(path)

  def betweenLines(startDelim: String, endDelim: String)(path: Path): ConfigHeaderParser = {
    val parser = startDelim ~> TextParsers.delimitedBy(endDelim) <~ wsEol
    forTextParser(parser)(path)
  }

  def beforeLine(endDelim: String)(path: Path): ConfigHeaderParser = {
    val parser = TextParsers.delimitedBy(endDelim) <~ wsEol
    forTextParser(parser)(path)
  }

  def forTextParser (parser: Parser[String])(path: Path): ConfigHeaderParser = parser ^^ { str =>
    try {
      Right(ConfigFactory.parseString(str, ConfigParseOptions.defaults().setOriginDescription(s"path:$path")))
    }
    catch {
      case ex: Exception => Left(InvalidElement("Error parsing config header: "+ex.getMessage, s"{%$str%}"))
    }
  }

  def merged (parsers: Seq[Path => ConfigHeaderParser])(path: Path): ConfigHeaderParser =
    parsers.map(_(path)).reduce(_ | _)

  val fallback: Path => Parser[Either[InvalidElement, Config]] = { _ => Parsers.success(Right(ConfigFactory.empty)) }

  def merge (config: Config, values: Map[String, AnyRef]): Config = {
    import scala.collection.JavaConverters._
    val javaValues = values.mapValues {
      case m: Map[_,_]      => m.asJava
      case it: Iterable[_]  => it.asJava
      case other            => other
    }
    config.withFallback(ConfigFactory.parseMap(javaValues.asJava))
  }


}
{'fraction_non_alphanumeric': 0.1163104178702099, 'fraction_numerical': 0.00462160600808781, 'mean_word_length': 4.2044088176352705, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1085867', 'n_tokens_mistral': 1576, 'n_tokens_neox': 1515, 'n_words': 413}