/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ // SPDX-License-Identifier: GPL-3.0 /** @file Whiskers.h * @author Chris * @date 2017 * * Moustache-like templates. */ #pragma once #include #include #include #include namespace solidity::util { DEV_SIMPLE_EXCEPTION(WhiskersError); /** * Moustache-like templates. * * Usage: * std::vector> listValues(2); * listValues[0]["k"] = "key1"; * listValues[0]["v"] = "value1"; * listValues[1]["k"] = "key2"; * listValues[1]["v"] = "value2"; * auto s = Whiskers("y\n<#list> -> \n") * ("p1", "HEAD") * ("c", true) * ("list", listValues) * .render(); * * results in s == "HEAD\nkey1 -> value1\nkey2 -> value2\n" * * Note that lists cannot themselves contain lists - this would be a future feature. * * The elements are: * - Regular parameter: * just replaced * - Condition parameter: ......, where "" is optional * replaced (and recursively expanded) by the first part if the condition is true * and by the second (or empty string if missing) if the condition is false * - List parameter: <#list>... * The part between the tags is repeated as often as values are provided * in the mapping. Each list element can have its own parameter -> value mapping. * - Conditional value parameter: ...... * Works similar to a conditional parameter where the checked condition is * that the string or list parameter called "name" is non-empty or contains * no elements respectively. */ class Whiskers { public: using StringMap = std::map; using StringListMap = std::map>; explicit Whiskers(std::string _template = ""); /// Sets a single regular parameter, . Whiskers& operator()(std::string _parameter, std::string _value); Whiskers& operator()(std::string _parameter, char const* _value) { return (*this)(_parameter, std::string{_value}); } /// Sets a condition parameter, ...... Whiskers& operator()(std::string _parameter, bool _value); /// Sets a list parameter, <#listName> . Whiskers& operator()( std::string _listParameter, std::vector _values ); std::string render() const; private: // Prevent implicit cast to bool Whiskers& operator()(std::string _parameter, long long); void checkTemplateValid() const; void checkParameterValid(std::string const& _parameter) const; void checkParameterUnknown(std::string const& _parameter) const; /// Checks whether the string stored in `m_template` contains all the tags specified. /// @param _parameter name of the parameter. This name is used to construct the tag(s). /// @param _prefixes a vector of strings, where each element is used to compose the tag /// like `"<" + element + _parameter + ">"`. Each element of _prefixes is used as a prefix of the tag name. void checkTemplateContainsTags(std::string const& _parameter, std::vector const& _prefixes) const; static std::string replace( std::string const& _template, StringMap const& _parameters, std::map const& _conditions, StringListMap const& _listParameters = StringListMap() ); static std::string paramRegex() { return "[a-zA-Z0-9_$-]+"; } /// Joins the two maps throwing an exception if two keys are equal. static StringMap joinMaps(StringMap const& _a, StringMap const& _b); std::string m_template; StringMap m_parameters; std::map m_conditions; StringListMap m_listParameters; }; }