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
|
@@ -17,17 +17,14 @@
|
|
|
17
17
|
#endif
|
|
18
18
|
|
|
19
19
|
#if defined(_MSC_VER)
|
|
20
|
-
# define FORCEINLINE __forceinline
|
|
21
20
|
# if !defined(DEPRECATED)
|
|
22
21
|
# define DEPRECATED __declspec(deprecated)
|
|
23
22
|
# endif
|
|
24
23
|
#elif defined(__clang__) || defined(__GNUC__)
|
|
25
|
-
# define FORCEINLINE inline
|
|
26
24
|
# if !defined(DEPRECATED)
|
|
27
25
|
# define DEPRECATED __attribute__((deprecated))
|
|
28
26
|
# endif
|
|
29
27
|
#else
|
|
30
|
-
# define FORCEINLINE inline
|
|
31
28
|
# if !defined(DEPRECATED)
|
|
32
29
|
# define DEPRECATED
|
|
33
30
|
# endif
|
|
@@ -9,187 +9,206 @@
|
|
|
9
9
|
#ifndef SNOWCRASH_RESOURCEGROUPPARSER_H
|
|
10
10
|
#define SNOWCRASH_RESOURCEGROUPPARSER_H
|
|
11
11
|
|
|
12
|
-
#include "
|
|
13
|
-
#include "Blueprint.h"
|
|
12
|
+
#include "SectionParser.h"
|
|
14
13
|
#include "ResourceParser.h"
|
|
14
|
+
#include "RegexMatch.h"
|
|
15
|
+
|
|
16
|
+
namespace snowcrash {
|
|
15
17
|
|
|
16
|
-
namespace snowcrashconst {
|
|
17
|
-
|
|
18
18
|
const char* const GroupHeaderRegex = "^[[:blank:]]*[Gg]roup[[:blank:]]+" SYMBOL_IDENTIFIER "[[:blank:]]*$";
|
|
19
|
-
}
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
FORCEINLINE Collection<ResourceGroup>::const_iterator FindResourceGroup(const Blueprint& blueprint,
|
|
30
|
-
const ResourceGroup& group) {
|
|
31
|
-
|
|
32
|
-
return std::find_if(blueprint.resourceGroups.begin(),
|
|
33
|
-
blueprint.resourceGroups.end(),
|
|
34
|
-
std::bind2nd(MatchName<ResourceGroup>(), group));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* \brief Check a markdown block of Group signature, also retrieves a group name.
|
|
39
|
-
* \param block A markdown block to query for its signature and retrieve a group name from.
|
|
40
|
-
* \param name An output buffer to retrieve a Resource Group Name into.
|
|
41
|
-
* \returns True if the given markdown block has Resource group signature, false otherwise.
|
|
42
|
-
*/
|
|
43
|
-
FORCEINLINE bool GetResourceGroupSignature(const MarkdownBlock& block,
|
|
44
|
-
Name& name) {
|
|
45
|
-
if (block.type != HeaderBlockType ||
|
|
46
|
-
block.content.empty())
|
|
47
|
-
return false;
|
|
48
|
-
|
|
49
|
-
CaptureGroups captureGroups;
|
|
50
|
-
if (RegexCapture(block.content, snowcrashconst::GroupHeaderRegex, captureGroups, 3)) {
|
|
51
|
-
name = captureGroups[1];
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
|
|
20
|
+
/** Resource iterator pair: its containment group and resource iterator itself */
|
|
21
|
+
typedef std::pair<Collection<ResourceGroup>::const_iterator, ResourceIterator> ResourceIteratorPair;
|
|
22
|
+
|
|
23
|
+
/** Internal type alias for Collection of Resource */
|
|
24
|
+
typedef Collection<ResourceGroup>::type ResourceGroups;
|
|
25
|
+
|
|
26
|
+
typedef Collection<ResourceGroup>::const_iterator ResourceGroupIterator;
|
|
27
|
+
|
|
58
28
|
/**
|
|
59
|
-
*
|
|
60
|
-
* \param block A markdown block to query its signature
|
|
61
|
-
* \returns True if the given markdown block has Resource group signature, false otherwise.
|
|
29
|
+
* ResourceGroup Section processor
|
|
62
30
|
*/
|
|
63
|
-
FORCEINLINE bool HasResourceGroupSignature(const MarkdownBlock& block)
|
|
64
|
-
{
|
|
65
|
-
Name name;
|
|
66
|
-
return GetResourceGroupSignature(block, name);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** Internal list items classifier, Resource Group Context */
|
|
70
|
-
template <>
|
|
71
|
-
FORCEINLINE SectionType ClassifyInternaListBlock<ResourceGroup>(const BlockIterator& begin,
|
|
72
|
-
const BlockIterator& end) {
|
|
73
|
-
return UndefinedSectionType;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/** Block Classifier, Resource Group Context */
|
|
77
|
-
template <>
|
|
78
|
-
FORCEINLINE SectionType ClassifyBlock<ResourceGroup>(const BlockIterator& begin,
|
|
79
|
-
const BlockIterator& end,
|
|
80
|
-
const SectionType& context) {
|
|
81
|
-
|
|
82
|
-
if (HasResourceGroupSignature(*begin))
|
|
83
|
-
return (context == UndefinedSectionType) ? ResourceGroupSectionType : UndefinedSectionType;
|
|
84
|
-
|
|
85
|
-
if (HasResourceSignature(*begin))
|
|
86
|
-
return ResourceSectionType;
|
|
87
|
-
|
|
88
|
-
return (context == ResourceGroupSectionType) ? context : UndefinedSectionType;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/** Resource Group SectionType Parser */
|
|
92
31
|
template<>
|
|
93
|
-
struct
|
|
94
|
-
|
|
95
|
-
static
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
break;
|
|
32
|
+
struct SectionProcessor<ResourceGroup> : public SectionProcessorBase<ResourceGroup> {
|
|
33
|
+
|
|
34
|
+
static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
|
|
35
|
+
const MarkdownNodes& siblings,
|
|
36
|
+
SectionParserData& pd,
|
|
37
|
+
SectionLayout& layout,
|
|
38
|
+
Report& report,
|
|
39
|
+
ResourceGroup& out) {
|
|
40
|
+
|
|
41
|
+
MarkdownNodeIterator cur = node;
|
|
42
|
+
SectionType nestedType = nestedSectionType(cur);
|
|
43
|
+
|
|
44
|
+
// Resources only, parse as exclusive nested sections
|
|
45
|
+
if (nestedType != UndefinedSectionType) {
|
|
46
|
+
layout = ExclusiveNestedSectionLayout;
|
|
47
|
+
return cur;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
CaptureGroups captureGroups;
|
|
51
|
+
|
|
52
|
+
if (RegexCapture(node->text, GroupHeaderRegex, captureGroups, 3)) {
|
|
53
|
+
out.name = captureGroups[1];
|
|
54
|
+
TrimString(out.name);
|
|
117
55
|
}
|
|
118
|
-
|
|
119
|
-
return
|
|
56
|
+
|
|
57
|
+
return ++MarkdownNodeIterator(node);
|
|
120
58
|
}
|
|
121
59
|
|
|
122
|
-
static
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
60
|
+
static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
|
|
61
|
+
const MarkdownNodes& siblings,
|
|
62
|
+
SectionParserData& pd,
|
|
63
|
+
Report& report,
|
|
64
|
+
ResourceGroup& out) {
|
|
65
|
+
|
|
66
|
+
if (pd.sectionContext() == ResourceSectionType) {
|
|
67
|
+
|
|
68
|
+
Resource resource;
|
|
69
|
+
MarkdownNodeIterator cur = ResourceParser::parse(node, siblings, pd, report, resource);
|
|
70
|
+
|
|
71
|
+
ResourceIterator duplicate = findResource(out.resources, resource);
|
|
72
|
+
ResourceIteratorPair globalDuplicate;
|
|
73
|
+
|
|
74
|
+
if (duplicate == out.resources.end()) {
|
|
75
|
+
globalDuplicate = findResource(pd.blueprint, resource);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (duplicate != out.resources.end() ||
|
|
79
|
+
globalDuplicate.first != pd.blueprint.resourceGroups.end()) {
|
|
80
|
+
|
|
81
|
+
// WARN: Duplicate resource
|
|
82
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
83
|
+
report.warnings.push_back(Warning("the resource '" + resource.uriTemplate + "' is already defined",
|
|
84
|
+
DuplicateWarning,
|
|
85
|
+
sourceMap));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
out.resources.push_back(resource);
|
|
89
|
+
|
|
90
|
+
return cur;
|
|
141
91
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
result = ParseDescriptionBlock<ResourceGroup>(section,
|
|
145
|
-
sectionCur,
|
|
146
|
-
parser.sourceData,
|
|
147
|
-
group);
|
|
148
|
-
return result;
|
|
149
|
-
|
|
92
|
+
|
|
93
|
+
return node;
|
|
150
94
|
}
|
|
151
|
-
|
|
152
|
-
static
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
result.first.warnings.push_back(Warning("the resource '" +
|
|
179
|
-
resource.uriTemplate +
|
|
180
|
-
"' is already defined",
|
|
181
|
-
DuplicateWarning,
|
|
182
|
-
sourceBlock));
|
|
95
|
+
|
|
96
|
+
static MarkdownNodeIterator processUnexpectedNode(const MarkdownNodeIterator& node,
|
|
97
|
+
const MarkdownNodes& siblings,
|
|
98
|
+
SectionParserData& pd,
|
|
99
|
+
SectionType& lastSectionType,
|
|
100
|
+
Report& report,
|
|
101
|
+
ResourceGroup& out) {
|
|
102
|
+
|
|
103
|
+
if (SectionProcessor<Action>::actionType(node) == DependentActionType &&
|
|
104
|
+
!out.resources.empty()) {
|
|
105
|
+
|
|
106
|
+
mdp::ByteBuffer method;
|
|
107
|
+
mdp::ByteBuffer name;
|
|
108
|
+
|
|
109
|
+
SectionProcessor<Action>::actionHTTPMethodAndName(node, method, name);
|
|
110
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
111
|
+
|
|
112
|
+
// WARN: Unexpected action
|
|
113
|
+
std::stringstream ss;
|
|
114
|
+
ss << "unexpected action '" << method << "', to define multiple actions for the '" << out.resources.back().uriTemplate;
|
|
115
|
+
ss << "' resource omit the HTTP method in its definition, e.g. '# /resource'";
|
|
116
|
+
|
|
117
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
118
|
+
IgnoringWarning,
|
|
119
|
+
sourceMap));
|
|
120
|
+
|
|
121
|
+
return ++MarkdownNodeIterator(node);
|
|
183
122
|
}
|
|
184
123
|
|
|
124
|
+
return SectionProcessorBase<ResourceGroup>::processUnexpectedNode(node, siblings, pd, lastSectionType, report, out);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static SectionType sectionType(const MarkdownNodeIterator& node) {
|
|
128
|
+
|
|
129
|
+
if (node->type == mdp::HeaderMarkdownNodeType
|
|
130
|
+
&& !node->text.empty()) {
|
|
131
|
+
|
|
132
|
+
mdp::ByteBuffer subject = node->text;
|
|
133
|
+
TrimString(subject);
|
|
134
|
+
|
|
135
|
+
if (RegexMatch(subject, GroupHeaderRegex)) {
|
|
136
|
+
return ResourceGroupSectionType;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return UndefinedSectionType;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
static SectionType nestedSectionType(const MarkdownNodeIterator& node) {
|
|
144
|
+
|
|
145
|
+
// Return ResourceSectionType or UndefinedSectionType
|
|
146
|
+
return SectionProcessor<Resource>::sectionType(node);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
static SectionTypes nestedSectionTypes() {
|
|
150
|
+
SectionTypes nested;
|
|
151
|
+
|
|
152
|
+
// Resource & descendants
|
|
153
|
+
nested.push_back(ResourceSectionType);
|
|
154
|
+
SectionTypes types = SectionProcessor<Resource>::nestedSectionTypes();
|
|
155
|
+
nested.insert(nested.end(), types.begin(), types.end());
|
|
156
|
+
|
|
157
|
+
return nested;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static bool isDescriptionNode(const MarkdownNodeIterator& node,
|
|
161
|
+
SectionType sectionType) {
|
|
162
|
+
|
|
163
|
+
mdp::ByteBuffer method;
|
|
185
164
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
165
|
+
if (SectionProcessor<Action>::actionType(node) == CompleteActionType) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return SectionProcessorBase<ResourceGroup>::isDescriptionNode(node, sectionType);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
static bool isUnexpectedNode(const MarkdownNodeIterator& node,
|
|
173
|
+
SectionType sectionType) {
|
|
174
|
+
|
|
175
|
+
if (SectionProcessor<Action>::actionType(node) == DependentActionType) {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return SectionProcessorBase<ResourceGroup>::isUnexpectedNode(node, sectionType);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Finds a resource inside an resources collection */
|
|
183
|
+
static ResourceIterator findResource(const Resources& resources,
|
|
184
|
+
const Resource& resource) {
|
|
185
|
+
|
|
186
|
+
return std::find_if(resources.begin(),
|
|
187
|
+
resources.end(),
|
|
188
|
+
std::bind2nd(MatchResource(), resource));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Finds a resource in blueprint by its URI template */
|
|
192
|
+
static ResourceIteratorPair findResource(const Blueprint& blueprint,
|
|
193
|
+
const Resource& resource) {
|
|
194
|
+
|
|
195
|
+
for (Collection<ResourceGroup>::const_iterator it = blueprint.resourceGroups.begin();
|
|
196
|
+
it != blueprint.resourceGroups.end();
|
|
197
|
+
++it) {
|
|
198
|
+
|
|
199
|
+
ResourceIterator match = findResource(it->resources, resource);
|
|
200
|
+
|
|
201
|
+
if (match != it->resources.end()) {
|
|
202
|
+
return std::make_pair(it, match);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return std::make_pair(blueprint.resourceGroups.end(), ResourceIterator());
|
|
189
207
|
}
|
|
190
208
|
};
|
|
191
|
-
|
|
192
|
-
|
|
209
|
+
|
|
210
|
+
/** ResourceGroup Section Parser */
|
|
211
|
+
typedef SectionParser<ResourceGroup, HeaderSectionAdapter> ResourceGroupParser;
|
|
193
212
|
}
|
|
194
213
|
|
|
195
214
|
#endif
|
|
@@ -9,576 +9,408 @@
|
|
|
9
9
|
#ifndef SNOWCRASH_RESOURCEPARSER_H
|
|
10
10
|
#define SNOWCRASH_RESOURCEPARSER_H
|
|
11
11
|
|
|
12
|
-
#include
|
|
13
|
-
#include "BlueprintParserCore.h"
|
|
14
|
-
#include "Blueprint.h"
|
|
12
|
+
#include "SectionParser.h"
|
|
15
13
|
#include "ActionParser.h"
|
|
16
|
-
#include "
|
|
17
|
-
#include "StringUtility.h"
|
|
14
|
+
#include "HeadersParser.h"
|
|
18
15
|
#include "ParametersParser.h"
|
|
19
|
-
#include "DescriptionSectionUtility.h"
|
|
20
16
|
#include "UriTemplateParser.h"
|
|
17
|
+
#include "RegexMatch.h"
|
|
21
18
|
|
|
22
|
-
namespace
|
|
19
|
+
namespace snowcrash {
|
|
23
20
|
|
|
24
21
|
/** Nameless resource matching regex */
|
|
25
22
|
const char* const ResourceHeaderRegex = "^[[:blank:]]*(" HTTP_REQUEST_METHOD "[[:blank:]]+)?" URI_TEMPLATE "$";
|
|
26
23
|
|
|
27
24
|
/** Named resource matching regex */
|
|
28
25
|
const char* const NamedResourceHeaderRegex = "^[[:blank:]]*" SYMBOL_IDENTIFIER "[[:blank:]]+\\[" URI_TEMPLATE "]$";
|
|
29
|
-
}
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
// Resource signature
|
|
34
|
-
enum ResourceSignature {
|
|
35
|
-
UndefinedResourceSignature,
|
|
36
|
-
NoResourceSignature,
|
|
37
|
-
URIResourceSignature,
|
|
38
|
-
MethodURIResourceSignature,
|
|
39
|
-
NamedResourceSignature
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
// Query resource signature
|
|
43
|
-
FORCEINLINE ResourceSignature GetResourceSignature(const MarkdownBlock& block,
|
|
44
|
-
Name& name,
|
|
45
|
-
URITemplate& uri,
|
|
46
|
-
HTTPMethod& method) {
|
|
47
|
-
if (block.type != HeaderBlockType ||
|
|
48
|
-
block.content.empty())
|
|
49
|
-
return NoResourceSignature;
|
|
50
|
-
|
|
51
|
-
CaptureGroups captureGroups;
|
|
52
|
-
// Nameless resource
|
|
53
|
-
if (RegexCapture(block.content, snowcrashconst::ResourceHeaderRegex, captureGroups, 4)) {
|
|
54
|
-
method = captureGroups[2];
|
|
55
|
-
uri = captureGroups[3];
|
|
56
|
-
return (method.empty()) ? URIResourceSignature : MethodURIResourceSignature;
|
|
57
|
-
}
|
|
58
|
-
else if (RegexCapture(block.content, snowcrashconst::NamedResourceHeaderRegex, captureGroups, 4)) {
|
|
59
|
-
method.clear();
|
|
60
|
-
name = captureGroups[1];
|
|
61
|
-
TrimString(name);
|
|
62
|
-
uri = captureGroups[2];
|
|
63
|
-
return NamedResourceSignature;
|
|
64
|
-
}
|
|
27
|
+
/** Internal type alias for Collection of Resource */
|
|
28
|
+
typedef Collection<Resource>::type Resources;
|
|
65
29
|
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Returns true if block has resource header signature, false otherwise
|
|
70
|
-
FORCEINLINE bool HasResourceSignature(const MarkdownBlock& block) {
|
|
30
|
+
typedef Collection<Resource>::const_iterator ResourceIterator;
|
|
71
31
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Resource Section processor
|
|
34
|
+
*/
|
|
35
|
+
template<>
|
|
36
|
+
struct SectionProcessor<Resource> : public SectionProcessorBase<Resource> {
|
|
77
37
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const Resource& resource) {
|
|
95
|
-
|
|
96
|
-
for (Collection<ResourceGroup>::const_iterator it = blueprint.resourceGroups.begin();
|
|
97
|
-
it != blueprint.resourceGroups.end();
|
|
98
|
-
++it) {
|
|
99
|
-
|
|
100
|
-
Collection<Resource>::const_iterator match = FindResource(*it, resource);
|
|
101
|
-
if (match != it->resources.end())
|
|
102
|
-
return std::make_pair(it, match);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return std::make_pair(blueprint.resourceGroups.end(), Collection<Resource>::iterator());
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
//
|
|
110
|
-
// Classifier of internal list items, Resource context
|
|
111
|
-
//
|
|
112
|
-
template <>
|
|
113
|
-
FORCEINLINE SectionType ClassifyInternaListBlock<Resource>(const BlockIterator& begin,
|
|
114
|
-
const BlockIterator& end) {
|
|
115
|
-
if (HasHeaderSignature(begin, end))
|
|
116
|
-
return HeadersSectionType;
|
|
117
|
-
|
|
118
|
-
if (HasParametersSignature(begin, end))
|
|
119
|
-
return ParametersSectionType;
|
|
120
|
-
|
|
121
|
-
Name name;
|
|
122
|
-
SourceData mediaType;
|
|
123
|
-
PayloadSignature payloadSignature = GetPayloadSignature(begin, end, name, mediaType);
|
|
124
|
-
if (payloadSignature == ObjectPayloadSignature)
|
|
125
|
-
return ObjectSectionType;
|
|
126
|
-
else if (payloadSignature == ModelPayloadSignature)
|
|
127
|
-
return ModelSectionType;
|
|
128
|
-
|
|
129
|
-
return UndefinedSectionType;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/** Children blocks classifier */
|
|
133
|
-
template <>
|
|
134
|
-
FORCEINLINE SectionType ClassifyChildrenListBlock<Resource>(const BlockIterator& begin,
|
|
135
|
-
const BlockIterator& end) {
|
|
136
|
-
|
|
137
|
-
SectionType type = ClassifyInternaListBlock<Resource>(begin, end);
|
|
138
|
-
if (type != UndefinedSectionType)
|
|
139
|
-
return type;
|
|
140
|
-
|
|
141
|
-
type = ClassifyChildrenListBlock<HeaderCollection>(begin, end);
|
|
142
|
-
if (type != UndefinedSectionType)
|
|
143
|
-
return type;
|
|
144
|
-
|
|
145
|
-
type = ClassifyChildrenListBlock<ParameterCollection>(begin, end);
|
|
146
|
-
if (type != UndefinedSectionType)
|
|
147
|
-
return type;
|
|
148
|
-
|
|
149
|
-
type = ClassifyChildrenListBlock<Payload>(begin, end);
|
|
150
|
-
if (type != UndefinedSectionType)
|
|
151
|
-
return type;
|
|
152
|
-
|
|
153
|
-
return UndefinedSectionType;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
//
|
|
157
|
-
// Block Classifier, Resource Context
|
|
158
|
-
//
|
|
159
|
-
template <>
|
|
160
|
-
FORCEINLINE SectionType ClassifyBlock<Resource>(const BlockIterator& begin,
|
|
161
|
-
const BlockIterator& end,
|
|
162
|
-
const SectionType& context) {
|
|
163
|
-
if (HasResourceGroupSignature(*begin))
|
|
164
|
-
return UndefinedSectionType;
|
|
38
|
+
static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
|
|
39
|
+
const MarkdownNodes& siblings,
|
|
40
|
+
SectionParserData& pd,
|
|
41
|
+
SectionLayout& layout,
|
|
42
|
+
Report& report,
|
|
43
|
+
Resource& out) {
|
|
44
|
+
|
|
45
|
+
CaptureGroups captureGroups;
|
|
46
|
+
|
|
47
|
+
// If Abbreviated resource section
|
|
48
|
+
if (RegexCapture(node->text, ResourceHeaderRegex, captureGroups, 4)) {
|
|
49
|
+
|
|
50
|
+
out.uriTemplate = captureGroups[3];
|
|
51
|
+
|
|
52
|
+
// Make this section an action
|
|
53
|
+
if (!captureGroups[2].empty()) {
|
|
165
54
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
55
|
+
Action action;
|
|
56
|
+
MarkdownNodeIterator cur = ActionParser::parse(node, node->parent().children(), pd, report, action);
|
|
57
|
+
|
|
58
|
+
out.actions.push_back(action);
|
|
59
|
+
layout = RedirectSectionLayout;
|
|
60
|
+
|
|
61
|
+
return cur;
|
|
62
|
+
}
|
|
63
|
+
} else if (RegexCapture(node->text, NamedResourceHeaderRegex, captureGroups, 4)) {
|
|
64
|
+
|
|
65
|
+
out.name = captureGroups[1];
|
|
66
|
+
TrimString(out.name);
|
|
67
|
+
out.uriTemplate = captureGroups[2];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return ++MarkdownNodeIterator(node);
|
|
174
71
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return (context == ResourceSectionType) ? context : UndefinedSectionType;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
//
|
|
191
|
-
// Resource SectionType Parser
|
|
192
|
-
//
|
|
193
|
-
template<>
|
|
194
|
-
struct SectionParser<Resource> {
|
|
195
|
-
|
|
196
|
-
static ParseSectionResult ParseSection(const BlueprintSection& section,
|
|
197
|
-
const BlockIterator& cur,
|
|
198
|
-
BlueprintParserCore& parser,
|
|
199
|
-
Resource& resource) {
|
|
200
|
-
ParseSectionResult result = std::make_pair(Result(), cur);
|
|
201
|
-
|
|
202
|
-
switch (section.type) {
|
|
203
|
-
case ResourceSectionType:
|
|
204
|
-
result = HandleResourceDescriptionBlock(section, cur, parser, resource);
|
|
205
|
-
break;
|
|
206
|
-
|
|
207
|
-
case ResourceMethodSectionType:
|
|
208
|
-
result = HandleResourceMethod(section, cur, parser, resource);
|
|
209
|
-
break;
|
|
210
|
-
|
|
211
|
-
case ModelSectionType:
|
|
212
|
-
case ObjectSectionType:
|
|
213
|
-
result = HandleModel(section, cur, parser, resource);
|
|
214
|
-
break;
|
|
215
|
-
|
|
72
|
+
|
|
73
|
+
static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
|
|
74
|
+
const MarkdownNodes& siblings,
|
|
75
|
+
SectionParserData& pd,
|
|
76
|
+
Report& report,
|
|
77
|
+
Resource& out) {
|
|
78
|
+
|
|
79
|
+
switch (pd.sectionContext()) {
|
|
80
|
+
case ActionSectionType:
|
|
81
|
+
return processAction(node, siblings, pd, report, out);
|
|
82
|
+
|
|
216
83
|
case ParametersSectionType:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
84
|
+
return processParameters(node, siblings, pd, report, out);
|
|
85
|
+
|
|
86
|
+
case ModelSectionType:
|
|
87
|
+
case ModelBodySectionType:
|
|
88
|
+
return processModel(node, siblings, pd, report, out);
|
|
89
|
+
|
|
220
90
|
case HeadersSectionType:
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
case ActionSectionType:
|
|
225
|
-
result = HandleAction(section, cur, parser, resource);
|
|
226
|
-
break;
|
|
227
|
-
|
|
228
|
-
case UndefinedSectionType:
|
|
229
|
-
CheckAmbiguousMethod(section, cur, resource, parser.sourceData, result.first);
|
|
230
|
-
result.second = CloseList(cur, section.bounds.second);
|
|
231
|
-
break;
|
|
232
|
-
|
|
233
|
-
case ForeignSectionType:
|
|
234
|
-
result = HandleForeignSection<Resource>(section, cur, parser.sourceData);
|
|
235
|
-
break;
|
|
236
|
-
|
|
91
|
+
return SectionProcessor<Action>::handleDeprecatedHeaders(node, siblings, pd, report, out.headers);
|
|
92
|
+
|
|
237
93
|
default:
|
|
238
|
-
result.first.error = UnexpectedBlockError(section, cur, parser.sourceData);
|
|
239
94
|
break;
|
|
240
95
|
}
|
|
241
96
|
|
|
97
|
+
return node;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static MarkdownNodeIterator processUnexpectedNode(const MarkdownNodeIterator& node,
|
|
101
|
+
const MarkdownNodes& siblings,
|
|
102
|
+
SectionParserData& pd,
|
|
103
|
+
SectionType& sectionType,
|
|
104
|
+
Report& report,
|
|
105
|
+
Resource& out) {
|
|
242
106
|
|
|
243
|
-
|
|
107
|
+
if ((node->type == mdp::ParagraphMarkdownNodeType ||
|
|
108
|
+
node->type == mdp::CodeMarkdownNodeType) &&
|
|
109
|
+
(sectionType == ModelBodySectionType ||
|
|
110
|
+
sectionType == ModelSectionType)) {
|
|
111
|
+
|
|
112
|
+
CodeBlockUtility::addDanglingAsset(node, pd, sectionType, report, out.model.body);
|
|
113
|
+
|
|
114
|
+
// Update model in the symbol table as well
|
|
115
|
+
ResourceModelSymbolTable::iterator it = pd.symbolTable.resourceModels.find(out.model.name);
|
|
116
|
+
|
|
117
|
+
if (it != pd.symbolTable.resourceModels.end()) {
|
|
118
|
+
it->second.body = out.model.body;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return ++MarkdownNodeIterator(node);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return SectionProcessorBase<Resource>::processUnexpectedNode(node, siblings, pd, sectionType, report, out);
|
|
244
125
|
}
|
|
245
126
|
|
|
246
|
-
static
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
127
|
+
static bool isDescriptionNode(const MarkdownNodeIterator& node,
|
|
128
|
+
SectionType sectionType) {
|
|
129
|
+
|
|
130
|
+
if (SectionProcessor<Action>::actionType(node) == CompleteActionType) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return SectionProcessorBase<Resource>::isDescriptionNode(node, sectionType);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static SectionType sectionType(const MarkdownNodeIterator& node) {
|
|
138
|
+
|
|
139
|
+
if (node->type == mdp::HeaderMarkdownNodeType
|
|
140
|
+
&& !node->text.empty()) {
|
|
141
|
+
|
|
142
|
+
CaptureGroups captureGroups;
|
|
143
|
+
mdp::ByteBuffer subject = node->text;
|
|
144
|
+
|
|
145
|
+
TrimString(subject);
|
|
146
|
+
|
|
147
|
+
if (RegexMatch(subject, NamedResourceHeaderRegex) ||
|
|
148
|
+
RegexMatch(subject, ResourceHeaderRegex)) {
|
|
149
|
+
return ResourceSectionType;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return UndefinedSectionType;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static SectionType nestedSectionType(const MarkdownNodeIterator& node) {
|
|
157
|
+
|
|
158
|
+
SectionType nestedType = UndefinedSectionType;
|
|
159
|
+
|
|
160
|
+
// Check if parameters section
|
|
161
|
+
nestedType = SectionProcessor<Parameters>::sectionType(node);
|
|
162
|
+
|
|
163
|
+
if (nestedType != UndefinedSectionType) {
|
|
164
|
+
return nestedType;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check if headers section
|
|
168
|
+
nestedType = SectionProcessor<Headers>::sectionType(node);
|
|
169
|
+
|
|
170
|
+
if (nestedType == HeadersSectionType) {
|
|
171
|
+
return nestedType;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Check if model section
|
|
175
|
+
nestedType = SectionProcessor<Payload>::sectionType(node);
|
|
176
|
+
|
|
177
|
+
if (nestedType == ModelSectionType ||
|
|
178
|
+
nestedType == ModelBodySectionType) {
|
|
179
|
+
|
|
180
|
+
return nestedType;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Check if action section
|
|
184
|
+
nestedType = SectionProcessor<Action>::sectionType(node);
|
|
185
|
+
|
|
186
|
+
if (nestedType == ActionSectionType) {
|
|
187
|
+
|
|
188
|
+
// Do not consider complete actions as nested
|
|
189
|
+
mdp::ByteBuffer method;
|
|
190
|
+
if (SectionProcessor<Action>::actionType(node) == CompleteActionType)
|
|
191
|
+
return UndefinedSectionType;
|
|
192
|
+
|
|
193
|
+
return nestedType;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return UndefinedSectionType;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
static SectionTypes nestedSectionTypes() {
|
|
200
|
+
SectionTypes nested;
|
|
201
|
+
|
|
202
|
+
// Action & descendants
|
|
203
|
+
nested.push_back(ActionSectionType);
|
|
204
|
+
SectionTypes types = SectionProcessor<Action>::nestedSectionTypes();
|
|
205
|
+
nested.insert(nested.end(), types.begin(), types.end());
|
|
206
|
+
|
|
207
|
+
nested.push_back(ModelSectionType);
|
|
208
|
+
nested.push_back(ModelBodySectionType);
|
|
209
|
+
|
|
210
|
+
return nested;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
static void finalize(const MarkdownNodeIterator& node,
|
|
214
|
+
SectionParserData& pd,
|
|
215
|
+
Report& report,
|
|
216
|
+
Resource& out) {
|
|
217
|
+
|
|
218
|
+
if (!out.uriTemplate.empty()) {
|
|
251
219
|
|
|
252
|
-
if (!resource.uriTemplate.empty()) {
|
|
253
220
|
URITemplateParser uriTemplateParser;
|
|
254
221
|
ParsedURITemplate parsedResult;
|
|
255
|
-
|
|
222
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
223
|
+
|
|
224
|
+
uriTemplateParser.parse(out.uriTemplate, sourceMap, parsedResult);
|
|
256
225
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
result += parsedResult.result;
|
|
226
|
+
if (!parsedResult.report.warnings.empty()) {
|
|
227
|
+
report += parsedResult.report;
|
|
260
228
|
}
|
|
261
229
|
}
|
|
262
230
|
|
|
263
231
|
// Consolidate depraceted headers into subsequent payloads
|
|
264
|
-
if (!
|
|
265
|
-
|
|
266
|
-
|
|
232
|
+
if (!out.headers.empty()) {
|
|
233
|
+
|
|
234
|
+
for (Collection<Action>::iterator it = out.actions.begin();
|
|
235
|
+
it != out.actions.end();
|
|
267
236
|
++it) {
|
|
268
|
-
|
|
237
|
+
|
|
238
|
+
SectionProcessor<Headers>::injectDeprecatedHeaders(out.headers, it->examples);
|
|
269
239
|
}
|
|
270
|
-
|
|
271
|
-
|
|
240
|
+
|
|
241
|
+
out.headers.clear();
|
|
272
242
|
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Process Action section */
|
|
246
|
+
static MarkdownNodeIterator processAction(const MarkdownNodeIterator& node,
|
|
247
|
+
const MarkdownNodes& siblings,
|
|
248
|
+
SectionParserData& pd,
|
|
249
|
+
Report& report,
|
|
250
|
+
Resource& out) {
|
|
251
|
+
|
|
252
|
+
Action action;
|
|
253
|
+
MarkdownNodeIterator cur = ActionParser::parse(node, siblings, pd, report, action);
|
|
273
254
|
|
|
255
|
+
ActionIterator duplicate = findAction(out.actions, action);
|
|
256
|
+
|
|
257
|
+
if (duplicate != out.actions.end()) {
|
|
258
|
+
|
|
259
|
+
// WARN: duplicate method
|
|
260
|
+
std::stringstream ss;
|
|
261
|
+
ss << "action with method '" << action.method << "' already defined for resource '";
|
|
262
|
+
ss << out.uriTemplate << "'";
|
|
263
|
+
|
|
264
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
265
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
266
|
+
DuplicateWarning,
|
|
267
|
+
sourceMap));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (!action.parameters.empty()) {
|
|
271
|
+
|
|
272
|
+
checkParametersEligibility(node, pd, out, action.parameters, report);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
out.actions.push_back(action);
|
|
276
|
+
|
|
277
|
+
return cur;
|
|
274
278
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
result.second = ++sectionCur;
|
|
291
|
-
return result;
|
|
279
|
+
|
|
280
|
+
/** Process Parameters section */
|
|
281
|
+
static MarkdownNodeIterator processParameters(const MarkdownNodeIterator& node,
|
|
282
|
+
const MarkdownNodes& siblings,
|
|
283
|
+
SectionParserData& pd,
|
|
284
|
+
Report& report,
|
|
285
|
+
Resource& out) {
|
|
286
|
+
|
|
287
|
+
Parameters parameters;
|
|
288
|
+
MarkdownNodeIterator cur = ParametersParser::parse(node, siblings, pd, report, parameters);
|
|
289
|
+
|
|
290
|
+
if (!parameters.empty()) {
|
|
291
|
+
|
|
292
|
+
checkParametersEligibility(node, pd, out, parameters, report);
|
|
293
|
+
out.parameters.insert(out.parameters.end(), parameters.begin(), parameters.end());
|
|
292
294
|
}
|
|
293
295
|
|
|
294
|
-
|
|
295
|
-
sectionCur,
|
|
296
|
-
parser.sourceData,
|
|
297
|
-
resource);
|
|
298
|
-
return result;
|
|
296
|
+
return cur;
|
|
299
297
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if (
|
|
313
|
-
return result;
|
|
314
|
-
|
|
315
|
-
// Check whether there isnt a model already
|
|
316
|
-
if (!resource.model.name.empty()) {
|
|
298
|
+
|
|
299
|
+
/** Process Model section */
|
|
300
|
+
static MarkdownNodeIterator processModel(const MarkdownNodeIterator& node,
|
|
301
|
+
const MarkdownNodes& siblings,
|
|
302
|
+
SectionParserData& pd,
|
|
303
|
+
Report& report,
|
|
304
|
+
Resource& out) {
|
|
305
|
+
|
|
306
|
+
Payload model;
|
|
307
|
+
MarkdownNodeIterator cur = PayloadParser::parse(node, siblings, pd, report, model);
|
|
308
|
+
|
|
309
|
+
// Check whether there isn't a model already
|
|
310
|
+
if (!out.model.name.empty()) {
|
|
317
311
|
|
|
318
312
|
// WARN: Model already defined
|
|
319
313
|
std::stringstream ss;
|
|
320
|
-
ss << "overshadowing previous model
|
|
314
|
+
ss << "overshadowing previous model definition for '";
|
|
321
315
|
|
|
322
|
-
if (!
|
|
323
|
-
ss <<
|
|
324
|
-
else
|
|
325
|
-
ss <<
|
|
316
|
+
if (!out.name.empty()) {
|
|
317
|
+
ss << out.name << "(" << out.uriTemplate << ")";
|
|
318
|
+
} else {
|
|
319
|
+
ss << out.uriTemplate;
|
|
320
|
+
}
|
|
326
321
|
|
|
327
322
|
ss << "' resource, a resource can be represented by a single model only";
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
sourceBlock));
|
|
334
|
-
|
|
335
|
-
return result;
|
|
323
|
+
|
|
324
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
325
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
326
|
+
DuplicateWarning,
|
|
327
|
+
sourceMap));
|
|
336
328
|
}
|
|
337
329
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
else {
|
|
330
|
+
if (model.name.empty()) {
|
|
331
|
+
|
|
332
|
+
if (!out.name.empty()) {
|
|
333
|
+
model.name = out.name;
|
|
334
|
+
} else {
|
|
335
|
+
|
|
345
336
|
// ERR: No name specified for resource model
|
|
346
337
|
std::stringstream ss;
|
|
347
338
|
ss << "resource model can be specified only for a named resource";
|
|
348
|
-
ss << ", name your resource, e.g. '# <resource name> [" <<
|
|
339
|
+
ss << ", name your resource, e.g. '# <resource name> [" << out.uriTemplate << "]'";
|
|
349
340
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
sourceBlock);
|
|
341
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
342
|
+
report.error = Error(ss.str(),
|
|
343
|
+
SymbolError,
|
|
344
|
+
sourceMap);
|
|
355
345
|
}
|
|
356
346
|
}
|
|
357
|
-
|
|
358
|
-
// Check whether symbol isn't already defined
|
|
359
|
-
ResourceModelSymbolTable::const_iterator it = parser.symbolTable.resourceModels.find(payload.name);
|
|
360
|
-
if (it == parser.symbolTable.resourceModels.end()) {
|
|
361
347
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
348
|
+
ResourceModelSymbolTable::iterator it = pd.symbolTable.resourceModels.find(model.name);
|
|
349
|
+
|
|
350
|
+
if (it == pd.symbolTable.resourceModels.end()) {
|
|
351
|
+
|
|
352
|
+
pd.symbolTable.resourceModels[model.name] = model;
|
|
353
|
+
} else {
|
|
354
|
+
|
|
365
355
|
// ERR: Symbol already defined
|
|
366
356
|
std::stringstream ss;
|
|
367
|
-
ss << "symbol '" <<
|
|
357
|
+
ss << "symbol '" << model.name << "' already defined";
|
|
368
358
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
sourceBlock);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// Assign model
|
|
377
|
-
resource.model = payload;
|
|
378
|
-
|
|
379
|
-
return result;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/** Parse Parameters section */
|
|
383
|
-
static ParseSectionResult HandleParameters(const BlueprintSection& section,
|
|
384
|
-
const BlockIterator& cur,
|
|
385
|
-
BlueprintParserCore& parser,
|
|
386
|
-
Resource& resource) {
|
|
387
|
-
ParameterCollection parameters;
|
|
388
|
-
ParseSectionResult result = ParametersParser::Parse(cur,
|
|
389
|
-
section.bounds.second,
|
|
390
|
-
section,
|
|
391
|
-
parser,
|
|
392
|
-
parameters);
|
|
393
|
-
if (result.first.error.code != Error::OK)
|
|
394
|
-
return result;
|
|
395
|
-
|
|
396
|
-
if (parameters.empty()) {
|
|
397
|
-
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
|
398
|
-
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
|
|
399
|
-
result.first.warnings.push_back(Warning(snowcrashconst::NoParametersMessage,
|
|
400
|
-
FormattingWarning,
|
|
401
|
-
sourceBlock));
|
|
402
|
-
}
|
|
403
|
-
else {
|
|
404
|
-
// Check Eligibility
|
|
405
|
-
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
|
406
|
-
CheckParametersEligibility(resource, parameters, nameBlock->sourceMap, parser.sourceData, result.first);
|
|
407
|
-
|
|
408
|
-
// Insert
|
|
409
|
-
resource.parameters.insert(resource.parameters.end(), parameters.begin(), parameters.end());
|
|
359
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
360
|
+
report.error = Error(ss.str(),
|
|
361
|
+
SymbolError,
|
|
362
|
+
sourceMap);
|
|
410
363
|
}
|
|
411
|
-
|
|
412
|
-
|
|
364
|
+
|
|
365
|
+
out.model = model;
|
|
366
|
+
|
|
367
|
+
return cur;
|
|
413
368
|
}
|
|
414
|
-
|
|
415
|
-
/** Check
|
|
416
|
-
static void
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
for (
|
|
369
|
+
|
|
370
|
+
/** Check Parameters eligibility in URI template */
|
|
371
|
+
static void checkParametersEligibility(const MarkdownNodeIterator& node,
|
|
372
|
+
const SectionParserData& pd,
|
|
373
|
+
Resource& resource,
|
|
374
|
+
Parameters& parameters,
|
|
375
|
+
Report& report) {
|
|
376
|
+
|
|
377
|
+
for (ParameterIterator it = parameters.begin();
|
|
423
378
|
it != parameters.end();
|
|
424
379
|
++it) {
|
|
425
|
-
|
|
380
|
+
|
|
426
381
|
// Naive check whether parameter is present in URI Template
|
|
427
382
|
if (resource.uriTemplate.find(it->name) == std::string::npos) {
|
|
383
|
+
|
|
428
384
|
// WARN: parameter name not present
|
|
429
385
|
std::stringstream ss;
|
|
430
386
|
ss << "parameter '" << it->name << "' not specified in ";
|
|
431
|
-
|
|
387
|
+
|
|
388
|
+
if (!resource.name.empty()) {
|
|
432
389
|
ss << "'" << resource.name << "' ";
|
|
390
|
+
}
|
|
391
|
+
|
|
433
392
|
ss << "its '" << resource.uriTemplate << "' URI template";
|
|
434
393
|
|
|
435
|
-
|
|
394
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
395
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
436
396
|
LogicalErrorWarning,
|
|
437
|
-
|
|
397
|
+
sourceMap));
|
|
438
398
|
}
|
|
439
399
|
}
|
|
440
400
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
GetResourceSignature(*cur, resource.name, resource.uriTemplate, method);
|
|
450
|
-
|
|
451
|
-
// Parse as a resource action abbreviation
|
|
452
|
-
return HandleAction(section, cur, parser, resource, true);
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
static ParseSectionResult HandleAction(const BlueprintSection& section,
|
|
456
|
-
const BlockIterator& cur,
|
|
457
|
-
BlueprintParserCore& parser,
|
|
458
|
-
Resource& resource,
|
|
459
|
-
bool abbrev = false)
|
|
460
|
-
{
|
|
461
|
-
Action action;
|
|
462
|
-
ParseSectionResult result = ActionParser::Parse(cur,
|
|
463
|
-
section.bounds.second,
|
|
464
|
-
section,
|
|
465
|
-
parser,
|
|
466
|
-
action);
|
|
467
|
-
if (result.first.error.code != Error::OK)
|
|
468
|
-
return result;
|
|
469
|
-
|
|
470
|
-
if (!abbrev) {
|
|
471
|
-
Name name;
|
|
472
|
-
HTTPMethod httpMethod;
|
|
473
|
-
ActionSignature actionSignature = GetActionSignature(*cur, name, httpMethod);
|
|
474
|
-
|
|
475
|
-
if (actionSignature == MethodURIActionSignature) {
|
|
476
|
-
// WARN: ignoring extraneous content in action header
|
|
477
|
-
std::stringstream ss;
|
|
478
|
-
ss << "ignoring additional content in method header '" << cur->content << "'";
|
|
479
|
-
ss << ", expected method-only e.g. '# " << action.method << "'";
|
|
480
|
-
|
|
481
|
-
SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, parser.sourceData);
|
|
482
|
-
result.first.warnings.push_back(Warning(ss.str(),
|
|
483
|
-
IgnoringWarning,
|
|
484
|
-
sourceBlock));
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
Collection<Action>::iterator duplicate = FindAction(resource, action);
|
|
489
|
-
if (duplicate != resource.actions.end()) {
|
|
490
|
-
|
|
491
|
-
// WARN: duplicate method
|
|
492
|
-
std::stringstream ss;
|
|
493
|
-
ss << "action with method '" << action.method << "' already defined for resource '";
|
|
494
|
-
ss << resource.uriTemplate << "'";
|
|
495
|
-
|
|
496
|
-
SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, parser.sourceData);
|
|
497
|
-
result.first.warnings.push_back(Warning(ss.str(),
|
|
498
|
-
DuplicateWarning,
|
|
499
|
-
sourceBlock));
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// Check Eligibility
|
|
503
|
-
if (!action.parameters.empty())
|
|
504
|
-
CheckParametersEligibility(resource, action.parameters, cur->sourceMap, parser.sourceData, result.first);
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
// Check for header duplictes
|
|
508
|
-
DeepCheckHeaderDuplicates(resource, action, cur->sourceMap, parser.sourceData, result.first);
|
|
509
|
-
|
|
510
|
-
if (action.examples.empty() ||
|
|
511
|
-
action.examples.front().responses.empty()) {
|
|
512
|
-
// WARN: method has no response
|
|
513
|
-
std::stringstream ss;
|
|
514
|
-
ss << "no response defined for '" << action.method << " " << resource.uriTemplate << "'";
|
|
515
|
-
|
|
516
|
-
SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, parser.sourceData);
|
|
517
|
-
result.first.warnings.push_back(Warning(ss.str(),
|
|
518
|
-
EmptyDefinitionWarning,
|
|
519
|
-
sourceBlock));
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
resource.actions.push_back(action);
|
|
523
|
-
return result;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
static void DeepCheckHeaderDuplicates(const Resource& resource,
|
|
527
|
-
const Action& action,
|
|
528
|
-
const SourceDataBlock& sourceMap,
|
|
529
|
-
const SourceData& sourceData,
|
|
530
|
-
Result& result) {
|
|
531
|
-
|
|
532
|
-
if (action.examples.empty())
|
|
533
|
-
return;
|
|
534
|
-
|
|
535
|
-
CheckHeaderDuplicates(resource, action, sourceMap, sourceData, result);
|
|
536
|
-
for (Collection<Request>::const_iterator it = action.examples.front().requests.begin();
|
|
537
|
-
it != action.examples.front().requests.end();
|
|
538
|
-
++it) {
|
|
539
|
-
|
|
540
|
-
CheckHeaderDuplicates(resource, *it, sourceMap, sourceData, result);
|
|
541
|
-
}
|
|
542
|
-
for (Collection<Response>::const_iterator it = action.examples.front().responses.begin();
|
|
543
|
-
it != action.examples.front().responses.end();
|
|
544
|
-
++it) {
|
|
545
|
-
|
|
546
|
-
CheckHeaderDuplicates(resource, *it, sourceMap, sourceData, result);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// Check whether abbreviated resource action isn't followed by an
|
|
551
|
-
// action header which would imply possible additional method intended.
|
|
552
|
-
static void CheckAmbiguousMethod(const BlueprintSection& section,
|
|
553
|
-
const BlockIterator& cur,
|
|
554
|
-
const Resource& resource,
|
|
555
|
-
const SourceData& sourceData,
|
|
556
|
-
Result& result) {
|
|
557
|
-
|
|
558
|
-
if (cur == section.bounds.second ||
|
|
559
|
-
cur->type != HeaderBlockType)
|
|
560
|
-
return;
|
|
561
|
-
|
|
562
|
-
Name name;
|
|
563
|
-
HTTPMethod method;
|
|
564
|
-
ActionSignature actionSignature = GetActionSignature(*cur, name, method);
|
|
565
|
-
if (actionSignature == MethodActionSignature ||
|
|
566
|
-
actionSignature == NamedActionSignature) {
|
|
567
|
-
// WARN: ignoring possible method header
|
|
568
|
-
std::stringstream ss;
|
|
569
|
-
ss << "unexpected action '" << cur->content << "', ";
|
|
570
|
-
ss << "to the define muliple actions for the '" << resource.uriTemplate << "' resource omit the HTTP method in its definition, ";
|
|
571
|
-
ss << "e.g. '# " << resource.uriTemplate << "'";
|
|
572
|
-
|
|
573
|
-
SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, sourceData);
|
|
574
|
-
result.warnings.push_back(Warning(ss.str(),
|
|
575
|
-
IgnoringWarning,
|
|
576
|
-
sourceBlock));
|
|
577
|
-
}
|
|
401
|
+
|
|
402
|
+
/** Finds an action inside an actions collection */
|
|
403
|
+
static ActionIterator findAction(const Actions& actions,
|
|
404
|
+
const Action& action) {
|
|
405
|
+
|
|
406
|
+
return std::find_if(actions.begin(),
|
|
407
|
+
actions.end(),
|
|
408
|
+
std::bind2nd(MatchAction<Action>(), action));
|
|
578
409
|
}
|
|
579
410
|
};
|
|
580
|
-
|
|
581
|
-
|
|
411
|
+
|
|
412
|
+
/** Resource Section Parser */
|
|
413
|
+
typedef SectionParser<Resource, HeaderSectionAdapter> ResourceParser;
|
|
582
414
|
}
|
|
583
415
|
|
|
584
416
|
#endif
|