diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 22c9967..6cb9a37 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -45,6 +45,7 @@ jobs: INPUT_BASE_CONFIG: ${{ matrix.build-config }} INPUT_EXTRA_FLAGS: ${{ matrix.extra-flags }} run: | + sudo apt-get update sudo apt-get install -y cmake build-essential ${INPUT_COMPILER} - name: Prepare build env: diff --git a/README.md b/README.md index 7acd2ef..0a274ec 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ More detailed examples and features description can be found in the documentatio ## Current Jinja2 support Currently, Jinja2C++ supports the limited number of Jinja2 features. By the way, Jinja2C++ is planned to be a full [jinja2 specification](http://jinja.pocoo.org/docs/2.10/templates/)-conformant. The current support is limited to: - expressions. You can use almost every expression style: simple, filtered, conditional, and so on. -- the big number of filters (**sort, default, first, last, length, max, min, reverse, unique, sum, attr, map, reject, rejectattr, select, selectattr, pprint, dictsort, abs, float, int, list, round, random, trim, title, upper, wordcount, replace, truncate, groupby, urlencode, capitalize, escape, tojson**) +- the big number of filters (**sort, default, first, last, length, max, min, reverse, unique, sum, attr, map, reject, rejectattr, select, selectattr, pprint, dictsort, abs, float, int, list, round, random, trim, title, upper, wordcount, replace, truncate, groupby, urlencode, capitalize, escape, tojson, striptags**) - the big number of testers (**eq, defined, ge, gt, iterable, le, lt, mapping, ne, number, sequence, string, undefined, in, even, odd, lower, upper**) - the number of functions (**range**, **loop.cycle**) - 'if' statement (with 'elif' and 'else' branches) diff --git a/src/filters.cpp b/src/filters.cpp index 22d784d..1ec0f4a 100644 --- a/src/filters.cpp +++ b/src/filters.cpp @@ -70,6 +70,7 @@ std::unordered_map s_filters = { {"selectattr", FilterFactory::MakeCreator(filters::Tester::SelectAttrMode)}, {"slice", FilterFactory::MakeCreator(filters::Slice::SliceMode)}, {"sort", &FilterFactory::Create}, + {"striptags", FilterFactory::MakeCreator(filters::StringConverter::StriptagsMode) }, {"sum", FilterFactory::MakeCreator(filters::SequenceAccessor::SumItemsMode)}, {"title", FilterFactory::MakeCreator(filters::StringConverter::TitleMode)}, {"tojson", FilterFactory::MakeCreator(filters::Serialize::JsonMode)}, diff --git a/src/filters.h b/src/filters.h index 75dfa66..31a5ab0 100644 --- a/src/filters.h +++ b/src/filters.h @@ -182,6 +182,7 @@ class StringConverter : public FilterBase EscapeHtmlMode, LowerMode, ReplaceMode, + StriptagsMode, TitleMode, TrimMode, TruncateMode, diff --git a/src/string_converter_filter.cpp b/src/string_converter_filter.cpp index 9e51f45..18a0701 100644 --- a/src/string_converter_filter.cpp +++ b/src/string_converter_filter.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -343,6 +344,30 @@ InternalValue StringConverter::Filter(const InternalValue& baseVal, RenderContex } }); break; + case StriptagsMode: + result = ApplyStringConverter(baseVal, [](auto srcStr) -> TargetString { + auto str = sv_to_string(srcStr); + using StringT = decltype(str); + using CharT = typename StringT::value_type; + static const std::basic_regex STRIPTAGS_RE(UNIVERSAL_STR("(|<[^>]*>)").GetValue()); + str = std::regex_replace(str, STRIPTAGS_RE, UNIVERSAL_STR("").GetValue()); + ba::trim_all(str); + static const StringT html_entities [] { + UNIVERSAL_STR("&").GetValue(), UNIVERSAL_STR("&").GetValue(), + UNIVERSAL_STR("'").GetValue(), UNIVERSAL_STR("\'").GetValue(), + UNIVERSAL_STR(">").GetValue(), UNIVERSAL_STR(">").GetValue(), + UNIVERSAL_STR("<").GetValue(), UNIVERSAL_STR("<").GetValue(), + UNIVERSAL_STR(""").GetValue(), UNIVERSAL_STR("\"").GetValue(), + UNIVERSAL_STR("'").GetValue(), UNIVERSAL_STR("\'").GetValue(), + UNIVERSAL_STR(""").GetValue(), UNIVERSAL_STR("\"").GetValue(), + }; + for (auto it = std::begin(html_entities), end = std::end(html_entities); it < end; it += 2) + { + ba::replace_all(str, *it, *(it + 1)); + } + return str; + }); + break; default: break; } diff --git a/test/filters_test.cpp b/test/filters_test.cpp index 52ae811..e331365 100644 --- a/test/filters_test.cpp +++ b/test/filters_test.cpp @@ -555,3 +555,12 @@ INSTANTIATE_TEST_CASE_P(ListSlice, ListSliceTest, ::testing::Values( InputOutputPair{"[1, 2, 3, 4, 5, 6, 7] | slice(3) | pprint", "[[1, 2, 3], [4, 5, 6], [7]]"}, InputOutputPair{"[1, 2, 3, 4, 5, 6, 7] | slice(3, 0) | pprint", "[[1, 2, 3], [4, 5, 6], [7, 0, 0]]"} )); + +INSTANTIATE_TEST_CASE_P(Striptags, FilterGenericTest, ::testing::Values( + InputOutputPair{ "' Hello World ' | striptags | pprint", "'Hello World'" }, + InputOutputPair{ "'foo baz ' | striptags | pprint", "'foo baz'" }, + InputOutputPair{"'ab&cd&><efgh' | striptags | pprint", "'ab&cd&>Foo & Bar' | striptags | pprint", "'Foo & Bar'"}, + InputOutputPair{"'&'><"'\""' | striptags | pprint", "'&\'><\"\'\"\"'"}, + InputOutputPair{"'"'' | striptags | pprint", "'\"\''"})); +