Skip to content

Commit 69abcf9

Browse files
committed
Implement block quote whitespace normalization
1 parent 2ef4bfc commit 69abcf9

File tree

4 files changed

+138
-4
lines changed

4 files changed

+138
-4
lines changed

include/graphqlservice/internal/Grammar.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,29 @@ struct block_escape_sequence : seq<backslash_token, block_quote_token>
151151
};
152152

153153
struct block_quote_character
154-
: plus<not_at<block_quote_token>, not_at<block_escape_sequence>, source_character>
154+
: plus<not_at<ascii::eol>, not_at<block_quote_token>, not_at<block_escape_sequence>, source_character>
155+
{
156+
};
157+
158+
struct block_quote_empty_line : star<not_at<eol>, space>
159+
{
160+
};
161+
162+
struct block_quote_line_content
163+
: plus<sor<block_escape_sequence, block_quote_character>>
164+
{
165+
};
166+
167+
struct block_quote_line : seq<block_quote_empty_line, block_quote_line_content>
168+
{
169+
};
170+
171+
struct block_quote_content_lines: opt<list<sor<block_quote_line, block_quote_empty_line>, eol>>
155172
{
156173
};
157174

158175
struct block_quote_content
159-
: seq<star<sor<block_escape_sequence, block_quote_character>>, must<block_quote_token>>
176+
: seq<block_quote_content_lines, must<block_quote_token>>
160177
{
161178
};
162179

samples/today/schema.today.graphql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ type Mutation {
9696
setFloat(value: Float!): Float!
9797
}
9898

99+
"""
100+
101+
Subscription type:
102+
103+
2nd line...
104+
3rd line goes here!
105+
106+
"""
99107
type Subscription {
100108
nextAppointmentChange : Appointment @deprecated(
101109
reason:"""Need to deprecate a [field](http://spec.graphql.org/June2018/#sec-Deprecation)"""

samples/today/schema/TodaySchema.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,10 @@ void AddTypesToSchema(const std::shared_ptr<schema::Schema>& schema)
196196
schema->AddType(R"gql(CompleteTaskPayload)gql"sv, typeCompleteTaskPayload);
197197
auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"sv);
198198
schema->AddType(R"gql(Mutation)gql"sv, typeMutation);
199-
auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md()md"sv);
199+
auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md(Subscription type:
200+
201+
2nd line...
202+
3rd line goes here!)md"sv);
200203
schema->AddType(R"gql(Subscription)gql"sv, typeSubscription);
201204
auto typeAppointment = schema::ObjectType::Make(R"gql(Appointment)gql"sv, R"md()md"sv);
202205
schema->AddType(R"gql(Appointment)gql"sv, typeAppointment);

src/SyntaxTree.cpp

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
#include <tao/pegtl/contrib/unescape.hpp>
1010

1111
#include <functional>
12+
#include <iterator>
1213
#include <memory>
1314
#include <numeric>
15+
#include <optional>
1416
#include <tuple>
17+
#include <utility>
1518

1619
using namespace std::literals;
1720

@@ -47,7 +50,90 @@ std::string_view ast_node::unescaped_view() const
4750
{
4851
if (!_unescaped)
4952
{
50-
if (children.size() > 1)
53+
if (is_type<block_quote_content_lines>())
54+
{
55+
// Trim leading and trailing empty lines
56+
const auto isNonEmptyLine = [](const std::unique_ptr<ast_node>& child) noexcept {
57+
return child->is_type<block_quote_line>();
58+
};
59+
const auto itrEndRev = std::make_reverse_iterator(
60+
std::find_if(children.cbegin(), children.cend(), isNonEmptyLine));
61+
const auto itrRev = std::find_if(children.crbegin(), itrEndRev, isNonEmptyLine);
62+
std::vector<std::optional<std::pair<std::string_view, std::string_view>>> lines(
63+
std::distance(itrRev, itrEndRev));
64+
65+
std::transform(itrRev,
66+
itrEndRev,
67+
lines.rbegin(),
68+
[](const std::unique_ptr<ast_node>& child) noexcept {
69+
return (child->is_type<block_quote_line>() && !child->children.empty()
70+
&& child->children.front()->is_type<block_quote_empty_line>()
71+
&& child->children.back()->is_type<block_quote_line_content>())
72+
? std::make_optional(std::make_pair(child->children.front()->string_view(),
73+
child->children.back()->unescaped_view()))
74+
: std::nullopt;
75+
});
76+
77+
// Calculate the common indent
78+
const auto commonIndent = std::accumulate(lines.cbegin(),
79+
lines.cend(),
80+
std::optional<size_t> {},
81+
[](auto value, const auto& line) noexcept {
82+
if (line)
83+
{
84+
const auto indent = line->first.size();
85+
86+
if (!value || indent < *value)
87+
{
88+
value = indent;
89+
}
90+
}
91+
92+
return value;
93+
});
94+
95+
const auto trimIndent = commonIndent ? *commonIndent : 0;
96+
std::string joined;
97+
98+
if (!lines.empty())
99+
{
100+
joined.reserve(std::accumulate(lines.cbegin(),
101+
lines.cend(),
102+
size_t {},
103+
[trimIndent](auto value, const auto& line) noexcept {
104+
if (line)
105+
{
106+
value += line->first.size() - trimIndent;
107+
value += line->second.size();
108+
}
109+
110+
return value;
111+
})
112+
+ lines.size() - 1);
113+
114+
bool firstLine = true;
115+
116+
for (const auto& line : lines)
117+
{
118+
if (!firstLine)
119+
{
120+
joined.append(1, '\n');
121+
}
122+
123+
if (line)
124+
{
125+
joined.append(line->first.substr(trimIndent));
126+
joined.append(line->second);
127+
}
128+
129+
firstLine = false;
130+
}
131+
}
132+
133+
const_cast<ast_node*>(this)->_unescaped =
134+
std::make_unique<unescaped_t>(std::move(joined));
135+
}
136+
else if (children.size() > 1)
51137
{
52138
std::string joined;
53139

@@ -224,6 +310,26 @@ struct ast_selector<block_escape_sequence> : std::true_type
224310
}
225311
};
226312

313+
template <>
314+
struct ast_selector<block_quote_content_lines> : std::true_type
315+
{
316+
};
317+
318+
template <>
319+
struct ast_selector<block_quote_empty_line> : std::true_type
320+
{
321+
};
322+
323+
template <>
324+
struct ast_selector<block_quote_line> : std::true_type
325+
{
326+
};
327+
328+
template <>
329+
struct ast_selector<block_quote_line_content> : std::true_type
330+
{
331+
};
332+
227333
template <>
228334
struct ast_selector<block_quote_character> : std::true_type
229335
{

0 commit comments

Comments
 (0)