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
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
//
|
|
2
|
+
// HeaderParser.h
|
|
3
|
+
// snowcrash
|
|
4
|
+
//
|
|
5
|
+
// Created by Zdenek Nemec on 5/22/13.
|
|
6
|
+
// Copyright (c) 2013 Apiary Inc. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
#ifndef SNOWCRASH_HEADERPARSER_H
|
|
10
|
+
#define SNOWCRASH_HEADERPARSER_H
|
|
11
|
+
|
|
12
|
+
#include "SectionParser.h"
|
|
13
|
+
#include "RegexMatch.h"
|
|
14
|
+
#include "CodeBlockUtility.h"
|
|
15
|
+
#include "StringUtility.h"
|
|
16
|
+
#include "BlueprintUtility.h"
|
|
17
|
+
|
|
18
|
+
namespace snowcrash {
|
|
19
|
+
|
|
20
|
+
/** Headers matching regex */
|
|
21
|
+
const char* const HeadersRegex = "^[[:blank:]]*[Hh]eaders?[[:blank:]]*$";
|
|
22
|
+
|
|
23
|
+
/** Internal type alias for collection of HTTP headers */
|
|
24
|
+
typedef Collection<Header>::type Headers;
|
|
25
|
+
|
|
26
|
+
/** Header Iterator in its containment group */
|
|
27
|
+
typedef Collection<Header>::const_iterator HeaderIterator;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Headers Section Processor
|
|
31
|
+
*/
|
|
32
|
+
template<>
|
|
33
|
+
struct SectionProcessor<Headers> : public SectionProcessorBase<Headers> {
|
|
34
|
+
|
|
35
|
+
static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
|
|
36
|
+
const MarkdownNodes& siblings,
|
|
37
|
+
SectionParserData& pd,
|
|
38
|
+
SectionLayout& layout,
|
|
39
|
+
Report& report,
|
|
40
|
+
Headers& out) {
|
|
41
|
+
|
|
42
|
+
mdp::ByteBuffer content;
|
|
43
|
+
CodeBlockUtility::signatureContentAsCodeBlock(node, pd, report, content);
|
|
44
|
+
|
|
45
|
+
headersFromContent(node, content, pd, report, out);
|
|
46
|
+
|
|
47
|
+
return ++MarkdownNodeIterator(node);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static MarkdownNodeIterator processDescription(const MarkdownNodeIterator& node,
|
|
51
|
+
const MarkdownNodes& siblings,
|
|
52
|
+
SectionParserData& pd,
|
|
53
|
+
Report& report,
|
|
54
|
+
Headers& out) {
|
|
55
|
+
return node;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static MarkdownNodeIterator processContent(const MarkdownNodeIterator& node,
|
|
59
|
+
const MarkdownNodes& siblings,
|
|
60
|
+
SectionParserData& pd,
|
|
61
|
+
Report& report,
|
|
62
|
+
Headers& out) {
|
|
63
|
+
|
|
64
|
+
mdp::ByteBuffer content;
|
|
65
|
+
CodeBlockUtility::contentAsCodeBlock(node, pd, report, content);
|
|
66
|
+
|
|
67
|
+
headersFromContent(node, content, pd, report, out);
|
|
68
|
+
|
|
69
|
+
return ++MarkdownNodeIterator(node);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static bool isDescriptionNode(const MarkdownNodeIterator& node,
|
|
73
|
+
SectionType sectionType) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static bool isContentNode(const MarkdownNodeIterator& node,
|
|
78
|
+
SectionType sectionType) {
|
|
79
|
+
|
|
80
|
+
return (SectionKeywordSignature(node) == UndefinedSectionType);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static SectionType sectionType(const MarkdownNodeIterator& node) {
|
|
84
|
+
|
|
85
|
+
if (node->type == mdp::ListItemMarkdownNodeType
|
|
86
|
+
&& !node->children().empty()) {
|
|
87
|
+
|
|
88
|
+
mdp::ByteBuffer subject = node->children().front().text;
|
|
89
|
+
mdp::ByteBuffer signature;
|
|
90
|
+
mdp::ByteBuffer remainingContent;
|
|
91
|
+
|
|
92
|
+
signature = GetFirstLine(subject, remainingContent);
|
|
93
|
+
TrimString(signature);
|
|
94
|
+
|
|
95
|
+
if (RegexMatch(signature, HeadersRegex))
|
|
96
|
+
return HeadersSectionType;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return UndefinedSectionType;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static void finalize(const MarkdownNodeIterator& node,
|
|
103
|
+
SectionParserData& pd,
|
|
104
|
+
Report& report,
|
|
105
|
+
Headers& out) {
|
|
106
|
+
|
|
107
|
+
if (out.empty()) {
|
|
108
|
+
|
|
109
|
+
// WARN: No headers defined
|
|
110
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
111
|
+
report.warnings.push_back(Warning("no headers specified",
|
|
112
|
+
FormattingWarning,
|
|
113
|
+
sourceMap));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Retrieve headers from content */
|
|
118
|
+
static void headersFromContent(const MarkdownNodeIterator& node,
|
|
119
|
+
const mdp::ByteBuffer& content,
|
|
120
|
+
SectionParserData& pd,
|
|
121
|
+
Report& report,
|
|
122
|
+
Headers& headers) {
|
|
123
|
+
std::vector<std::string> lines = Split(content, '\n');
|
|
124
|
+
|
|
125
|
+
for (std::vector<std::string>::iterator line = lines.begin();
|
|
126
|
+
line != lines.end();
|
|
127
|
+
++line) {
|
|
128
|
+
if (TrimString(*line).empty()) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
Header header;
|
|
133
|
+
|
|
134
|
+
if (CodeBlockUtility::keyValueFromLine(*line, header)) {
|
|
135
|
+
if (findHeader(headers, header) != headers.end()) {
|
|
136
|
+
// WARN: duplicate header on this level
|
|
137
|
+
std::stringstream ss;
|
|
138
|
+
|
|
139
|
+
ss << "duplicate definition of '" << header.first << "' header";
|
|
140
|
+
|
|
141
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
142
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
143
|
+
DuplicateWarning,
|
|
144
|
+
sourceMap));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
headers.push_back(header);
|
|
148
|
+
} else {
|
|
149
|
+
// WARN: unable to parse header
|
|
150
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
151
|
+
report.warnings.push_back(Warning("unable to parse HTTP header, expected '<header name> : <header value>', one header per line",
|
|
152
|
+
FormattingWarning,
|
|
153
|
+
sourceMap));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Inject headers into transaction examples requests and responses */
|
|
159
|
+
static void injectDeprecatedHeaders(const Headers& headers,
|
|
160
|
+
Collection<TransactionExample>::type& examples) {
|
|
161
|
+
|
|
162
|
+
for (Collection<TransactionExample>::iterator exampleIt = examples.begin();
|
|
163
|
+
exampleIt != examples.end();
|
|
164
|
+
++exampleIt) {
|
|
165
|
+
|
|
166
|
+
// Requests
|
|
167
|
+
for (Collection<Request>::iterator reqIt = exampleIt->requests.begin();
|
|
168
|
+
reqIt != exampleIt->requests.end();
|
|
169
|
+
++reqIt) {
|
|
170
|
+
|
|
171
|
+
reqIt->headers.insert(reqIt->headers.begin(), headers.begin(), headers.end());
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Responses
|
|
175
|
+
for (Collection<Response>::iterator resIt = exampleIt->responses.begin();
|
|
176
|
+
resIt != exampleIt->responses.end();
|
|
177
|
+
++resIt) {
|
|
178
|
+
|
|
179
|
+
resIt->headers.insert(resIt->headers.begin(), headers.begin(), headers.end());
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Finds a header in its containment group by its key (first) */
|
|
185
|
+
static HeaderIterator findHeader(const Headers& headers,
|
|
186
|
+
const Header& header) {
|
|
187
|
+
return std::find_if(headers.begin(),
|
|
188
|
+
headers.end(),
|
|
189
|
+
std::bind2nd(MatchFirsts<Header>(), header));
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/** Headers Section Parser */
|
|
194
|
+
typedef SectionParser<Headers, ListSectionAdapter> HeadersParser;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
#endif
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ParameterParser.h
|
|
3
|
+
// snowcrash
|
|
4
|
+
//
|
|
5
|
+
// Created by Zdenek Nemec on 9/1/13.
|
|
6
|
+
// Copyright (c) 2013 Apiary Inc. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
#ifndef SNOWCRASH_PARAMETERPARSER_H
|
|
10
|
+
#define SNOWCRASH_PARAMETERPARSER_H
|
|
11
|
+
|
|
12
|
+
#include "SectionParser.h"
|
|
13
|
+
#include "ValuesParser.h"
|
|
14
|
+
#include "RegexMatch.h"
|
|
15
|
+
#include "StringUtility.h"
|
|
16
|
+
|
|
17
|
+
/** Parameter Value regex */
|
|
18
|
+
#define PARAMETER_VALUE "`([^`]+)`"
|
|
19
|
+
|
|
20
|
+
/** Parameter Identifier */
|
|
21
|
+
#define PARAMETER_IDENTIFIER "(([[:alnum:]_.-])*|(%[A-Fa-f0-9]{2})*)+"
|
|
22
|
+
|
|
23
|
+
/** Lead in and out for comma separated values regex */
|
|
24
|
+
#define CSV_LEADINOUT "[[:blank:]]*,?[[:blank:]]*"
|
|
25
|
+
|
|
26
|
+
namespace snowcrash {
|
|
27
|
+
|
|
28
|
+
/** Parameter Required matching regex */
|
|
29
|
+
const char* const ParameterRequiredRegex = "^[[:blank:]]*[Rr]equired[[:blank:]]*$";
|
|
30
|
+
|
|
31
|
+
/** Parameter Optional matching regex */
|
|
32
|
+
const char* const ParameterOptionalRegex = "^[[:blank:]]*[Oo]ptional[[:blank:]]*$";
|
|
33
|
+
|
|
34
|
+
/** Additonal Parameter Traits Example matching regex */
|
|
35
|
+
const char* const AdditionalTraitsExampleRegex = CSV_LEADINOUT "`([^`]*)`" CSV_LEADINOUT;
|
|
36
|
+
|
|
37
|
+
/** Additonal Parameter Traits Use matching regex */
|
|
38
|
+
const char* const AdditionalTraitsUseRegex = CSV_LEADINOUT "([Oo]ptional|[Rr]equired)" CSV_LEADINOUT;
|
|
39
|
+
|
|
40
|
+
/** Additonal Parameter Traits Type matching regex */
|
|
41
|
+
const char* const AdditionalTraitsTypeRegex = CSV_LEADINOUT "([^,]*)" CSV_LEADINOUT;
|
|
42
|
+
|
|
43
|
+
/** Parameter Values matching regex */
|
|
44
|
+
const char* const ParameterValuesRegex = "^[[:blank:]]*[Vv]alues[[:blank:]]*$";
|
|
45
|
+
|
|
46
|
+
/** Values expected content */
|
|
47
|
+
const char* const ExpectedValuesContent = "nested list of possible parameter values, one element per list item e.g. '`value`'";
|
|
48
|
+
|
|
49
|
+
/** Parameter description delimiter */
|
|
50
|
+
const std::string DescriptionIdentifier = "...";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Parameter section processor
|
|
54
|
+
*/
|
|
55
|
+
template<>
|
|
56
|
+
struct SectionProcessor<Parameter> : public SectionProcessorBase<Parameter> {
|
|
57
|
+
|
|
58
|
+
static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
|
|
59
|
+
const MarkdownNodes& siblings,
|
|
60
|
+
SectionParserData& pd,
|
|
61
|
+
SectionLayout& layout,
|
|
62
|
+
Report& report,
|
|
63
|
+
Parameter& out) {
|
|
64
|
+
|
|
65
|
+
mdp::ByteBuffer signature, remainingContent;
|
|
66
|
+
signature = GetFirstLine(node->text, remainingContent);
|
|
67
|
+
|
|
68
|
+
parseSignature(node, pd, signature, report, out);
|
|
69
|
+
|
|
70
|
+
if (!remainingContent.empty()) {
|
|
71
|
+
out.description += "\n" + remainingContent + "\n";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return ++MarkdownNodeIterator(node);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
|
|
79
|
+
const MarkdownNodes& siblings,
|
|
80
|
+
SectionParserData& pd,
|
|
81
|
+
Report& report,
|
|
82
|
+
Parameter& out) {
|
|
83
|
+
|
|
84
|
+
if (pd.sectionContext() != ValuesSectionType) {
|
|
85
|
+
return node;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Check redefinition
|
|
89
|
+
if (!out.values.empty()) {
|
|
90
|
+
// WARN: parameter values are already defined
|
|
91
|
+
std::stringstream ss;
|
|
92
|
+
ss << "overshadowing previous 'values' definition";
|
|
93
|
+
ss << " for parameter '" << out.name << "'";
|
|
94
|
+
|
|
95
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
96
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
97
|
+
RedefinitionWarning,
|
|
98
|
+
sourceMap));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Clear any previous values
|
|
102
|
+
out.values.clear();
|
|
103
|
+
|
|
104
|
+
ValuesParser::parse(node, siblings, pd, report, out.values);
|
|
105
|
+
|
|
106
|
+
if (out.values.empty()) {
|
|
107
|
+
// WARN: empty definition
|
|
108
|
+
std::stringstream ss;
|
|
109
|
+
ss << "no possible values specified for parameter '" << out.name << "'";
|
|
110
|
+
|
|
111
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
112
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
113
|
+
EmptyDefinitionWarning,
|
|
114
|
+
sourceMap));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if ((!out.exampleValue.empty() || !out.defaultValue.empty()) &&
|
|
118
|
+
!out.values.empty()) {
|
|
119
|
+
|
|
120
|
+
checkExampleAndDefaultValue(node, pd, report, out);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return ++MarkdownNodeIterator(node);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static SectionType sectionType(const MarkdownNodeIterator& node) {
|
|
127
|
+
|
|
128
|
+
if (node->type == mdp::ListItemMarkdownNodeType
|
|
129
|
+
&& !node->children().empty()) {
|
|
130
|
+
|
|
131
|
+
mdp::ByteBuffer subject, remainingContent;
|
|
132
|
+
subject = GetFirstLine(node->children().front().text, remainingContent);
|
|
133
|
+
TrimString(subject);
|
|
134
|
+
|
|
135
|
+
if (isValidParameterSignature(subject)) {
|
|
136
|
+
return ParameterSectionType;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return UndefinedSectionType;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
static SectionType nestedSectionType(const MarkdownNodeIterator& node) {
|
|
144
|
+
|
|
145
|
+
return SectionProcessor<Values>::sectionType(node);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static SectionTypes nestedSectionTypes() {
|
|
149
|
+
SectionTypes nested;
|
|
150
|
+
|
|
151
|
+
nested.push_back(ValuesSectionType);
|
|
152
|
+
|
|
153
|
+
return nested;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static void parseSignature(const mdp::MarkdownNodeIterator& node,
|
|
157
|
+
SectionParserData& pd,
|
|
158
|
+
mdp::ByteBuffer& signature,
|
|
159
|
+
Report& report,
|
|
160
|
+
Parameter& parameter) {
|
|
161
|
+
|
|
162
|
+
parameter.use = UndefinedParameterUse;
|
|
163
|
+
|
|
164
|
+
TrimString(signature);
|
|
165
|
+
|
|
166
|
+
CaptureGroups captureGroups;
|
|
167
|
+
|
|
168
|
+
if (isValidParameterSignature(signature)) {
|
|
169
|
+
|
|
170
|
+
mdp::ByteBuffer innerSignature = signature;
|
|
171
|
+
innerSignature = TrimString(innerSignature);
|
|
172
|
+
|
|
173
|
+
size_t firstSpace = innerSignature.find(" ");
|
|
174
|
+
|
|
175
|
+
if (firstSpace == std::string::npos) {
|
|
176
|
+
// Name
|
|
177
|
+
parameter.name = signature;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
parameter.name = innerSignature.substr(0, firstSpace);
|
|
181
|
+
innerSignature = innerSignature.substr(firstSpace + 1);
|
|
182
|
+
size_t descriptionPos = innerSignature.find(snowcrash::DescriptionIdentifier);
|
|
183
|
+
|
|
184
|
+
if (descriptionPos != std::string::npos) {
|
|
185
|
+
// Description
|
|
186
|
+
parameter.description = innerSignature.substr(descriptionPos);
|
|
187
|
+
parameter.description = TrimString(parameter.description.replace(0, snowcrash::DescriptionIdentifier.length(), ""));
|
|
188
|
+
innerSignature = innerSignature.substr(0, descriptionPos);
|
|
189
|
+
innerSignature = TrimString(innerSignature);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
size_t attributesPos = innerSignature.find("(");
|
|
193
|
+
|
|
194
|
+
if (attributesPos != std::string::npos) {
|
|
195
|
+
size_t endOfAttributesPos = innerSignature.find_last_of(")");
|
|
196
|
+
|
|
197
|
+
if (endOfAttributesPos - attributesPos > 1) {
|
|
198
|
+
std::string attributes = innerSignature.substr(attributesPos, endOfAttributesPos - attributesPos);
|
|
199
|
+
attributes = attributes.substr(1);
|
|
200
|
+
parseAdditionalTraits(node, pd, attributes, report, parameter);
|
|
201
|
+
innerSignature = innerSignature.substr(0, attributesPos);
|
|
202
|
+
innerSignature = TrimString(innerSignature);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (innerSignature.length() > 0) {
|
|
207
|
+
// Remove =
|
|
208
|
+
parameter.defaultValue = innerSignature;
|
|
209
|
+
parameter.defaultValue.erase(std::remove(parameter.defaultValue.begin(), parameter.defaultValue.end(), '='), parameter.defaultValue.end());
|
|
210
|
+
parameter.defaultValue.erase(std::remove(parameter.defaultValue.begin(), parameter.defaultValue.end(), '`'), parameter.defaultValue.end());
|
|
211
|
+
parameter.defaultValue = TrimString(parameter.defaultValue);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Check possible required vs default clash
|
|
216
|
+
if (parameter.use != OptionalParameterUse &&
|
|
217
|
+
!parameter.defaultValue.empty()) {
|
|
218
|
+
|
|
219
|
+
// WARN: Required vs default clash
|
|
220
|
+
std::stringstream ss;
|
|
221
|
+
ss << "specifying parameter '" << parameter.name << "' as required supersedes its default value"\
|
|
222
|
+
", declare the parameter as 'optional' to specify its default value";
|
|
223
|
+
|
|
224
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
225
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
226
|
+
LogicalErrorWarning,
|
|
227
|
+
sourceMap));
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
// ERR: unable to parse
|
|
231
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
232
|
+
report.error = Error("unable to parse parameter specification",
|
|
233
|
+
BusinessError,
|
|
234
|
+
sourceMap);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
static void parseAdditionalTraits(const mdp::MarkdownNodeIterator& node,
|
|
239
|
+
SectionParserData& pd,
|
|
240
|
+
mdp::ByteBuffer& traits,
|
|
241
|
+
Report& report,
|
|
242
|
+
Parameter& parameter) {
|
|
243
|
+
|
|
244
|
+
TrimString(traits);
|
|
245
|
+
|
|
246
|
+
CaptureGroups captureGroups;
|
|
247
|
+
|
|
248
|
+
// Cherry pick example value, if any
|
|
249
|
+
if (RegexCapture(traits, AdditionalTraitsExampleRegex, captureGroups) &&
|
|
250
|
+
captureGroups.size() > 1) {
|
|
251
|
+
|
|
252
|
+
parameter.exampleValue = captureGroups[1];
|
|
253
|
+
std::string::size_type pos = traits.find(captureGroups[0]);
|
|
254
|
+
|
|
255
|
+
if (pos != std::string::npos) {
|
|
256
|
+
traits.replace(pos, captureGroups[0].length(), std::string());
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
captureGroups.clear();
|
|
261
|
+
|
|
262
|
+
// Cherry pick use attribute, if any
|
|
263
|
+
if (RegexCapture(traits, AdditionalTraitsUseRegex, captureGroups) &&
|
|
264
|
+
captureGroups.size() > 1) {
|
|
265
|
+
|
|
266
|
+
parameter.use = RegexMatch(captureGroups[1], ParameterOptionalRegex) ? OptionalParameterUse : RequiredParameterUse;
|
|
267
|
+
std::string::size_type pos = traits.find(captureGroups[0]);
|
|
268
|
+
|
|
269
|
+
if (pos != std::string::npos) {
|
|
270
|
+
traits.replace(pos, captureGroups[0].length(), std::string());
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
captureGroups.clear();
|
|
275
|
+
|
|
276
|
+
// Finish with type
|
|
277
|
+
if (RegexCapture(traits, AdditionalTraitsTypeRegex, captureGroups) &&
|
|
278
|
+
captureGroups.size() > 1) {
|
|
279
|
+
|
|
280
|
+
parameter.type = captureGroups[1];
|
|
281
|
+
std::string::size_type pos = traits.find(captureGroups[0]);
|
|
282
|
+
|
|
283
|
+
if (pos != std::string::npos) {
|
|
284
|
+
traits.replace(pos, captureGroups[0].length(), std::string());
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Check what is left
|
|
289
|
+
TrimString(traits);
|
|
290
|
+
|
|
291
|
+
if (!traits.empty()) {
|
|
292
|
+
// WARN: Additional parameters traits warning
|
|
293
|
+
std::stringstream ss;
|
|
294
|
+
ss << "unable to parse additional parameter traits";
|
|
295
|
+
ss << ", expected '([required | optional], [<type>], [`<example value>`])'";
|
|
296
|
+
ss << ", e.g. '(optional, string, `Hello World`)'";
|
|
297
|
+
|
|
298
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
299
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
300
|
+
FormattingWarning,
|
|
301
|
+
sourceMap));
|
|
302
|
+
|
|
303
|
+
parameter.type.clear();
|
|
304
|
+
parameter.exampleValue.clear();
|
|
305
|
+
parameter.use = UndefinedParameterUse;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
static void checkExampleAndDefaultValue(const mdp::MarkdownNodeIterator& node,
|
|
310
|
+
SectionParserData& pd,
|
|
311
|
+
Report& report,
|
|
312
|
+
Parameter& parameter) {
|
|
313
|
+
|
|
314
|
+
bool isExampleFound = false;
|
|
315
|
+
bool isDefaultFound = false;
|
|
316
|
+
|
|
317
|
+
std::stringstream ss;
|
|
318
|
+
bool printWarning = false;
|
|
319
|
+
|
|
320
|
+
for (Collection<Value>::iterator it = parameter.values.begin();
|
|
321
|
+
it != parameter.values.end();
|
|
322
|
+
++it) {
|
|
323
|
+
|
|
324
|
+
if (parameter.exampleValue == *it) {
|
|
325
|
+
isExampleFound = true;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (parameter.defaultValue == *it) {
|
|
329
|
+
isDefaultFound = true;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if(!parameter.exampleValue.empty() &&
|
|
334
|
+
!isExampleFound) {
|
|
335
|
+
|
|
336
|
+
// WARN: missing example in values.
|
|
337
|
+
ss << "the example value '" << parameter.exampleValue << "' of parameter '"<< parameter.name <<"' is not in its list of expected values";
|
|
338
|
+
printWarning = true;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if(!parameter.defaultValue.empty() &&
|
|
342
|
+
!isDefaultFound) {
|
|
343
|
+
|
|
344
|
+
// WARN: missing default in values.
|
|
345
|
+
ss << "the default value '" << parameter.defaultValue << "' of parameter '"<< parameter.name <<"' is not in its list of expected values";
|
|
346
|
+
printWarning = true;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (printWarning) {
|
|
350
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
|
351
|
+
report.warnings.push_back(Warning(ss.str(),
|
|
352
|
+
LogicalErrorWarning,
|
|
353
|
+
sourceMap));
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** Determine if a signature is a valid parameter*/
|
|
358
|
+
static bool isValidParameterSignature(const mdp::ByteBuffer& signature) {
|
|
359
|
+
|
|
360
|
+
mdp::ByteBuffer innerSignature = signature;
|
|
361
|
+
innerSignature = TrimString(innerSignature);
|
|
362
|
+
|
|
363
|
+
if (innerSignature.length() == 0) {
|
|
364
|
+
return false; // Empty string, invalid
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
size_t firstSpace = innerSignature.find(" ");
|
|
368
|
+
|
|
369
|
+
if (firstSpace == std::string::npos) {
|
|
370
|
+
return RegexMatch(innerSignature, "^" PARAMETER_IDENTIFIER "$");
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
std::string paramName = innerSignature.substr(0, firstSpace);
|
|
374
|
+
|
|
375
|
+
if (!RegexMatch(paramName, "^" PARAMETER_IDENTIFIER "$")) {
|
|
376
|
+
return false; // Invalid param name
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Remove param name
|
|
380
|
+
innerSignature = innerSignature.substr(firstSpace + 1);
|
|
381
|
+
size_t descriptionPos = innerSignature.find(snowcrash::DescriptionIdentifier);
|
|
382
|
+
|
|
383
|
+
// Remove description
|
|
384
|
+
if (descriptionPos != std::string::npos) {
|
|
385
|
+
innerSignature = innerSignature.substr(0, descriptionPos);
|
|
386
|
+
innerSignature = TrimString(innerSignature);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
size_t attributesPos = innerSignature.find("(");
|
|
390
|
+
|
|
391
|
+
if (attributesPos != std::string::npos) {
|
|
392
|
+
size_t endOfAttributesPos = innerSignature.find_last_of(")");
|
|
393
|
+
|
|
394
|
+
if (endOfAttributesPos == std::string::npos) {
|
|
395
|
+
return false; // Expecting close of attributes
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Remove attributes
|
|
399
|
+
innerSignature = innerSignature.substr(0, attributesPos);
|
|
400
|
+
innerSignature = TrimString(innerSignature);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (innerSignature.length() == 0) {
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (innerSignature.substr(0,1) == "=") {
|
|
408
|
+
innerSignature = innerSignature.substr(1);
|
|
409
|
+
innerSignature = TrimString(innerSignature);
|
|
410
|
+
|
|
411
|
+
if (innerSignature.length() == 0) {
|
|
412
|
+
return false; // No default value
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (innerSignature.substr(0,1) == "`" && innerSignature.substr(innerSignature.length()-1,1) == "`") {
|
|
416
|
+
return true;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
/** Parameter Section Parser */
|
|
426
|
+
typedef SectionParser<Parameter, ListSectionAdapter> ParameterParser;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
#endif
|