redsnow 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -0
- data/ext/snowcrash/Makefile +1 -1
- data/ext/snowcrash/bin/snowcrash +0 -0
- data/ext/snowcrash/configure +9 -9
- data/ext/snowcrash/ext/markdown-parser/Makefile +87 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/CONTRIBUTING.md +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/Makefile +2 -1
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/Makefile.win +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/examples/smartypants.c +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/examples/sundown.c +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/houdini.h +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/houdini_href_e.c +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/houdini_html_e.c +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/html.c +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/html.h +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/html_smartypants.c +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html_block_names.txt +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/autolink.c +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/autolink.h +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/buffer.c +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/buffer.h +1 -1
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/html_blocks.h +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/markdown.c +9 -3
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/markdown.h +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/src_map.c +11 -7
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/src_map.h +1 -1
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/stack.c +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/stack.h +0 -0
- data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/sundown.def +0 -0
- data/ext/snowcrash/ext/markdown-parser/msvc/markdown/markdown.vcproj +188 -0
- data/ext/snowcrash/ext/markdown-parser/msvc/msvc.sln +38 -0
- data/ext/snowcrash/ext/markdown-parser/msvc/sundown/sundown.vcproj +206 -0
- data/ext/snowcrash/ext/markdown-parser/src/ByteBuffer.cc +92 -0
- data/ext/snowcrash/ext/markdown-parser/src/ByteBuffer.h +82 -0
- data/ext/snowcrash/ext/markdown-parser/src/MarkdownNode.cc +152 -0
- data/ext/snowcrash/ext/markdown-parser/src/MarkdownNode.h +103 -0
- data/ext/snowcrash/ext/markdown-parser/src/MarkdownParser.cc +388 -0
- data/ext/snowcrash/{src → ext/markdown-parser/src}/MarkdownParser.h +43 -33
- data/ext/snowcrash/snowcrash.gyp +114 -63
- data/ext/snowcrash/src/ActionParser.h +334 -398
- data/ext/snowcrash/src/AssetParser.h +82 -171
- data/ext/snowcrash/src/Blueprint.h +7 -2
- data/ext/snowcrash/src/BlueprintParser.h +212 -286
- data/ext/snowcrash/src/BlueprintUtility.h +2 -2
- data/ext/snowcrash/src/CBlueprint.h +1 -1
- data/ext/snowcrash/src/CSourceAnnotation.cc +11 -11
- data/ext/snowcrash/src/CSourceAnnotation.h +9 -9
- data/ext/snowcrash/src/CodeBlockUtility.h +199 -149
- data/ext/snowcrash/src/HeadersParser.h +197 -0
- data/ext/snowcrash/src/ParameterParser.h +429 -0
- data/ext/snowcrash/src/ParametersParser.h +136 -211
- data/ext/snowcrash/src/PayloadParser.h +458 -562
- data/ext/snowcrash/src/Platform.h +0 -3
- data/ext/snowcrash/src/ResourceGroupParser.h +183 -164
- data/ext/snowcrash/src/ResourceParser.h +325 -493
- data/ext/snowcrash/src/Section.cc +42 -0
- data/ext/snowcrash/src/Section.h +47 -0
- data/ext/snowcrash/src/SectionParser.h +229 -0
- data/ext/snowcrash/src/SectionParserData.h +81 -0
- data/ext/snowcrash/src/SectionProcessor.h +211 -0
- data/ext/snowcrash/src/Signature.cc +74 -0
- data/ext/snowcrash/src/Signature.h +32 -0
- data/ext/snowcrash/src/SourceAnnotation.h +7 -20
- data/ext/snowcrash/src/StringUtility.h +30 -10
- data/ext/snowcrash/src/SymbolTable.h +7 -7
- data/ext/snowcrash/src/UriTemplateParser.cc +10 -10
- data/ext/snowcrash/src/UriTemplateParser.h +11 -14
- data/ext/snowcrash/src/ValuesParser.h +122 -0
- data/ext/snowcrash/src/Version.h +2 -2
- data/ext/snowcrash/src/csnowcrash.cc +5 -5
- data/ext/snowcrash/src/csnowcrash.h +3 -3
- data/ext/snowcrash/src/snowcrash.cc +74 -4
- data/ext/snowcrash/src/snowcrash.h +9 -4
- data/ext/snowcrash/src/snowcrash/snowcrash.cc +16 -16
- data/ext/snowcrash/tools/homebrew/snowcrash.rb +3 -2
- data/ext/snowcrash/vcbuild.bat +13 -4
- data/lib/redsnow.rb +5 -5
- data/lib/redsnow/binding.rb +1 -1
- data/lib/redsnow/blueprint.rb +33 -2
- data/lib/redsnow/parseresult.rb +7 -4
- data/lib/redsnow/version.rb +1 -1
- data/test/redsnow_binding_test.rb +6 -6
- data/test/redsnow_parseresult_test.rb +1 -1
- metadata +62 -42
- data/ext/snowcrash/src/BlockUtility.h +0 -186
- data/ext/snowcrash/src/BlueprintParserCore.h +0 -190
- data/ext/snowcrash/src/BlueprintSection.h +0 -140
- data/ext/snowcrash/src/DescriptionSectionUtility.h +0 -156
- data/ext/snowcrash/src/HeaderParser.h +0 -289
- data/ext/snowcrash/src/ListBlockUtility.h +0 -273
- data/ext/snowcrash/src/ListUtility.h +0 -95
- data/ext/snowcrash/src/MarkdownBlock.cc +0 -176
- data/ext/snowcrash/src/MarkdownBlock.h +0 -93
- data/ext/snowcrash/src/MarkdownParser.cc +0 -266
- data/ext/snowcrash/src/ParameterDefinitonParser.h +0 -645
- data/ext/snowcrash/src/Parser.cc +0 -71
- data/ext/snowcrash/src/Parser.h +0 -29
- data/ext/snowcrash/src/ParserCore.cc +0 -120
- data/ext/snowcrash/src/ParserCore.h +0 -82
- data/ext/snowcrash/src/SectionUtility.h +0 -142
|
@@ -9,244 +9,169 @@
|
|
|
9
9
|
#ifndef SNOWCRASH_PARAMETERSPARSER_H
|
|
10
10
|
#define SNOWCRASH_PARAMETERSPARSER_H
|
|
11
11
|
|
|
12
|
-
#include
|
|
13
|
-
#include "
|
|
14
|
-
#include "Blueprint.h"
|
|
12
|
+
#include "SectionParser.h"
|
|
13
|
+
#include "ParameterParser.h"
|
|
15
14
|
#include "RegexMatch.h"
|
|
16
15
|
#include "StringUtility.h"
|
|
17
|
-
#include "
|
|
18
|
-
|
|
16
|
+
#include "BlueprintUtility.h"
|
|
17
|
+
|
|
18
|
+
namespace snowcrash {
|
|
19
19
|
|
|
20
|
-
namespace snowcrashconst {
|
|
21
|
-
|
|
22
20
|
/** Parameters matching regex */
|
|
23
21
|
const char* const ParametersRegex = "^[[:blank:]]*[Pp]arameters?[[:blank:]]*$";
|
|
24
22
|
|
|
25
|
-
/** Expected parameters content */
|
|
26
|
-
const char* const ExpectedParametersContent = "a nested list of parameters, one parameter per list item";
|
|
27
|
-
|
|
28
23
|
/** No parameters specified message */
|
|
29
24
|
const char* const NoParametersMessage = "no parameters specified, expected a nested list of parameters, one parameter per list item";
|
|
30
|
-
}
|
|
31
25
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
/** Internal type alias for Collection of Paramaeter */
|
|
35
|
-
typedef Collection<Parameter>::type ParameterCollection;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
/** Finds a parameter inside a parameters collection */
|
|
39
|
-
FORCEINLINE ParameterCollection::iterator FindParameter(ParameterCollection& parameters,
|
|
40
|
-
const Parameter& parameter) {
|
|
41
|
-
return std::find_if(parameters.begin(),
|
|
42
|
-
parameters.end(),
|
|
43
|
-
std::bind2nd(MatchName<Parameter>(), parameter));
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Returns true if given block has parameters signature, false otherwise.
|
|
48
|
-
*/
|
|
49
|
-
FORCEINLINE bool HasParametersSignature(const BlockIterator& begin,
|
|
50
|
-
const BlockIterator& end) {
|
|
26
|
+
/** Internal type alias for Collection of Parameter */
|
|
27
|
+
typedef Collection<Parameter>::type Parameters;
|
|
51
28
|
|
|
52
|
-
|
|
53
|
-
begin->type != ListItemBlockBeginType)
|
|
54
|
-
return false;
|
|
55
|
-
|
|
56
|
-
SourceData remainingContent;
|
|
57
|
-
SourceData content = GetListItemSignature(begin, end, remainingContent);
|
|
58
|
-
TrimString(content);
|
|
59
|
-
return RegexMatch(content, snowcrashconst::ParametersRegex);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** Children List Block Classifier, ParameterCollection context. */
|
|
63
|
-
template <>
|
|
64
|
-
FORCEINLINE SectionType ClassifyChildrenListBlock<ParameterCollection>(const BlockIterator& begin,
|
|
65
|
-
const BlockIterator& end){
|
|
66
|
-
// TODO:
|
|
67
|
-
return UndefinedSectionType;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** Block Classifier, ParameterCollection context. */
|
|
71
|
-
template <>
|
|
72
|
-
FORCEINLINE SectionType ClassifyBlock<ParameterCollection>(const BlockIterator& begin,
|
|
73
|
-
const BlockIterator& end,
|
|
74
|
-
const SectionType& context) {
|
|
75
|
-
|
|
76
|
-
if (context == UndefinedSectionType) {
|
|
77
|
-
if (HasParametersSignature(begin, end))
|
|
78
|
-
return ParametersSectionType;
|
|
79
|
-
}
|
|
80
|
-
else if (context == ParametersSectionType) {
|
|
81
|
-
|
|
82
|
-
if (begin->type == ListItemBlockEndType ||
|
|
83
|
-
begin->type == ListBlockEndType)
|
|
84
|
-
return UndefinedSectionType;
|
|
85
|
-
|
|
86
|
-
if (HasParameterDefinitionSignature(begin, end))
|
|
87
|
-
return ParameterDefinitionSectionType;
|
|
88
|
-
|
|
89
|
-
if (begin->type == ListBlockBeginType)
|
|
90
|
-
return ForeignSectionType; // Foreign nested list-item
|
|
91
|
-
|
|
92
|
-
if (begin->type == ListItemBlockBeginType)
|
|
93
|
-
return UndefinedSectionType;
|
|
94
|
-
}
|
|
95
|
-
else if (context == ParameterDefinitionSectionType ||
|
|
96
|
-
context == ForeignSectionType) {
|
|
97
|
-
|
|
98
|
-
if (begin->type == ListItemBlockEndType ||
|
|
99
|
-
begin->type == ListBlockEndType)
|
|
100
|
-
return UndefinedSectionType;
|
|
101
|
-
|
|
102
|
-
if (HasParameterDefinitionSignature(begin, end))
|
|
103
|
-
return ParameterDefinitionSectionType;
|
|
104
|
-
|
|
105
|
-
return ForeignSectionType;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return (context == ParametersSectionType) ? context : UndefinedSectionType;
|
|
109
|
-
}
|
|
29
|
+
typedef Collection<Parameter>::iterator ParameterIterator;
|
|
110
30
|
|
|
111
31
|
/**
|
|
112
|
-
*
|
|
32
|
+
* Parameters section processor
|
|
113
33
|
*/
|
|
114
34
|
template<>
|
|
115
|
-
struct
|
|
116
|
-
|
|
117
|
-
static
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
default:
|
|
141
|
-
result.first.error = UnexpectedBlockError(section, cur, parser.sourceData);
|
|
142
|
-
break;
|
|
35
|
+
struct SectionProcessor<Parameters> : public SectionProcessorBase<Parameters> {
|
|
36
|
+
|
|
37
|
+
static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
|
|
38
|
+
const MarkdownNodes& siblings,
|
|
39
|
+
SectionParserData& pd,
|
|
40
|
+
SectionLayout& layout,
|
|
41
|
+
Report& report,
|
|
42
|
+
Parameters& out) {
|
|
43
|
+
|
|
44
|
+
mdp::ByteBuffer remainingContent;
|
|
45
|
+
|
|
46
|
+
GetFirstLine(node->text, remainingContent);
|
|
47
|
+
|
|
48
|
+
if (!remainingContent.empty()) {
|
|
49
|
+
|
|
50
|
+
// WARN: Extra content in parameters section
|
|
51
|
+
std::stringstream ss;
|
|
52
|
+
ss << "ignoring additional content after 'parameters' keyword,";
|
|
53
|
+
ss << " expected a nested list of parameters, one parameter per list item";
|
|
54
|
+
|
|
55
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
56
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
57
|
+
IgnoringWarning,
|
|
58
|
+
sourceMap));
|
|
143
59
|
}
|
|
144
|
-
|
|
145
|
-
return
|
|
60
|
+
|
|
61
|
+
return ++MarkdownNodeIterator(node);
|
|
146
62
|
}
|
|
147
|
-
|
|
148
|
-
static
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
* \param section Actual section being parsed.
|
|
156
|
-
* \param cur The actual position within Markdown block buffer.
|
|
157
|
-
* \param parser Parser's instance.
|
|
158
|
-
* \param payload An output buffer to write parameters into.
|
|
159
|
-
* \return A block parser section result.
|
|
160
|
-
*/
|
|
161
|
-
static ParseSectionResult HandleParmetersSection(const BlueprintSection& section,
|
|
162
|
-
const BlockIterator& cur,
|
|
163
|
-
BlueprintParserCore& parser,
|
|
164
|
-
ParameterCollection& parameters) {
|
|
165
|
-
|
|
166
|
-
ParseSectionResult result = std::make_pair(Result(), cur);
|
|
167
|
-
BlockIterator sectionCur = cur;
|
|
168
|
-
|
|
169
|
-
// Signature
|
|
170
|
-
if (sectionCur == section.bounds.first) {
|
|
171
|
-
|
|
172
|
-
CheckSignatureAdditionalContent(section,
|
|
173
|
-
sectionCur,
|
|
174
|
-
parser.sourceData,
|
|
175
|
-
"'parameters' keyword",
|
|
176
|
-
snowcrashconst::ExpectedParametersContent,
|
|
177
|
-
result.first);
|
|
178
|
-
result.second = SkipSignatureBlock(sectionCur, section.bounds.second);
|
|
179
|
-
return result;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Unexpected description
|
|
183
|
-
if (sectionCur->type == QuoteBlockBeginType) {
|
|
184
|
-
sectionCur = SkipToClosingBlock(sectionCur, section.bounds.second, QuoteBlockBeginType, QuoteBlockEndType);
|
|
185
|
-
}
|
|
186
|
-
else if (sectionCur->type == ListBlockBeginType) {
|
|
187
|
-
sectionCur = SkipToClosingBlock(sectionCur, section.bounds.second, ListBlockBeginType, ListItemBlockEndType);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (!CheckCursor(section, sectionCur, parser.sourceData, result.first))
|
|
191
|
-
return result;
|
|
192
|
-
|
|
193
|
-
// WARN: on ignoring additional content
|
|
194
|
-
std::stringstream ss;
|
|
195
|
-
ss << "ignoring additional content in the 'parameters' definition, expected " << snowcrashconst::ExpectedParametersContent;
|
|
196
|
-
|
|
197
|
-
SourceCharactersBlock sourceBlock = CharacterMapForBlock(sectionCur, cur, section.bounds, parser.sourceData);
|
|
198
|
-
result.first.warnings.push_back(Warning(ss.str(),
|
|
199
|
-
IgnoringWarning,
|
|
200
|
-
sourceBlock));
|
|
201
|
-
|
|
202
|
-
if (sectionCur != section.bounds.second)
|
|
203
|
-
result.second = ++sectionCur;
|
|
204
|
-
|
|
205
|
-
return result;
|
|
63
|
+
|
|
64
|
+
static MarkdownNodeIterator processDescription(const MarkdownNodeIterator& node,
|
|
65
|
+
const MarkdownNodes& siblings,
|
|
66
|
+
SectionParserData& pd,
|
|
67
|
+
Report& report,
|
|
68
|
+
Parameters& out) {
|
|
69
|
+
|
|
70
|
+
return node;
|
|
206
71
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
72
|
+
|
|
73
|
+
static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
|
|
74
|
+
const MarkdownNodes& siblings,
|
|
75
|
+
SectionParserData& pd,
|
|
76
|
+
Report& report,
|
|
77
|
+
Parameters& out) {
|
|
78
|
+
|
|
79
|
+
if (pd.sectionContext() != ParameterSectionType) {
|
|
80
|
+
return node;
|
|
81
|
+
}
|
|
82
|
+
|
|
213
83
|
Parameter parameter;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
// Check duplicates
|
|
223
|
-
if (!parameters.empty()) {
|
|
224
|
-
ParameterCollection::iterator duplicate = FindParameter(parameters, parameter);
|
|
225
|
-
if (duplicate != parameters.end()) {
|
|
84
|
+
ParameterParser::parse(node, siblings, pd, report, parameter);
|
|
85
|
+
|
|
86
|
+
if (!out.empty()) {
|
|
87
|
+
|
|
88
|
+
ParameterIterator duplicate = findParameter(out, parameter);
|
|
89
|
+
|
|
90
|
+
if (duplicate != out.end()) {
|
|
226
91
|
|
|
227
92
|
// WARN: Parameter already defined
|
|
228
93
|
std::stringstream ss;
|
|
229
94
|
ss << "overshadowing previous parameter '" << parameter.name << "' definition";
|
|
230
95
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
96
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
97
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
98
|
+
RedefinitionWarning,
|
|
99
|
+
sourceMap));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
out.push_back(parameter);
|
|
104
|
+
|
|
105
|
+
return ++MarkdownNodeIterator(node);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static bool isDescriptionNode(const MarkdownNodeIterator& node,
|
|
109
|
+
SectionType sectionType) {
|
|
110
|
+
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static SectionType sectionType(const MarkdownNodeIterator& node) {
|
|
115
|
+
|
|
116
|
+
if (node->type == mdp::ListItemMarkdownNodeType
|
|
117
|
+
&& !node->children().empty()) {
|
|
118
|
+
|
|
119
|
+
mdp::ByteBuffer remaining, subject = node->children().front().text;
|
|
120
|
+
|
|
121
|
+
subject = GetFirstLine(subject, remaining);
|
|
122
|
+
TrimString(subject);
|
|
123
|
+
|
|
124
|
+
if (RegexMatch(subject, ParametersRegex)) {
|
|
125
|
+
return ParametersSectionType;
|
|
239
126
|
}
|
|
240
127
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
128
|
+
|
|
129
|
+
return UndefinedSectionType;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
static SectionType nestedSectionType(const MarkdownNodeIterator& node) {
|
|
133
|
+
|
|
134
|
+
return SectionProcessor<Parameter>::sectionType(node);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static SectionTypes nestedSectionTypes() {
|
|
138
|
+
SectionTypes nested;
|
|
139
|
+
|
|
140
|
+
// Parameter & descendants
|
|
141
|
+
nested.push_back(ParameterSectionType);
|
|
142
|
+
SectionTypes types = SectionProcessor<Parameter>::nestedSectionTypes();
|
|
143
|
+
nested.insert(nested.end(), types.begin(), types.end());
|
|
144
|
+
|
|
145
|
+
return nested;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static void finalize(const MarkdownNodeIterator& node,
|
|
149
|
+
SectionParserData& pd,
|
|
150
|
+
Report& report,
|
|
151
|
+
Parameters& out) {
|
|
152
|
+
|
|
153
|
+
if (out.empty()) {
|
|
154
|
+
|
|
155
|
+
// WARN: No parameters defined
|
|
156
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
157
|
+
report.warnings.push_back(Warning(NoParametersMessage,
|
|
158
|
+
FormattingWarning,
|
|
159
|
+
sourceMap));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Finds a parameter inside a parameters collection */
|
|
164
|
+
static ParameterIterator findParameter(Parameters& parameters,
|
|
165
|
+
const Parameter& parameter) {
|
|
166
|
+
|
|
167
|
+
return std::find_if(parameters.begin(),
|
|
168
|
+
parameters.end(),
|
|
169
|
+
std::bind2nd(MatchName<Parameter>(), parameter));
|
|
245
170
|
}
|
|
246
171
|
};
|
|
247
|
-
|
|
248
|
-
typedef BlockParser<ParameterCollection, SectionParser<ParameterCollection> > ParametersParser;
|
|
249
|
-
}
|
|
250
172
|
|
|
173
|
+
/** Parameters Section parser */
|
|
174
|
+
typedef SectionParser<Parameters, ListSectionAdapter> ParametersParser;
|
|
175
|
+
}
|
|
251
176
|
|
|
252
177
|
#endif
|
|
@@ -9,664 +9,560 @@
|
|
|
9
9
|
#ifndef SNOWCRASH_PARSEPAYLOAD_H
|
|
10
10
|
#define SNOWCRASH_PARSEPAYLOAD_H
|
|
11
11
|
|
|
12
|
-
#include
|
|
13
|
-
#include <sstream>
|
|
14
|
-
#include "BlueprintParserCore.h"
|
|
15
|
-
#include "Blueprint.h"
|
|
12
|
+
#include "SectionParser.h"
|
|
16
13
|
#include "RegexMatch.h"
|
|
17
14
|
#include "AssetParser.h"
|
|
18
|
-
#include "
|
|
19
|
-
#include "
|
|
20
|
-
#include "StringUtility.h"
|
|
21
|
-
#include "BlockUtility.h"
|
|
15
|
+
#include "HeadersParser.h"
|
|
16
|
+
#include "ParametersParser.h"
|
|
22
17
|
|
|
23
18
|
/** Media type in brackets regex */
|
|
24
19
|
#define MEDIA_TYPE "([[:blank:]]*\\(([^\\)]*)\\))"
|
|
25
20
|
|
|
26
|
-
namespace
|
|
27
|
-
|
|
21
|
+
namespace snowcrash {
|
|
22
|
+
|
|
23
|
+
/// Payload signature
|
|
24
|
+
enum PayloadSignature {
|
|
25
|
+
NoPayloadSignature = 0,
|
|
26
|
+
RequestPayloadSignature, /// < Request payload.
|
|
27
|
+
ResponsePayloadSignature, /// < Response payload.
|
|
28
|
+
ModelPayloadSignature, /// < Resource Model payload.
|
|
29
|
+
UndefinedPayloadSignature = -1
|
|
30
|
+
};
|
|
31
|
+
|
|
28
32
|
/** Request matching regex */
|
|
29
33
|
const char* const RequestRegex = "^[[:blank:]]*[Rr]equest" SYMBOL_IDENTIFIER "?" MEDIA_TYPE "?[[:blank:]]*";
|
|
30
|
-
|
|
34
|
+
|
|
31
35
|
/** Response matching regex */
|
|
32
36
|
const char* const ResponseRegex = "^[[:blank:]]*[Rr]esponse([[:blank:][:digit:]]+)?" MEDIA_TYPE "?[[:blank:]]*";
|
|
33
|
-
|
|
34
|
-
/** Object matching regex */
|
|
35
|
-
const char* const ObjectRegex = "^[[:blank:]]*" SYMBOL_IDENTIFIER "[Oo]bject" MEDIA_TYPE "?[[:blank:]]*$";
|
|
36
|
-
|
|
37
|
+
|
|
37
38
|
/** Model matching regex */
|
|
38
|
-
const char* const ModelRegex = "^[[:blank:]]*" SYMBOL_IDENTIFIER "?[Mm]odel" MEDIA_TYPE "?[[:blank:]]
|
|
39
|
-
}
|
|
39
|
+
const char* const ModelRegex = "^[[:blank:]]*(" SYMBOL_IDENTIFIER "[[:blank:]]+)?[Mm]odel" MEDIA_TYPE "?[[:blank:]]*$";
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Payload signature
|
|
45
|
-
*/
|
|
46
|
-
enum PayloadSignature {
|
|
47
|
-
UndefinedPayloadSignature, /// < Undefined payload.
|
|
48
|
-
NoPayloadSignature, /// < Not a payload.
|
|
49
|
-
RequestPayloadSignature, /// < Request payload.
|
|
50
|
-
ResponsePayloadSignature, /// < Response payload.
|
|
51
|
-
ObjectPayloadSignature, /// < Resource object payload.
|
|
52
|
-
ModelPayloadSignature /// < Resource Model payload.
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* \brief Query the payload signature of a given block.
|
|
57
|
-
* \param begin The begin of the block to be queried.
|
|
58
|
-
* \param end The end of the markdown block buffer.
|
|
59
|
-
* \param name A buffer to retrieve payload name into.
|
|
60
|
-
* \param mediaType A buffer to retrieve payload media type into.
|
|
61
|
-
* \return The %PayloadSignature of the given block.
|
|
41
|
+
/**
|
|
42
|
+
* Payload Section Processor
|
|
62
43
|
*/
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
else if (RegexCapture(content, snowcrashconst::ResponseRegex, captureGroups, 5)) {
|
|
88
|
-
name = captureGroups[1];
|
|
89
|
-
TrimString(name);
|
|
90
|
-
mediaType = captureGroups[3];
|
|
91
|
-
return ResponsePayloadSignature;
|
|
92
|
-
}
|
|
93
|
-
else if (RegexCapture(content, snowcrashconst::ObjectRegex, captureGroups, 5)) {
|
|
94
|
-
name = captureGroups[1];
|
|
95
|
-
TrimString(name);
|
|
96
|
-
mediaType = captureGroups[3];
|
|
97
|
-
return ObjectPayloadSignature;
|
|
44
|
+
template<>
|
|
45
|
+
struct SectionProcessor<Payload> : public SectionProcessorBase<Payload> {
|
|
46
|
+
|
|
47
|
+
static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
|
|
48
|
+
const MarkdownNodes& siblings,
|
|
49
|
+
SectionParserData& pd,
|
|
50
|
+
SectionLayout& layout,
|
|
51
|
+
Report& report,
|
|
52
|
+
Payload& out) {
|
|
53
|
+
|
|
54
|
+
mdp::ByteBuffer signature, remainingContent;
|
|
55
|
+
signature = GetFirstLine(node->text, remainingContent);
|
|
56
|
+
|
|
57
|
+
parseSignature(node, pd, signature, report, out);
|
|
58
|
+
|
|
59
|
+
// WARN: missing status code
|
|
60
|
+
if (out.name.empty() &&
|
|
61
|
+
(pd.sectionContext() == ResponseSectionType || pd.sectionContext() == ResponseBodySectionType)) {
|
|
62
|
+
|
|
63
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
64
|
+
report.warnings.push_back(Warning("missing response HTTP status code, assuming 'Response 200'",
|
|
65
|
+
EmptyDefinitionWarning,
|
|
66
|
+
sourceMap));
|
|
67
|
+
out.name = "200";
|
|
98
68
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
69
|
+
|
|
70
|
+
if (!remainingContent.empty()) {
|
|
71
|
+
if (!isAbbreviated(pd.sectionContext())) {
|
|
72
|
+
out.description = remainingContent;
|
|
73
|
+
} else if (!parseSymbolReference(node, pd, remainingContent, report, out)) {
|
|
74
|
+
|
|
75
|
+
// NOTE: NOT THE CORRECT WAY TO DO THIS
|
|
76
|
+
// https://github.com/apiaryio/snowcrash/commit/a7c5868e62df0048a85e2f9aeeb42c3b3e0a2f07#commitcomment-7322085
|
|
77
|
+
pd.sectionsContext.push_back(BodySectionType);
|
|
78
|
+
CodeBlockUtility::signatureContentAsCodeBlock(node, pd, report, out.body);
|
|
79
|
+
pd.sectionsContext.pop_back();
|
|
80
|
+
}
|
|
104
81
|
}
|
|
82
|
+
|
|
83
|
+
return ++MarkdownNodeIterator(node);
|
|
105
84
|
}
|
|
106
85
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
*/
|
|
113
|
-
FORCEINLINE bool HasPayloadSignature(const BlockIterator& begin,
|
|
114
|
-
const BlockIterator& end) {
|
|
115
|
-
Name name;
|
|
116
|
-
SourceData mediaType;
|
|
117
|
-
PayloadSignature signature = GetPayloadSignature(begin, end, name, mediaType);
|
|
118
|
-
return signature != NoPayloadSignature;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Retruns true if given block has any payload signature and
|
|
123
|
-
* is written in the abbreviated form. False otherwise.
|
|
124
|
-
*/
|
|
125
|
-
FORCEINLINE bool HasPayloadAssetSignature(const BlockIterator& begin,
|
|
126
|
-
const BlockIterator& end) {
|
|
127
|
-
if (!HasPayloadSignature(begin, end))
|
|
128
|
-
return false;
|
|
129
|
-
|
|
130
|
-
return !HasNestedListBlock(begin, end);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Classifier of internal list items, payload context.
|
|
135
|
-
*/
|
|
136
|
-
template <>
|
|
137
|
-
FORCEINLINE SectionType ClassifyInternaListBlock<Payload>(const BlockIterator& begin,
|
|
138
|
-
const BlockIterator& end) {
|
|
139
|
-
|
|
140
|
-
AssetSignature asset = GetAssetSignature(begin, end);
|
|
141
|
-
if (asset == BodyAssetSignature)
|
|
142
|
-
return BodySectionType;
|
|
143
|
-
else if (asset == SchemaAssetSignature)
|
|
144
|
-
return SchemaSectionType;
|
|
145
|
-
|
|
146
|
-
if (HasHeaderSignature(begin, end))
|
|
147
|
-
return HeadersSectionType;
|
|
148
|
-
|
|
149
|
-
return UndefinedSectionType;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/** Children blocks classifier */
|
|
153
|
-
template <>
|
|
154
|
-
FORCEINLINE SectionType ClassifyChildrenListBlock<Payload>(const BlockIterator& begin,
|
|
155
|
-
const BlockIterator& end) {
|
|
156
|
-
|
|
157
|
-
SectionType type = ClassifyInternaListBlock<Payload>(begin, end);
|
|
158
|
-
if (type != UndefinedSectionType)
|
|
159
|
-
return type;
|
|
160
|
-
|
|
161
|
-
return UndefinedSectionType;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Block Classifier, payload context.
|
|
166
|
-
*/
|
|
167
|
-
template <>
|
|
168
|
-
FORCEINLINE SectionType ClassifyBlock<Payload>(const BlockIterator& begin,
|
|
169
|
-
const BlockIterator& end,
|
|
170
|
-
const SectionType& context) {
|
|
171
|
-
|
|
172
|
-
if (context == UndefinedSectionType) {
|
|
173
|
-
|
|
174
|
-
Name name;
|
|
175
|
-
SourceData mediaType;
|
|
176
|
-
PayloadSignature payload = GetPayloadSignature(begin, end, name, mediaType);
|
|
177
|
-
if (payload == RequestPayloadSignature) {
|
|
86
|
+
static MarkdownNodeIterator processContent(const MarkdownNodeIterator& node,
|
|
87
|
+
const MarkdownNodes& siblings,
|
|
88
|
+
SectionParserData& pd,
|
|
89
|
+
Report& report,
|
|
90
|
+
Payload& out) {
|
|
178
91
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
92
|
+
mdp::ByteBuffer content;
|
|
93
|
+
|
|
94
|
+
if (!out.symbol.empty()) {
|
|
95
|
+
//WARN: ignoring extraneous content after symbol reference
|
|
96
|
+
std::stringstream ss;
|
|
97
|
+
|
|
98
|
+
ss << "ignoring extraneous content after symbol reference";
|
|
99
|
+
ss << ", expected symbol reference only e.g. '[" << out.symbol << "][]'";
|
|
100
|
+
|
|
101
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
102
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
103
|
+
IgnoringWarning,
|
|
104
|
+
sourceMap));
|
|
105
|
+
} else {
|
|
106
|
+
|
|
107
|
+
if (!out.body.empty() ||
|
|
108
|
+
node->type != mdp::ParagraphMarkdownNodeType ||
|
|
109
|
+
!parseSymbolReference(node, pd, node->text, report, out)) {
|
|
110
|
+
|
|
111
|
+
// NOTE: NOT THE CORRECT WAY TO DO THIS
|
|
112
|
+
// https://github.com/apiaryio/snowcrash/commit/a7c5868e62df0048a85e2f9aeeb42c3b3e0a2f07#commitcomment-7322085
|
|
113
|
+
pd.sectionsContext.push_back(BodySectionType);
|
|
114
|
+
CodeBlockUtility::contentAsCodeBlock(node, pd, report, content);
|
|
115
|
+
pd.sectionsContext.pop_back();
|
|
116
|
+
|
|
117
|
+
out.body += content;
|
|
118
|
+
}
|
|
192
119
|
}
|
|
193
120
|
|
|
121
|
+
return ++MarkdownNodeIterator(node);
|
|
194
122
|
}
|
|
195
|
-
else if (context == RequestSectionType ||
|
|
196
|
-
context == ResponseSectionType ||
|
|
197
|
-
context == ObjectSectionType ||
|
|
198
|
-
context == ModelSectionType) {
|
|
199
|
-
|
|
200
|
-
// SectionType closure
|
|
201
|
-
if (begin->type == ListItemBlockEndType ||
|
|
202
|
-
begin->type == ListBlockEndType)
|
|
203
|
-
return UndefinedSectionType;
|
|
204
|
-
|
|
205
|
-
SectionType listSection = ClassifyInternaListBlock<Payload>(begin, end);
|
|
206
|
-
if (listSection != UndefinedSectionType)
|
|
207
|
-
return listSection;
|
|
208
|
-
|
|
209
|
-
// Adjacent list item
|
|
210
|
-
if (begin->type == ListItemBlockBeginType)
|
|
211
|
-
return UndefinedSectionType;
|
|
212
|
-
}
|
|
213
|
-
else if (context == HeadersSectionType ||
|
|
214
|
-
context == BodySectionType ||
|
|
215
|
-
context == SchemaSectionType ||
|
|
216
|
-
context == ForeignSectionType) {
|
|
217
|
-
|
|
218
|
-
// SectionType closure
|
|
219
|
-
if (begin->type == ListItemBlockEndType ||
|
|
220
|
-
begin->type == ListBlockEndType)
|
|
221
|
-
return UndefinedSectionType;
|
|
222
|
-
|
|
223
|
-
SectionType listSection = ClassifyInternaListBlock<Payload>(begin, end);
|
|
224
|
-
if (listSection != UndefinedSectionType)
|
|
225
|
-
return listSection;
|
|
226
|
-
|
|
227
|
-
if (HasPayloadAssetSignature(begin, end))
|
|
228
|
-
return UndefinedSectionType;
|
|
229
|
-
|
|
230
|
-
return ForeignSectionType;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return (context == RequestSectionType ||
|
|
234
|
-
context == ResponseSectionType ||
|
|
235
|
-
context == ObjectSectionType ||
|
|
236
|
-
context == ModelSectionType) ? context : UndefinedSectionType;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Payload section parser.
|
|
241
|
-
*/
|
|
242
|
-
template<>
|
|
243
|
-
struct SectionParser<Payload> {
|
|
244
|
-
|
|
245
|
-
static ParseSectionResult ParseSection(const BlueprintSection& section,
|
|
246
|
-
const BlockIterator& cur,
|
|
247
|
-
BlueprintParserCore& parser,
|
|
248
|
-
Payload& payload) {
|
|
249
|
-
|
|
250
|
-
ParseSectionResult result = std::make_pair(Result(), cur);
|
|
251
123
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
case RequestBodySectionType:
|
|
261
|
-
case ResponseBodySectionType:
|
|
262
|
-
case ObjectBodySectionType:
|
|
263
|
-
case ModelBodySectionType:
|
|
264
|
-
result = HandlePayloadAsset(section, cur, parser, payload);
|
|
265
|
-
break;
|
|
266
|
-
|
|
124
|
+
static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
|
|
125
|
+
const MarkdownNodes& siblings,
|
|
126
|
+
SectionParserData& pd,
|
|
127
|
+
Report& report,
|
|
128
|
+
Payload& out) {
|
|
129
|
+
|
|
130
|
+
switch (pd.sectionContext()) {
|
|
267
131
|
case HeadersSectionType:
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
132
|
+
return HeadersParser::parse(node, siblings, pd, report, out.headers);
|
|
133
|
+
|
|
271
134
|
case BodySectionType:
|
|
135
|
+
if (!out.body.empty()) {
|
|
136
|
+
// WARN: Multiple body section
|
|
137
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
138
|
+
report.warnings.push_back(Warning("ignoring additional 'body' content, it is already defined",
|
|
139
|
+
RedefinitionWarning,
|
|
140
|
+
sourceMap));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return AssetParser::parse(node, siblings, pd, report, out.body);
|
|
144
|
+
|
|
272
145
|
case SchemaSectionType:
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
146
|
+
if (!out.schema.empty()) {
|
|
147
|
+
// WARN: Multiple schema section
|
|
148
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
149
|
+
report.warnings.push_back(Warning("ignoring additional 'schema' content, it is already defined",
|
|
150
|
+
RedefinitionWarning,
|
|
151
|
+
sourceMap));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return AssetParser::parse(node, siblings, pd, report, out.schema);
|
|
155
|
+
|
|
284
156
|
default:
|
|
285
|
-
result.first.error = UnexpectedBlockError(section, cur, parser.sourceData);
|
|
286
157
|
break;
|
|
287
158
|
}
|
|
288
|
-
|
|
289
|
-
return
|
|
159
|
+
|
|
160
|
+
return node;
|
|
290
161
|
}
|
|
291
|
-
|
|
292
|
-
static void Finalize(const SectionBounds& bounds,
|
|
293
|
-
BlueprintParserCore& parser,
|
|
294
|
-
Payload& payload,
|
|
295
|
-
Result& result) {}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* \brief Parse Payload's description blocks.
|
|
299
|
-
* \param section The current section's signature.
|
|
300
|
-
* \param cur The actual position within Markdown block buffer.
|
|
301
|
-
* \param bound Boundaries of Markdown block buffer.
|
|
302
|
-
* \param parser A parser's instance.
|
|
303
|
-
* \param payload An output buffer to write overview description into.
|
|
304
|
-
* \return A block parser section result.
|
|
305
|
-
*/
|
|
306
|
-
static ParseSectionResult HandleDescriptionSectionBlock(const BlueprintSection& section,
|
|
307
|
-
const BlockIterator& cur,
|
|
308
|
-
BlueprintParserCore& parser,
|
|
309
|
-
Payload& payload) {
|
|
310
|
-
|
|
311
|
-
ParseSectionResult result = std::make_pair(Result(), cur);
|
|
312
|
-
BlockIterator sectionCur = cur;
|
|
313
162
|
|
|
314
|
-
|
|
315
|
-
|
|
163
|
+
static MarkdownNodeIterator processUnexpectedNode(const MarkdownNodeIterator& node,
|
|
164
|
+
const MarkdownNodes& siblings,
|
|
165
|
+
SectionParserData& pd,
|
|
166
|
+
SectionType& sectionType,
|
|
167
|
+
Report& report,
|
|
168
|
+
Payload& out) {
|
|
316
169
|
|
|
317
|
-
|
|
318
|
-
|
|
170
|
+
if ((node->type == mdp::ParagraphMarkdownNodeType ||
|
|
171
|
+
node->type == mdp::CodeMarkdownNodeType) &&
|
|
172
|
+
sectionType == BodySectionType) {
|
|
319
173
|
|
|
320
|
-
|
|
321
|
-
return
|
|
322
|
-
|
|
174
|
+
CodeBlockUtility::addDanglingAsset(node, pd, sectionType, report, out.body);
|
|
175
|
+
return ++MarkdownNodeIterator(node);
|
|
323
176
|
}
|
|
177
|
+
|
|
178
|
+
return SectionProcessorBase<Payload>::processUnexpectedNode(node, siblings, pd, sectionType, report, out);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
static bool isDescriptionNode(const MarkdownNodeIterator& node,
|
|
182
|
+
SectionType sectionType) {
|
|
324
183
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
sectionCur,
|
|
328
|
-
parser.sourceData,
|
|
329
|
-
payload);
|
|
330
|
-
return result;
|
|
184
|
+
if (!isAbbreviated(sectionType) &&
|
|
185
|
+
SectionProcessorBase<Payload>::isDescriptionNode(node, sectionType)) {
|
|
331
186
|
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return false;
|
|
332
191
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
* \return A block parser section result.
|
|
342
|
-
*/
|
|
343
|
-
static ParseSectionResult HandleAsset(const BlueprintSection& section,
|
|
344
|
-
const BlockIterator& cur,
|
|
345
|
-
BlueprintParserCore& parser,
|
|
346
|
-
Payload& payload) {
|
|
347
|
-
Asset asset;
|
|
348
|
-
ParseSectionResult result = AssetParser::Parse(cur, section.bounds.second, section, parser, asset);
|
|
349
|
-
if (result.first.error.code != Error::OK)
|
|
350
|
-
return result;
|
|
351
|
-
|
|
352
|
-
if (!SetAsset(section.type, asset, payload)) {
|
|
353
|
-
// WARN: asset already set
|
|
354
|
-
std::stringstream ss;
|
|
355
|
-
ss << "ignoring additional " << SectionName(section.type) << " content, content is already defined";
|
|
356
|
-
|
|
357
|
-
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
|
358
|
-
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
|
|
359
|
-
result.first.warnings.push_back(Warning(ss.str(),
|
|
360
|
-
RedefinitionWarning,
|
|
361
|
-
sourceBlock));
|
|
192
|
+
|
|
193
|
+
static bool isContentNode(const MarkdownNodeIterator& node,
|
|
194
|
+
SectionType sectionType) {
|
|
195
|
+
|
|
196
|
+
if (isAbbreviated(sectionType) &&
|
|
197
|
+
(SectionKeywordSignature(node) == UndefinedSectionType)) {
|
|
198
|
+
|
|
199
|
+
return true;
|
|
362
200
|
}
|
|
363
|
-
|
|
364
|
-
return
|
|
201
|
+
|
|
202
|
+
return false;
|
|
365
203
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const BlockIterator& cur,
|
|
378
|
-
BlueprintParserCore& parser,
|
|
379
|
-
Payload& payload) {
|
|
380
|
-
// Try to parse as a Symbol reference
|
|
381
|
-
SymbolName symbol;
|
|
382
|
-
SourceDataBlock symbolSourceMap;
|
|
383
|
-
ParseSectionResult result = ParseSymbolReference(cur, section.bounds, parser, symbol, symbolSourceMap);
|
|
384
|
-
if (result.first.error.code != Error::OK)
|
|
385
|
-
return result;
|
|
386
|
-
|
|
387
|
-
if (result.second != cur) {
|
|
388
|
-
// Process a symbol reference
|
|
389
|
-
ResourceModelSymbolTable::const_iterator symbolEntry = parser.symbolTable.resourceModels.find(symbol);
|
|
390
|
-
if (symbolEntry == parser.symbolTable.resourceModels.end()) {
|
|
391
|
-
|
|
392
|
-
// ERR: Undefined symbol
|
|
393
|
-
std::stringstream ss;
|
|
394
|
-
ss << "undefined symbol '" << symbol << "'";
|
|
395
|
-
result.first.error = Error(ss.str(),
|
|
396
|
-
SymbolError,
|
|
397
|
-
MapSourceDataBlock(symbolSourceMap, parser.sourceData));
|
|
398
|
-
return result;
|
|
204
|
+
|
|
205
|
+
static SectionType sectionType(const MarkdownNodeIterator& node) {
|
|
206
|
+
|
|
207
|
+
if (node->type == mdp::ListItemMarkdownNodeType
|
|
208
|
+
&& !node->children().empty()) {
|
|
209
|
+
|
|
210
|
+
SectionType nestedType = UndefinedSectionType;
|
|
211
|
+
PayloadSignature signature = payloadSignature(node);
|
|
212
|
+
|
|
213
|
+
if (signature == NoPayloadSignature) {
|
|
214
|
+
return UndefinedSectionType;
|
|
399
215
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
216
|
+
|
|
217
|
+
for (MarkdownNodeIterator child = node->children().begin();
|
|
218
|
+
child != node->children().end();
|
|
219
|
+
++child) {
|
|
220
|
+
|
|
221
|
+
nestedType = nestedSectionType(child);
|
|
222
|
+
|
|
223
|
+
if (nestedType != UndefinedSectionType) {
|
|
224
|
+
return getSectionType(signature, nestedType);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Return abbreviated signature
|
|
229
|
+
return getSectionType(signature, nestedType);
|
|
407
230
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
ProcessSignature(section, cur, parser.sourceData, result.first, payload);
|
|
411
|
-
|
|
412
|
-
return result;
|
|
231
|
+
|
|
232
|
+
return UndefinedSectionType;
|
|
413
233
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
static ParseSectionResult ParseSymbolReference(const BlockIterator& cur,
|
|
425
|
-
const SectionBounds& bounds,
|
|
426
|
-
BlueprintParserCore& parser,
|
|
427
|
-
SymbolName& symbolName,
|
|
428
|
-
SourceDataBlock& symbolSourceMap) {
|
|
429
|
-
|
|
430
|
-
ParseSectionResult result = std::make_pair(Result(), cur);
|
|
431
|
-
BlockIterator sectionCur = cur;
|
|
432
|
-
SourceData content;
|
|
433
|
-
SourceData signature = GetListItemSignature(sectionCur, bounds.second, content);
|
|
434
|
-
if (!content.empty()) {
|
|
435
|
-
sectionCur = ListItemNameBlock(sectionCur, bounds.second);
|
|
234
|
+
|
|
235
|
+
static SectionType nestedSectionType(const MarkdownNodeIterator& node) {
|
|
236
|
+
|
|
237
|
+
SectionType nestedType = UndefinedSectionType;
|
|
238
|
+
|
|
239
|
+
// Check if headers section
|
|
240
|
+
nestedType = SectionProcessor<Headers>::sectionType(node);
|
|
241
|
+
|
|
242
|
+
if (nestedType != UndefinedSectionType) {
|
|
243
|
+
return nestedType;
|
|
436
244
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
// Try the next block
|
|
444
|
-
if (++sectionCur == bounds.second ||
|
|
445
|
-
sectionCur->type != ParagraphBlockType)
|
|
446
|
-
return result;
|
|
447
|
-
|
|
448
|
-
content = sectionCur->content;
|
|
245
|
+
|
|
246
|
+
// Check if asset section
|
|
247
|
+
nestedType = SectionProcessor<Asset>::sectionType(node);
|
|
248
|
+
|
|
249
|
+
if (nestedType != UndefinedSectionType) {
|
|
250
|
+
return nestedType;
|
|
449
251
|
}
|
|
450
|
-
|
|
451
|
-
TrimString(content);
|
|
452
|
-
SymbolName symbol;
|
|
453
|
-
if (!GetSymbolReference(content, symbol))
|
|
454
|
-
return result;
|
|
455
|
-
|
|
456
|
-
symbolName = symbol;
|
|
457
|
-
symbolSourceMap = sectionCur->sourceMap;
|
|
458
|
-
|
|
459
|
-
// Close list item
|
|
460
|
-
BlockIterator endCur = cur;
|
|
461
|
-
if (endCur->type == ListBlockBeginType)
|
|
462
|
-
++endCur;
|
|
463
|
-
endCur = SkipToClosingBlock(endCur, bounds.second, ListItemBlockBeginType, ListItemBlockEndType);
|
|
464
|
-
|
|
465
|
-
// Check extraneous content
|
|
466
|
-
if (sectionCur != endCur) {
|
|
467
|
-
++sectionCur;
|
|
468
|
-
for (; sectionCur != endCur; ++sectionCur) {
|
|
469
252
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
253
|
+
return UndefinedSectionType;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
static SectionTypes nestedSectionTypes() {
|
|
257
|
+
SectionTypes nested, types;
|
|
258
|
+
|
|
259
|
+
nested.push_back(HeadersSectionType);
|
|
260
|
+
nested.push_back(BodySectionType);
|
|
261
|
+
nested.push_back(SchemaSectionType);
|
|
262
|
+
|
|
263
|
+
// Parameters & descendants
|
|
264
|
+
nested.push_back(ParametersSectionType);
|
|
265
|
+
types = SectionProcessor<Parameters>::nestedSectionTypes();
|
|
266
|
+
nested.insert(nested.end(), types.begin(), types.end());
|
|
267
|
+
|
|
268
|
+
return nested;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
static void finalize(const MarkdownNodeIterator& node,
|
|
272
|
+
SectionParserData& pd,
|
|
273
|
+
Report& report,
|
|
274
|
+
Payload& out) {
|
|
275
|
+
|
|
276
|
+
bool warnEmptyBody = false;
|
|
277
|
+
|
|
278
|
+
mdp::ByteBuffer contentLength;
|
|
279
|
+
mdp::ByteBuffer transferEncoding;
|
|
280
|
+
|
|
281
|
+
SectionType sectionType = pd.sectionContext();
|
|
282
|
+
|
|
283
|
+
for (Collection<Header>::const_iterator it = out.headers.begin();
|
|
284
|
+
it != out.headers.end();
|
|
285
|
+
++it) {
|
|
286
|
+
|
|
287
|
+
if (it->first == HTTPHeaderName::ContentLength) {
|
|
288
|
+
contentLength = it->second;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (it->first == HTTPHeaderName::TransferEncoding) {
|
|
292
|
+
transferEncoding = it->second;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if ((sectionType == RequestSectionType || sectionType == RequestBodySectionType) && out.body.empty()) {
|
|
297
|
+
|
|
298
|
+
// Warn when content-length or transfer-encoding is specified or both headers and body are empty
|
|
299
|
+
if (out.headers.empty()) {
|
|
300
|
+
warnEmptyBody = true;
|
|
301
|
+
} else {
|
|
302
|
+
warnEmptyBody = !contentLength.empty() || !transferEncoding.empty();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (warnEmptyBody) {
|
|
306
|
+
// WARN: empty body
|
|
477
307
|
std::stringstream ss;
|
|
478
|
-
ss << "
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
308
|
+
ss << "empty " << SectionName(sectionType) << " " << SectionName(BodySectionType);
|
|
309
|
+
|
|
310
|
+
if (!contentLength.empty()) {
|
|
311
|
+
ss << ", expected " << SectionName(BodySectionType) << " for '" << contentLength << "' Content-Length";
|
|
312
|
+
} else if (!transferEncoding.empty()) {
|
|
313
|
+
ss << ", expected " << SectionName(BodySectionType) << " for '" << transferEncoding << "' Transfer-Encoding";
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
317
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
318
|
+
EmptyDefinitionWarning,
|
|
319
|
+
sourceMap));
|
|
320
|
+
}
|
|
321
|
+
} else if ((sectionType == ResponseSectionType || sectionType == ResponseBodySectionType)) {
|
|
322
|
+
|
|
323
|
+
HTTPStatusCode code = 200;
|
|
324
|
+
|
|
325
|
+
if (!out.name.empty()) {
|
|
326
|
+
std::stringstream(out.name) >> code;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
StatusCodeTraits statusCodeTraits = GetStatusCodeTrait(code);
|
|
330
|
+
|
|
331
|
+
if (!statusCodeTraits.allowBody && !out.body.empty()) {
|
|
332
|
+
// WARN: not empty body
|
|
333
|
+
std::stringstream ss;
|
|
334
|
+
ss << "the " << code << " response MUST NOT include a " << SectionName(BodySectionType);
|
|
335
|
+
|
|
336
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
337
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
338
|
+
EmptyDefinitionWarning,
|
|
339
|
+
sourceMap));
|
|
485
340
|
}
|
|
486
341
|
}
|
|
487
|
-
|
|
488
|
-
endCur = CloseList(sectionCur, bounds.second);
|
|
489
|
-
result.second = endCur;
|
|
490
|
-
|
|
491
|
-
return result;
|
|
492
342
|
}
|
|
493
|
-
|
|
494
|
-
/**
|
|
495
|
-
* Retrieve and process payload signature.
|
|
496
|
-
*/
|
|
497
|
-
static void ProcessSignature(const BlueprintSection& section,
|
|
498
|
-
const BlockIterator& cur,
|
|
499
|
-
const SourceData& sourceData,
|
|
500
|
-
Result& result,
|
|
501
|
-
Payload& payload) {
|
|
502
|
-
|
|
503
|
-
SourceData remainingContent;
|
|
504
|
-
SourceData signature = GetListItemSignature(cur, section.bounds.second, remainingContent);
|
|
505
343
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
GetPayloadSignature(cur, section.bounds.second, payload.name, mediaType);
|
|
509
|
-
|
|
510
|
-
// Check signature
|
|
511
|
-
if (!CheckSignature(section, cur, signature, sourceData, result)) {
|
|
512
|
-
// Clear all readouts
|
|
513
|
-
payload.name.clear();
|
|
514
|
-
mediaType.clear();
|
|
515
|
-
remainingContent.clear();
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// Add any extra lines to description unless abbreviated body
|
|
519
|
-
if (!remainingContent.empty() &&
|
|
520
|
-
section.type != RequestBodySectionType &&
|
|
521
|
-
section.type != ResponseBodySectionType) {
|
|
522
|
-
payload.description += remainingContent;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
// WARN: missing status code
|
|
526
|
-
if (payload.name.empty() &&
|
|
527
|
-
(section.type == ResponseSectionType || section.type == ResponseBodySectionType)) {
|
|
528
|
-
|
|
529
|
-
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
|
530
|
-
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, sourceData);
|
|
531
|
-
result.warnings.push_back(Warning("missing response HTTP status code, assuming 'Response 200'",
|
|
532
|
-
EmptyDefinitionWarning,
|
|
533
|
-
sourceBlock));
|
|
534
|
-
payload.name = "200";
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
// WARN: Object deprecation
|
|
539
|
-
if (section.type == ObjectSectionType || section.type == ObjectBodySectionType) {
|
|
344
|
+
/** Resolve payload signature */
|
|
345
|
+
static PayloadSignature payloadSignature(const MarkdownNodeIterator& node) {
|
|
540
346
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
if (
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
347
|
+
mdp::ByteBuffer subject = node->children().front().text;
|
|
348
|
+
mdp::ByteBuffer signature;
|
|
349
|
+
mdp::ByteBuffer remainingContent;
|
|
350
|
+
|
|
351
|
+
signature = GetFirstLine(subject, remainingContent);
|
|
352
|
+
TrimString(signature);
|
|
353
|
+
|
|
354
|
+
if (RegexMatch(signature, RequestRegex))
|
|
355
|
+
return RequestPayloadSignature;
|
|
356
|
+
|
|
357
|
+
if (RegexMatch(signature, ResponseRegex))
|
|
358
|
+
return ResponsePayloadSignature;
|
|
359
|
+
|
|
360
|
+
if (RegexMatch(signature, ModelRegex))
|
|
361
|
+
return ModelPayloadSignature;
|
|
362
|
+
|
|
363
|
+
return NoPayloadSignature;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/** Get SectionType from PayloadSignature and nestedSectionType */
|
|
367
|
+
static SectionType getSectionType(PayloadSignature signature,
|
|
368
|
+
SectionType nestedType) {
|
|
369
|
+
|
|
370
|
+
switch (signature) {
|
|
371
|
+
case RequestPayloadSignature:
|
|
372
|
+
return (nestedType != UndefinedSectionType) ? RequestSectionType : RequestBodySectionType;
|
|
373
|
+
|
|
374
|
+
case ResponsePayloadSignature:
|
|
375
|
+
return (nestedType != UndefinedSectionType) ? ResponseSectionType : ResponseBodySectionType;
|
|
376
|
+
|
|
377
|
+
case ModelPayloadSignature:
|
|
378
|
+
return (nestedType != UndefinedSectionType) ? ModelSectionType : ModelBodySectionType;
|
|
379
|
+
|
|
380
|
+
default:
|
|
381
|
+
break;
|
|
555
382
|
}
|
|
383
|
+
|
|
384
|
+
return UndefinedSectionType;
|
|
556
385
|
}
|
|
557
|
-
|
|
558
|
-
/**
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
386
|
+
|
|
387
|
+
/** True if abbreviated section type */
|
|
388
|
+
static bool isAbbreviated(SectionType sectionType) {
|
|
389
|
+
|
|
390
|
+
return (sectionType == RequestBodySectionType ||
|
|
391
|
+
sectionType == ResponseBodySectionType ||
|
|
392
|
+
sectionType == ModelBodySectionType);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/** Given the signature, parse it */
|
|
396
|
+
static bool parseSignature(const MarkdownNodeIterator& node,
|
|
397
|
+
SectionParserData& pd,
|
|
398
|
+
const mdp::ByteBuffer& signature,
|
|
399
|
+
Report& report,
|
|
400
|
+
Payload& out) {
|
|
401
|
+
|
|
402
|
+
const char* regex;
|
|
403
|
+
mdp::ByteBuffer mediaType;
|
|
404
|
+
CaptureGroups captureGroups;
|
|
405
|
+
|
|
406
|
+
switch (pd.sectionContext()) {
|
|
571
407
|
case RequestSectionType:
|
|
572
408
|
case RequestBodySectionType:
|
|
573
|
-
regex =
|
|
409
|
+
regex = RequestRegex;
|
|
574
410
|
break;
|
|
575
|
-
|
|
576
|
-
case ResponseBodySectionType:
|
|
411
|
+
|
|
577
412
|
case ResponseSectionType:
|
|
578
|
-
|
|
413
|
+
case ResponseBodySectionType:
|
|
414
|
+
regex = ResponseRegex;
|
|
579
415
|
break;
|
|
580
|
-
|
|
416
|
+
|
|
581
417
|
case ModelSectionType:
|
|
582
418
|
case ModelBodySectionType:
|
|
583
|
-
regex =
|
|
419
|
+
regex = ModelRegex;
|
|
584
420
|
break;
|
|
585
|
-
|
|
421
|
+
|
|
586
422
|
default:
|
|
587
423
|
return true;
|
|
588
424
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
if (RegexCapture(signature, regex, captureGroups) &&
|
|
425
|
+
|
|
426
|
+
if (RegexCapture(signature, regex, captureGroups, 5) &&
|
|
592
427
|
!captureGroups.empty()) {
|
|
593
428
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
429
|
+
mdp::ByteBuffer target = signature;
|
|
430
|
+
mdp::ByteBuffer::size_type pos = target.find(captureGroups[0]);
|
|
431
|
+
|
|
432
|
+
if (pos != mdp::ByteBuffer::npos) {
|
|
433
|
+
target.replace(pos, captureGroups[0].length(), mdp::ByteBuffer());
|
|
434
|
+
}
|
|
598
435
|
|
|
599
436
|
TrimString(target);
|
|
437
|
+
|
|
600
438
|
if (!target.empty()) {
|
|
601
439
|
// WARN: unable to parse payload signature
|
|
602
440
|
std::stringstream ss;
|
|
603
|
-
ss << "unable to parse " << SectionName(
|
|
604
|
-
|
|
605
|
-
switch (
|
|
606
|
-
|
|
441
|
+
ss << "unable to parse " << SectionName(pd.sectionContext()) << " signature, expected ";
|
|
442
|
+
|
|
443
|
+
switch (pd.sectionContext()) {
|
|
607
444
|
case RequestSectionType:
|
|
608
445
|
case RequestBodySectionType:
|
|
609
446
|
ss << "'request [<identifier>] [(<media type>)]'";
|
|
610
447
|
break;
|
|
611
|
-
|
|
448
|
+
|
|
612
449
|
case ResponseBodySectionType:
|
|
613
450
|
case ResponseSectionType:
|
|
614
451
|
ss << "'response [<HTTP status code>] [(<media type>)]'";
|
|
615
452
|
break;
|
|
616
|
-
|
|
453
|
+
|
|
617
454
|
case ModelSectionType:
|
|
618
455
|
case ModelBodySectionType:
|
|
619
456
|
ss << "'model [(<media type>)]'";
|
|
620
457
|
break;
|
|
621
|
-
|
|
458
|
+
|
|
622
459
|
default:
|
|
623
460
|
return false;
|
|
624
461
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
result.warnings.push_back(Warning(ss.str(),
|
|
462
|
+
|
|
463
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
464
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
629
465
|
FormattingWarning,
|
|
630
|
-
|
|
631
|
-
|
|
466
|
+
sourceMap));
|
|
467
|
+
|
|
632
468
|
return false;
|
|
633
469
|
}
|
|
470
|
+
|
|
471
|
+
if (pd.sectionContext() == ModelSectionType ||
|
|
472
|
+
pd.sectionContext() == ModelBodySectionType) {
|
|
473
|
+
|
|
474
|
+
out.name = captureGroups[2];
|
|
475
|
+
mediaType = captureGroups[4];
|
|
476
|
+
} else {
|
|
477
|
+
out.name = captureGroups[1];
|
|
478
|
+
mediaType = captureGroups[3];
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
TrimString(out.name);
|
|
482
|
+
TrimString(mediaType);
|
|
483
|
+
|
|
484
|
+
if (!mediaType.empty()) {
|
|
485
|
+
Header header = std::make_pair(HTTPHeaderName::ContentType, mediaType);
|
|
486
|
+
out.headers.push_back(header);
|
|
487
|
+
}
|
|
634
488
|
}
|
|
635
|
-
|
|
489
|
+
|
|
636
490
|
return true;
|
|
637
491
|
}
|
|
638
|
-
|
|
639
|
-
/**
|
|
640
|
-
* \brief Set payload's asset.
|
|
641
|
-
* \return True on success, false when an asset is already set.
|
|
642
|
-
*/
|
|
643
|
-
static bool SetAsset(const SectionType& sectionType, const Asset& asset, Payload& payload) {
|
|
644
|
-
|
|
645
|
-
if (sectionType == BodySectionType ||
|
|
646
|
-
sectionType == RequestBodySectionType ||
|
|
647
|
-
sectionType == ResponseBodySectionType ||
|
|
648
|
-
sectionType == ModelBodySectionType ||
|
|
649
|
-
sectionType == ObjectBodySectionType ||
|
|
650
|
-
sectionType == DanglingBodySectionType) {
|
|
651
|
-
if (!payload.body.empty())
|
|
652
|
-
return false;
|
|
653
492
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
493
|
+
static bool parseSymbolReference(const MarkdownNodeIterator& node,
|
|
494
|
+
SectionParserData& pd,
|
|
495
|
+
mdp::ByteBuffer& source,
|
|
496
|
+
Report& report,
|
|
497
|
+
Payload& out) {
|
|
498
|
+
|
|
499
|
+
SymbolName symbol;
|
|
500
|
+
ResourceModel model;
|
|
501
|
+
|
|
502
|
+
TrimString(source);
|
|
503
|
+
|
|
504
|
+
if (GetSymbolReference(source, symbol)) {
|
|
505
|
+
out.symbol = symbol;
|
|
506
|
+
|
|
507
|
+
// If symbol doesn't exist
|
|
508
|
+
if (pd.symbolTable.resourceModels.find(symbol) == pd.symbolTable.resourceModels.end()) {
|
|
509
|
+
|
|
510
|
+
// ERR: Undefined symbol
|
|
511
|
+
std::stringstream ss;
|
|
512
|
+
ss << "Undefined symbol " << symbol;
|
|
513
|
+
|
|
514
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
515
|
+
report.error = Error(ss.str(), SymbolError, sourceMap);
|
|
516
|
+
|
|
517
|
+
return true;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
model = pd.symbolTable.resourceModels.at(symbol);
|
|
660
521
|
|
|
661
|
-
|
|
522
|
+
out.description = model.description;
|
|
523
|
+
out.parameters = model.parameters;
|
|
524
|
+
|
|
525
|
+
Collection<Header>::const_iterator modelContentType = std::find_if(model.headers.begin(),
|
|
526
|
+
model.headers.end(),
|
|
527
|
+
std::bind2nd(MatchFirstWith<Header, std::string>(),
|
|
528
|
+
HTTPHeaderName::ContentType));
|
|
529
|
+
|
|
530
|
+
bool isPayloadContentType = !out.headers.empty();
|
|
531
|
+
bool isModelContentType = modelContentType != model.headers.end();
|
|
532
|
+
|
|
533
|
+
if (isPayloadContentType && isModelContentType) {
|
|
534
|
+
|
|
535
|
+
// WARN: Ignoring payload content-type, when referencing a model with headers
|
|
536
|
+
std::stringstream ss;
|
|
537
|
+
|
|
538
|
+
ss << "ignoring additional " << SectionName(pd.sectionContext()) << " header(s), ";
|
|
539
|
+
ss << "specify this header(s) in the referenced model definition instead";
|
|
540
|
+
|
|
541
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
542
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
543
|
+
IgnoringWarning,
|
|
544
|
+
sourceMap));
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if (isPayloadContentType && !isModelContentType) {
|
|
548
|
+
out.headers.insert(out.headers.end(), model.headers.begin(), model.headers.end());
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
out.headers = model.headers;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
out.body = model.body;
|
|
555
|
+
out.schema = model.schema;
|
|
556
|
+
|
|
557
|
+
return true;
|
|
662
558
|
}
|
|
663
|
-
|
|
664
|
-
return
|
|
559
|
+
|
|
560
|
+
return false;
|
|
665
561
|
}
|
|
666
562
|
};
|
|
667
|
-
|
|
668
|
-
/** Payload Parser */
|
|
669
|
-
typedef
|
|
563
|
+
|
|
564
|
+
/** Payload Section Parser */
|
|
565
|
+
typedef SectionParser<Payload, ListSectionAdapter> PayloadParser;
|
|
670
566
|
}
|
|
671
567
|
|
|
672
568
|
#endif
|