redsnow 0.1.6 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,87 +1,97 @@
|
|
1
1
|
//
|
2
2
|
// MarkdownParser.h
|
3
|
-
//
|
3
|
+
// markdownparser
|
4
4
|
//
|
5
|
-
// Created by Zdenek Nemec on 4/
|
6
|
-
// Copyright (c)
|
5
|
+
// Created by Zdenek Nemec on 4/18/14.
|
6
|
+
// Copyright (c) 2014 Apiary Inc. All rights reserved.
|
7
7
|
//
|
8
8
|
|
9
|
-
#ifndef
|
10
|
-
#define
|
9
|
+
#ifndef MARKDOWNPARSER_MARKDOWNPARSER_H
|
10
|
+
#define MARKDOWNPARSER_MARKDOWNPARSER_H
|
11
11
|
|
12
|
-
#include "
|
13
|
-
#include "
|
14
|
-
#include "MarkdownBlock.h"
|
12
|
+
#include "ByteBuffer.h"
|
13
|
+
#include "MarkdownNode.h"
|
15
14
|
#include "markdown.h"
|
16
15
|
|
17
|
-
namespace
|
16
|
+
namespace mdp {
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
/**
|
19
|
+
* GitHub-flavored Markdown Parser
|
20
|
+
*/
|
22
21
|
class MarkdownParser {
|
23
22
|
public:
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
MarkdownParser();
|
24
|
+
MarkdownParser(const MarkdownParser&);
|
25
|
+
MarkdownParser& operator=(const MarkdownParser&);
|
26
|
+
|
27
|
+
/**
|
28
|
+
* \brief Parse source buffer
|
29
|
+
*
|
30
|
+
* \param source Markdown source data to be parsed
|
31
|
+
* \param ast Parsed AST (root node)
|
32
|
+
*/
|
33
|
+
void parse(const ByteBuffer& source, MarkdownNode& ast);
|
28
34
|
|
29
|
-
// Parse source Markdown into Markdown AST
|
30
|
-
void parse(const SourceData& source, Result& result, MarkdownBlock::Stack& markdown);
|
31
|
-
|
32
35
|
private:
|
36
|
+
MarkdownNode* m_workingNode;
|
37
|
+
bool m_listBlockContext;
|
38
|
+
const ByteBuffer* m_source;
|
39
|
+
size_t m_sourceLength;
|
40
|
+
|
41
|
+
static const size_t OutputUnitSize;
|
42
|
+
static const size_t MaxNesting;
|
43
|
+
static const int ParserExtensions;
|
44
|
+
|
33
45
|
typedef sd_callbacks RenderCallbacks;
|
34
|
-
typedef void * RenderCallbackData;
|
35
|
-
|
36
46
|
RenderCallbacks renderCallbacks();
|
37
|
-
RenderCallbackData renderCallbackData();
|
38
47
|
|
39
|
-
|
48
|
+
typedef void * RenderCallbackData;
|
49
|
+
RenderCallbackData renderCallbackData();
|
40
50
|
|
41
51
|
// Header
|
42
52
|
static void renderHeader(struct buf *ob, const struct buf *text, int level, void *opaque);
|
43
|
-
void renderHeader(const
|
53
|
+
void renderHeader(const ByteBuffer& text, int level);
|
44
54
|
|
45
55
|
// List
|
46
56
|
static void beginList(int flags, void *opaque);
|
47
57
|
void beginList(int flags);
|
48
58
|
|
49
59
|
static void renderList(struct buf *ob, const struct buf *text, int flags, void *opaque);
|
50
|
-
void renderList(const
|
60
|
+
void renderList(const ByteBuffer& text, int flags);
|
51
61
|
|
52
62
|
// List item
|
53
63
|
static void beginListItem(int flags, void *opaque);
|
54
64
|
void beginListItem(int flags);
|
55
65
|
|
56
66
|
static void renderListItem(struct buf *ob, const struct buf *text, int flags, void *opaque);
|
57
|
-
void renderListItem(const
|
67
|
+
void renderListItem(const ByteBuffer& text, int flags);
|
58
68
|
|
59
69
|
// Code block
|
60
70
|
static void renderBlockCode(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque);
|
61
|
-
void renderBlockCode(const
|
71
|
+
void renderBlockCode(const ByteBuffer& text, const ByteBuffer& language);
|
62
72
|
|
63
73
|
// Paragraph
|
64
74
|
static void renderParagraph(struct buf *ob, const struct buf *text, void *opaque);
|
65
|
-
void renderParagraph(const
|
75
|
+
void renderParagraph(const ByteBuffer& text);
|
66
76
|
|
67
77
|
// Horizontal Rule
|
68
78
|
static void renderHorizontalRule(struct buf *ob, void *opaque);
|
69
79
|
void renderHorizontalRule();
|
70
|
-
|
80
|
+
|
71
81
|
// HTML
|
72
82
|
static void renderHTML(struct buf *ob, const struct buf *text, void *opaque);
|
73
|
-
void renderHTML(const
|
74
|
-
|
83
|
+
void renderHTML(const ByteBuffer& text);
|
84
|
+
|
75
85
|
// Quote
|
76
86
|
static void beginQuote(void *opaque);
|
77
87
|
void beginQuote();
|
78
|
-
|
88
|
+
|
79
89
|
static void renderQuote(struct buf *ob, const struct buf *text, void *opaque);
|
80
90
|
void renderQuote(const std::string& text);
|
81
91
|
|
82
92
|
// Source maps
|
83
93
|
static void blockDidParse(const src_map* map, const uint8_t *txt_data, size_t size, void *opaque);
|
84
|
-
void blockDidParse(const
|
94
|
+
void blockDidParse(const BytesRangeSet& sourceMap);
|
85
95
|
};
|
86
96
|
}
|
87
97
|
|
data/ext/snowcrash/snowcrash.gyp
CHANGED
@@ -2,25 +2,52 @@
|
|
2
2
|
"includes": [
|
3
3
|
"common.gypi"
|
4
4
|
],
|
5
|
-
|
6
5
|
'targets' : [
|
7
6
|
{
|
8
|
-
'target_name': '
|
7
|
+
'target_name': 'libsundown',
|
9
8
|
'type': 'static_library',
|
10
9
|
'include_dirs': [
|
11
|
-
'sundown/src',
|
12
|
-
'sundown/html'
|
10
|
+
'ext/markdown-parser/ext/sundown/src',
|
11
|
+
'ext/markdown-parser/ext/sundown/html'
|
13
12
|
],
|
14
13
|
'sources': [
|
15
|
-
'sundown/src/autolink.c',
|
16
|
-
'sundown/src/
|
17
|
-
'sundown/
|
18
|
-
'sundown/
|
19
|
-
'sundown/
|
20
|
-
'sundown/
|
21
|
-
'sundown/src/markdown.
|
22
|
-
'sundown/src/
|
23
|
-
'sundown/src/src_map.
|
14
|
+
'ext/markdown-parser/ext/sundown/src/autolink.c',
|
15
|
+
'ext/markdown-parser/ext/sundown/src/autolink.h',
|
16
|
+
'ext/markdown-parser/ext/sundown/src/buffer.c',
|
17
|
+
'ext/markdown-parser/ext/sundown/src/buffer.h',
|
18
|
+
'ext/markdown-parser/ext/sundown/src/html_blocks.h',
|
19
|
+
'ext/markdown-parser/ext/sundown/src/markdown.c',
|
20
|
+
'ext/markdown-parser/ext/sundown/src/markdown.h',
|
21
|
+
'ext/markdown-parser/ext/sundown/src/src_map.c',
|
22
|
+
'ext/markdown-parser/ext/sundown/src/src_map.h',
|
23
|
+
'ext/markdown-parser/ext/sundown/src/stack.c',
|
24
|
+
'ext/markdown-parser/ext/sundown/src/stack.h',
|
25
|
+
'ext/markdown-parser/ext/sundown/html/houdini.h',
|
26
|
+
'ext/markdown-parser/ext/sundown/html/houdini_href_e.c',
|
27
|
+
'ext/markdown-parser/ext/sundown/html/houdini_html_e.c',
|
28
|
+
'ext/markdown-parser/ext/sundown/html/html.c',
|
29
|
+
'ext/markdown-parser/ext/sundown/html/html.h',
|
30
|
+
'ext/markdown-parser/ext/sundown/html/html_smartypants.c'
|
31
|
+
]
|
32
|
+
},
|
33
|
+
{
|
34
|
+
'target_name': 'libmarkdownparser',
|
35
|
+
'type': 'static_library',
|
36
|
+
'include_dirs': [
|
37
|
+
'ext/markdown-parser/ext/sundown/src',
|
38
|
+
'ext/markdown-parser/ext/sundown/html'
|
39
|
+
'ext/markdown-parser/src',
|
40
|
+
],
|
41
|
+
'sources': [
|
42
|
+
'ext/markdown-parser/src/ByteBuffer.cc',
|
43
|
+
'ext/markdown-parser/src/ByteBuffer.h',
|
44
|
+
'ext/markdown-parser/src/MarkdownNode.cc',
|
45
|
+
'ext/markdown-parser/src/MarkdownNode.h',
|
46
|
+
'ext/markdown-parser/src/MarkdownParser.cc',
|
47
|
+
'ext/markdown-parser/src/MarkdownParser.h'
|
48
|
+
],
|
49
|
+
'dependencies': [
|
50
|
+
'libsundown'
|
24
51
|
]
|
25
52
|
},
|
26
53
|
{
|
@@ -28,34 +55,64 @@
|
|
28
55
|
'type': '<(libsnowcrash_type)',
|
29
56
|
'include_dirs': [
|
30
57
|
'src',
|
31
|
-
'
|
32
|
-
'sundown/src
|
58
|
+
'ext/markdown-parser/src',
|
59
|
+
'ext/markdown-parser/ext/sundown/src',
|
60
|
+
'ext/markdown-parser/ext/sundown/html'
|
33
61
|
],
|
34
62
|
'sources': [
|
63
|
+
'src/CBlueprint.cc',
|
64
|
+
'src/CBlueprint.h',
|
65
|
+
'src/CSourceAnnotation.cc',
|
66
|
+
'src/CSourceAnnotation.h',
|
35
67
|
'src/HTTP.cc',
|
36
|
-
'src/
|
37
|
-
'src/
|
38
|
-
'src/
|
39
|
-
'src/ParserCore.cc',
|
40
|
-
'src/RegexMatch.h',
|
68
|
+
'src/HTTP.h',
|
69
|
+
'src/Section.cc',
|
70
|
+
'src/Section.h',
|
41
71
|
'src/Serialize.cc',
|
42
72
|
'src/Serialize.h',
|
43
73
|
'src/SerializeJSON.cc',
|
74
|
+
'src/SerializeJSON.h',
|
44
75
|
'src/SerializeYAML.cc',
|
45
|
-
'src/
|
76
|
+
'src/SerializeYAML.h',
|
77
|
+
'src/Signature.cc',
|
78
|
+
'src/Signature.h',
|
46
79
|
'src/snowcrash.cc',
|
80
|
+
'src/snowcrash.h',
|
47
81
|
'src/csnowcrash.cc',
|
48
|
-
'src/
|
49
|
-
'src/
|
82
|
+
'src/csnowcrash.h',
|
83
|
+
'src/UriTemplateParser.cc',
|
84
|
+
'src/UriTemplateParser.h',
|
85
|
+
'src/PayloadParser.h',
|
86
|
+
'src/SectionParserData.h',
|
87
|
+
'src/ActionParser.h',
|
88
|
+
'src/AssetParser.h',
|
89
|
+
'src/Blueprint.h',
|
90
|
+
'src/BlueprintParser.h',
|
91
|
+
'src/BlueprintUtility.h',
|
92
|
+
'src/CodeBlockUtility.h',
|
93
|
+
'src/HeadersParser.h',
|
94
|
+
'src/ParameterParser.h',
|
95
|
+
'src/ParametersParser.h',
|
96
|
+
'src/Platform.h',
|
97
|
+
'src/RegexMatch.h',
|
98
|
+
'src/ResourceGroupParser.h',
|
99
|
+
'src/ResourceParser.h',
|
100
|
+
'src/SectionParser.h',
|
101
|
+
'src/SectionProcessor.h',
|
102
|
+
'src/SourceAnnotation.h',
|
103
|
+
'src/StringUtility.h',
|
104
|
+
'src/SymbolTable.h',
|
105
|
+
'src/ValuesParser.h',
|
106
|
+
'src/Version.h'
|
50
107
|
],
|
51
108
|
'conditions': [
|
52
|
-
[ 'OS=="win"',
|
53
|
-
{ 'sources': [ 'src/win/RegexMatch.cc' ] },
|
109
|
+
[ 'OS=="win"',
|
110
|
+
{ 'sources': [ 'src/win/RegexMatch.cc' ] },
|
54
111
|
{ 'sources': [ 'src/posix/RegexMatch.cc' ] } # OS != Windows
|
55
112
|
]
|
56
113
|
],
|
57
114
|
'dependencies': [
|
58
|
-
'
|
115
|
+
'libmarkdownparser'
|
59
116
|
]
|
60
117
|
},
|
61
118
|
{
|
@@ -65,45 +122,44 @@
|
|
65
122
|
'src',
|
66
123
|
'test',
|
67
124
|
'test/vendor/Catch/include',
|
68
|
-
'
|
69
|
-
'sundown/src
|
125
|
+
'ext/markdown-parser/src',
|
126
|
+
'ext/markdown-parser/ext/sundown/src',
|
127
|
+
'ext/markdown-parser/ext/sundown/html'
|
70
128
|
],
|
71
129
|
'sources': [
|
72
130
|
'test/test-ActionParser.cc',
|
73
131
|
'test/test-AssetParser.cc',
|
74
132
|
'test/test-Blueprint.cc',
|
75
133
|
'test/test-BlueprintParser.cc',
|
76
|
-
'test/test-
|
134
|
+
'test/test-HeadersParser.cc',
|
77
135
|
'test/test-Indentation.cc',
|
78
|
-
'test/test-
|
79
|
-
'test/test-MarkdownBlock.cc',
|
80
|
-
'test/test-MarkdownParser.cc',
|
81
|
-
'test/test-ParameterDefinitonParser.cc',
|
136
|
+
'test/test-ParameterParser.cc',
|
82
137
|
'test/test-ParametersParser.cc',
|
83
|
-
'test/test-Parser.cc',
|
84
138
|
'test/test-PayloadParser.cc',
|
85
139
|
'test/test-RegexMatch.cc',
|
86
|
-
'test/test-ResouceGroupParser.cc',
|
87
140
|
'test/test-ResourceParser.cc',
|
141
|
+
'test/test-ResourceGroupParser.cc',
|
142
|
+
'test/test-SectionParser.cc',
|
88
143
|
'test/test-SymbolIdentifier.cc',
|
89
144
|
'test/test-SymbolTable.cc',
|
145
|
+
'test/test-UriTemplateParser.cc',
|
146
|
+
'test/test-ValuesParser.cc',
|
90
147
|
'test/test-Warnings.cc',
|
91
148
|
'test/test-csnowcrash.cc',
|
92
|
-
'test/test-UriTemplateParser.cc',
|
93
149
|
'test/test-snowcrash.cc'
|
94
150
|
],
|
95
151
|
'dependencies': [
|
96
152
|
'libsnowcrash',
|
97
|
-
'
|
153
|
+
'libmarkdownparser'
|
98
154
|
]
|
99
155
|
},
|
100
|
-
|
101
156
|
{
|
102
157
|
'target_name': 'snowcrash',
|
103
158
|
'type': 'executable',
|
104
159
|
'include_dirs': [
|
105
160
|
'src',
|
106
161
|
'src/snowcrash',
|
162
|
+
'ext/markdown-parser/src',
|
107
163
|
'cmdline'
|
108
164
|
],
|
109
165
|
'sources': [
|
@@ -111,31 +167,26 @@
|
|
111
167
|
],
|
112
168
|
'dependencies': [
|
113
169
|
'libsnowcrash',
|
114
|
-
'
|
170
|
+
'libmarkdownparser'
|
115
171
|
]
|
116
|
-
}
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
'
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
'dependencies': [
|
134
|
-
'libsnowcrash',
|
135
|
-
'sundown'
|
136
|
-
]
|
137
|
-
}
|
172
|
+
},
|
173
|
+
{
|
174
|
+
'target_name': 'perf-libsnowcrash',
|
175
|
+
'type': 'executable',
|
176
|
+
'include_dirs': [
|
177
|
+
'src',
|
178
|
+
'ext/markdown-parser/src',
|
179
|
+
'cmdline',
|
180
|
+
'test',
|
181
|
+
'test/performance',
|
182
|
+
],
|
183
|
+
'sources': [
|
184
|
+
'test/performance/perf-snowcrash.cc'
|
185
|
+
],
|
186
|
+
'dependencies': [
|
187
|
+
'libsnowcrash',
|
188
|
+
'libmarkdownparser'
|
138
189
|
]
|
139
|
-
}
|
140
|
-
]
|
190
|
+
}
|
191
|
+
]
|
141
192
|
}
|
@@ -9,468 +9,331 @@
|
|
9
9
|
#ifndef SNOWCRASH_ACTIONPARSER_H
|
10
10
|
#define SNOWCRASH_ACTIONPARSER_H
|
11
11
|
|
12
|
-
#include "BlueprintParserCore.h"
|
13
|
-
#include "Blueprint.h"
|
14
|
-
#include "RegexMatch.h"
|
15
|
-
#include "PayloadParser.h"
|
16
|
-
#include "HeaderParser.h"
|
17
|
-
#include "ParametersParser.h"
|
18
12
|
#include "HTTP.h"
|
19
|
-
#include "
|
13
|
+
#include "SectionParser.h"
|
14
|
+
#include "ParametersParser.h"
|
15
|
+
#include "PayloadParser.h"
|
16
|
+
#include "RegexMatch.h"
|
17
|
+
|
18
|
+
namespace snowcrash {
|
20
19
|
|
21
|
-
namespace snowcrashconst {
|
22
|
-
|
23
20
|
/** Nameless action matching regex */
|
24
21
|
const char* const ActionHeaderRegex = "^[[:blank:]]*" HTTP_REQUEST_METHOD "[[:blank:]]*" URI_TEMPLATE "?$";
|
25
|
-
|
22
|
+
|
26
23
|
/** Named action matching regex */
|
27
24
|
const char* const NamedActionHeaderRegex = "^[[:blank:]]*" SYMBOL_IDENTIFIER "\\[" HTTP_REQUEST_METHOD "]$";
|
28
|
-
}
|
29
25
|
|
30
|
-
|
26
|
+
/** Internal type alias for Collection of Action */
|
27
|
+
typedef Collection<Action>::type Actions;
|
28
|
+
|
29
|
+
typedef Collection<Action>::const_iterator ActionIterator;
|
31
30
|
|
32
|
-
|
33
|
-
enum
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
NamedActionSignature // # My Method [GET]
|
31
|
+
/** Action Definition Type */
|
32
|
+
enum ActionType {
|
33
|
+
NotActionType = 0,
|
34
|
+
DependentActionType, /// Action isn't fully defined, depends on parents resource URI
|
35
|
+
CompleteActionType, /// Action is fully defined including its URI
|
36
|
+
UndefinedActionType = -1
|
39
37
|
};
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
38
|
+
|
39
|
+
/**
|
40
|
+
* Action Section processor
|
41
|
+
*/
|
42
|
+
template<>
|
43
|
+
struct SectionProcessor<Action> : public SectionProcessorBase<Action> {
|
44
|
+
|
45
|
+
static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
|
46
|
+
const MarkdownNodes& siblings,
|
47
|
+
SectionParserData& pd,
|
48
|
+
SectionLayout& layout,
|
49
|
+
Report& report,
|
50
|
+
Action& out) {
|
51
|
+
|
52
|
+
actionHTTPMethodAndName(node, out.method, out.name);
|
53
|
+
TrimString(out.name);
|
54
|
+
|
55
|
+
mdp::ByteBuffer remainingContent;
|
56
|
+
GetFirstLine(node->text, remainingContent);
|
57
|
+
|
58
|
+
if (!remainingContent.empty()) {
|
59
|
+
out.description += remainingContent;
|
60
|
+
}
|
61
|
+
|
62
|
+
return ++MarkdownNodeIterator(node);
|
62
63
|
}
|
63
|
-
|
64
|
-
return NoActionSignature;
|
65
|
-
}
|
66
64
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
return false;
|
73
|
-
|
74
|
-
Name name;
|
75
|
-
HTTPMethod method;
|
76
|
-
return GetActionSignature(block, name, method) != NoActionSignature;
|
77
|
-
}
|
78
|
-
|
79
|
-
// Finds an action inside resource
|
80
|
-
FORCEINLINE Collection<Action>::iterator FindAction(Resource& resource,
|
81
|
-
const Action& action) {
|
82
|
-
return std::find_if(resource.actions.begin(),
|
83
|
-
resource.actions.end(),
|
84
|
-
std::bind2nd(MatchAction<Action>(), action));
|
85
|
-
}
|
86
|
-
|
87
|
-
//
|
88
|
-
// Classifier of internal list items, Payload context
|
89
|
-
//
|
90
|
-
template <>
|
91
|
-
FORCEINLINE SectionType ClassifyInternaListBlock<Action>(const BlockIterator& begin,
|
92
|
-
const BlockIterator& end) {
|
93
|
-
if (HasHeaderSignature(begin, end))
|
94
|
-
return HeadersSectionType;
|
95
|
-
|
96
|
-
if (HasParametersSignature(begin, end))
|
97
|
-
return ParametersSectionType;
|
98
|
-
|
99
|
-
Name name;
|
100
|
-
SourceData mediaType;
|
101
|
-
PayloadSignature payload = GetPayloadSignature(begin, end, name, mediaType);
|
102
|
-
if (payload == RequestPayloadSignature)
|
103
|
-
return RequestSectionType;
|
104
|
-
else if (payload == ResponsePayloadSignature)
|
105
|
-
return ResponseSectionType;
|
106
|
-
else if (payload == ObjectPayloadSignature)
|
107
|
-
return ObjectSectionType;
|
108
|
-
else if (payload == ModelPayloadSignature)
|
109
|
-
return ModelSectionType;
|
110
|
-
|
111
|
-
return UndefinedSectionType;
|
112
|
-
}
|
113
|
-
|
114
|
-
/** Children blocks classifier */
|
115
|
-
template <>
|
116
|
-
FORCEINLINE SectionType ClassifyChildrenListBlock<Action>(const BlockIterator& begin,
|
117
|
-
const BlockIterator& end) {
|
118
|
-
|
119
|
-
SectionType type = ClassifyInternaListBlock<Action>(begin, end);
|
120
|
-
if (type != UndefinedSectionType)
|
121
|
-
return type;
|
122
|
-
|
123
|
-
type = ClassifyChildrenListBlock<HeaderCollection>(begin, end);
|
124
|
-
if (type != UndefinedSectionType)
|
125
|
-
return type;
|
126
|
-
|
127
|
-
type = ClassifyChildrenListBlock<ParameterCollection>(begin, end);
|
128
|
-
if (type != UndefinedSectionType)
|
129
|
-
return type;
|
65
|
+
static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
|
66
|
+
const MarkdownNodes& siblings,
|
67
|
+
SectionParserData& pd,
|
68
|
+
Report& report,
|
69
|
+
Action& out) {
|
130
70
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
return UndefinedSectionType;
|
136
|
-
}
|
137
|
-
|
138
|
-
//
|
139
|
-
// Block Classifier, Action Context
|
140
|
-
//
|
141
|
-
template <>
|
142
|
-
FORCEINLINE SectionType ClassifyBlock<Action>(const BlockIterator& begin,
|
143
|
-
const BlockIterator& end,
|
144
|
-
const SectionType& context) {
|
145
|
-
|
146
|
-
if (HasActionSignature(*begin))
|
147
|
-
return (context == UndefinedSectionType) ? ActionSectionType : UndefinedSectionType;
|
148
|
-
|
149
|
-
if (HasResourceSignature(*begin) ||
|
150
|
-
HasResourceGroupSignature(*begin))
|
151
|
-
return UndefinedSectionType;
|
152
|
-
|
153
|
-
SectionType listSection = ClassifyInternaListBlock<Action>(begin, end);
|
154
|
-
if (listSection != UndefinedSectionType)
|
155
|
-
return listSection;
|
156
|
-
|
157
|
-
// Unrecognized list item at this level
|
158
|
-
if (begin->type == ListItemBlockBeginType)
|
159
|
-
return ForeignSectionType;
|
160
|
-
|
161
|
-
return (context == ActionSectionType) ? ActionSectionType : UndefinedSectionType;
|
162
|
-
}
|
163
|
-
|
164
|
-
//
|
165
|
-
// Action SectionType Parser
|
166
|
-
//
|
167
|
-
template<>
|
168
|
-
struct SectionParser<Action> {
|
169
|
-
|
170
|
-
static ParseSectionResult ParseSection(const BlueprintSection& section,
|
171
|
-
const BlockIterator& cur,
|
172
|
-
BlueprintParserCore& parser,
|
173
|
-
Action& action) {
|
174
|
-
|
175
|
-
ParseSectionResult result = std::make_pair(Result(), cur);
|
176
|
-
|
177
|
-
switch (section.type) {
|
178
|
-
case ActionSectionType:
|
179
|
-
result = HandleActionDescriptionBlock(section, cur, parser, action);
|
180
|
-
break;
|
71
|
+
SectionType sectionType = pd.sectionContext();
|
72
|
+
MarkdownNodeIterator cur = node;
|
73
|
+
Payload payload;
|
74
|
+
std::stringstream ss;
|
181
75
|
|
76
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
77
|
+
|
78
|
+
switch (sectionType) {
|
182
79
|
case ParametersSectionType:
|
183
|
-
|
184
|
-
break;
|
80
|
+
return ParametersParser::parse(node, siblings, pd, report, out.parameters);
|
185
81
|
|
186
|
-
case HeadersSectionType:
|
187
|
-
result = HandleDeprecatedHeaders(section, cur, parser, action);
|
188
|
-
break;
|
189
|
-
|
190
82
|
case RequestSectionType:
|
191
|
-
case
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
83
|
+
case RequestBodySectionType:
|
84
|
+
cur = PayloadParser::parse(node, siblings, pd, report, payload);
|
85
|
+
|
86
|
+
if (out.examples.empty() || !out.examples.back().responses.empty()) {
|
87
|
+
TransactionExample transaction;
|
88
|
+
out.examples.push_back(transaction);
|
89
|
+
}
|
90
|
+
|
91
|
+
checkPayload(sectionType, sourceMap, payload, out, report);
|
92
|
+
|
93
|
+
out.examples.back().requests.push_back(payload);
|
201
94
|
break;
|
202
|
-
|
203
|
-
case
|
204
|
-
case
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
parser.sourceData);
|
211
|
-
result.first.error = Error("unexpected model definiton, a model can be only defined in the resource section",
|
212
|
-
SymbolError,
|
213
|
-
sourceBlock);
|
95
|
+
|
96
|
+
case ResponseSectionType:
|
97
|
+
case ResponseBodySectionType:
|
98
|
+
cur = PayloadParser::parse(node, siblings, pd, report, payload);
|
99
|
+
|
100
|
+
if (out.examples.empty()) {
|
101
|
+
TransactionExample transaction;
|
102
|
+
out.examples.push_back(transaction);
|
214
103
|
}
|
104
|
+
|
105
|
+
checkPayload(sectionType, sourceMap, payload, out, report);
|
106
|
+
|
107
|
+
out.examples.back().responses.push_back(payload);
|
215
108
|
break;
|
216
|
-
|
109
|
+
|
110
|
+
case HeadersSectionType:
|
111
|
+
return SectionProcessor<Action>::handleDeprecatedHeaders(node, siblings, pd, report, out.headers);
|
112
|
+
|
217
113
|
default:
|
218
|
-
result.first.error = UnexpectedBlockError(section, cur, parser.sourceData);
|
219
114
|
break;
|
220
115
|
}
|
116
|
+
|
117
|
+
return cur;
|
118
|
+
}
|
119
|
+
|
120
|
+
static bool isUnexpectedNode(const MarkdownNodeIterator& node,
|
121
|
+
SectionType sectionType) {
|
221
122
|
|
222
|
-
|
123
|
+
if ( SectionProcessor<Asset>::sectionType(node) != UndefinedSectionType) {
|
124
|
+
return true;
|
125
|
+
}
|
126
|
+
|
127
|
+
return SectionProcessorBase<Action>::isUnexpectedNode(node, sectionType);
|
223
128
|
}
|
224
129
|
|
225
|
-
static
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
130
|
+
static MarkdownNodeIterator processUnexpectedNode(const MarkdownNodeIterator& node,
|
131
|
+
const MarkdownNodes& siblings,
|
132
|
+
SectionParserData& pd,
|
133
|
+
SectionType& sectionType,
|
134
|
+
Report& report,
|
135
|
+
Action& out) {
|
136
|
+
|
137
|
+
if ((node->type == mdp::ParagraphMarkdownNodeType ||
|
138
|
+
node->type == mdp::CodeMarkdownNodeType) &&
|
139
|
+
(sectionType == ResponseBodySectionType ||
|
140
|
+
sectionType == ResponseSectionType) &&
|
141
|
+
!out.examples.empty() &&
|
142
|
+
!out.examples.back().responses.empty()) {
|
143
|
+
|
144
|
+
CodeBlockUtility::addDanglingAsset(node, pd, sectionType, report, out.examples.back().responses.back().body);
|
145
|
+
|
146
|
+
return ++MarkdownNodeIterator(node);
|
234
147
|
}
|
235
148
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
149
|
+
if ((node->type == mdp::ParagraphMarkdownNodeType ||
|
150
|
+
node->type == mdp::CodeMarkdownNodeType) &&
|
151
|
+
(sectionType == RequestBodySectionType ||
|
152
|
+
sectionType == RequestSectionType) &&
|
153
|
+
!out.examples.empty() &&
|
154
|
+
!out.examples.back().requests.empty()) {
|
241
155
|
|
242
|
-
|
243
|
-
ss << "action is missing a response for ";
|
244
|
-
if (action.examples.back().requests.back().name.empty())
|
245
|
-
ss << "a request";
|
246
|
-
else
|
247
|
-
ss << "the '" << action.examples.back().requests.back().name << "' request";
|
156
|
+
CodeBlockUtility::addDanglingAsset(node, pd, sectionType, report, out.examples.back().requests.back().body);
|
248
157
|
|
249
|
-
|
250
|
-
result.warnings.push_back(Warning(ss.str(),
|
251
|
-
EmptyDefinitionWarning,
|
252
|
-
sourceBlock));
|
158
|
+
return ++MarkdownNodeIterator(node);
|
253
159
|
}
|
254
|
-
}
|
255
|
-
|
256
|
-
static ParseSectionResult HandleActionDescriptionBlock(const BlueprintSection& section,
|
257
|
-
const BlockIterator& cur,
|
258
|
-
BlueprintParserCore& parser,
|
259
|
-
Action& action) {
|
260
160
|
|
261
|
-
|
262
|
-
BlockIterator sectionCur(cur);
|
161
|
+
SectionType assetType = SectionProcessor<Asset>::sectionType(node);
|
263
162
|
|
264
|
-
if (
|
265
|
-
|
163
|
+
if (assetType != UndefinedSectionType) {
|
164
|
+
|
165
|
+
// WARN: Ignoring section
|
166
|
+
std::stringstream ss;
|
167
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
266
168
|
|
267
|
-
|
268
|
-
|
269
|
-
|
169
|
+
ss << "Ignoring " << SectionName(assetType) << " list item, ";
|
170
|
+
ss << SectionName(assetType) << " list item is expected to be indented by 4 spaces or 1 tab";
|
171
|
+
|
172
|
+
report.warnings.push_back(Warning(ss.str(),
|
173
|
+
IgnoringWarning,
|
174
|
+
sourceMap));
|
175
|
+
|
176
|
+
return ++MarkdownNodeIterator(node);
|
270
177
|
}
|
271
178
|
|
272
|
-
|
273
|
-
sectionCur,
|
274
|
-
parser.sourceData,
|
275
|
-
action);
|
276
|
-
return result;
|
179
|
+
return SectionProcessorBase<Action>::processUnexpectedNode(node, siblings, pd, sectionType, report, out);
|
277
180
|
}
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
if (parameters.empty()) {
|
294
|
-
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
295
|
-
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
|
296
|
-
result.first.warnings.push_back(Warning(snowcrashconst::NoParametersMessage,
|
297
|
-
FormattingWarning,
|
298
|
-
sourceBlock));
|
299
|
-
}
|
300
|
-
else {
|
301
|
-
action.parameters.insert(action.parameters.end(), parameters.begin(), parameters.end());
|
181
|
+
|
182
|
+
static SectionType sectionType(const MarkdownNodeIterator& node) {
|
183
|
+
|
184
|
+
if (node->type == mdp::HeaderMarkdownNodeType
|
185
|
+
&& !node->text.empty()) {
|
186
|
+
|
187
|
+
mdp::ByteBuffer subject = node->text;
|
188
|
+
TrimString(subject);
|
189
|
+
|
190
|
+
if (RegexMatch(subject, ActionHeaderRegex) ||
|
191
|
+
RegexMatch(subject, NamedActionHeaderRegex)) {
|
192
|
+
|
193
|
+
return ActionSectionType;
|
194
|
+
}
|
302
195
|
}
|
303
|
-
|
304
|
-
return
|
196
|
+
|
197
|
+
return UndefinedSectionType;
|
305
198
|
}
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
const BlockIterator& cur,
|
317
|
-
BlueprintParserCore& parser,
|
318
|
-
Action& action)
|
319
|
-
{
|
320
|
-
Payload payload;
|
321
|
-
ParseSectionResult result = PayloadParser::Parse(cur,
|
322
|
-
section.bounds.second,
|
323
|
-
section,
|
324
|
-
parser,
|
325
|
-
payload);
|
326
|
-
if (result.first.error.code != Error::OK)
|
327
|
-
return result;
|
328
|
-
|
329
|
-
// Create transaction example if needed
|
330
|
-
if (action.examples.empty()) {
|
331
|
-
action.examples.push_back(TransactionExample());
|
199
|
+
|
200
|
+
static SectionType nestedSectionType(const MarkdownNodeIterator& node) {
|
201
|
+
|
202
|
+
SectionType nestedType = UndefinedSectionType;
|
203
|
+
|
204
|
+
// Check if parameters section
|
205
|
+
nestedType = SectionProcessor<Parameters>::sectionType(node);
|
206
|
+
|
207
|
+
if (nestedType != UndefinedSectionType) {
|
208
|
+
return nestedType;
|
332
209
|
}
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
210
|
+
|
211
|
+
// Check if headers section
|
212
|
+
nestedType = SectionProcessor<Headers>::sectionType(node);
|
213
|
+
|
214
|
+
if (nestedType == HeadersSectionType) {
|
215
|
+
return nestedType;
|
339
216
|
}
|
340
|
-
|
341
|
-
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
342
|
-
|
343
|
-
// Check for duplicate
|
344
|
-
if (IsPayloadDuplicate(section.type, payload, action.examples.back())) {
|
345
|
-
// WARN: duplicate payload
|
346
|
-
std::stringstream ss;
|
347
|
-
ss << SectionName(section.type) << " payload `" << payload.name << "`";
|
348
|
-
ss << " already defined for `" << action.method << "` method";
|
349
217
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
218
|
+
// Check if payload section
|
219
|
+
nestedType = SectionProcessor<Payload>::sectionType(node);
|
220
|
+
|
221
|
+
if (nestedType != UndefinedSectionType) {
|
222
|
+
return nestedType;
|
354
223
|
}
|
355
224
|
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
225
|
+
return UndefinedSectionType;
|
226
|
+
}
|
227
|
+
|
228
|
+
static SectionTypes nestedSectionTypes() {
|
229
|
+
SectionTypes nested, types;
|
230
|
+
|
231
|
+
// Payload & descendants
|
232
|
+
nested.push_back(ResponseBodySectionType);
|
233
|
+
nested.push_back(ResponseSectionType);
|
234
|
+
nested.push_back(RequestBodySectionType);
|
235
|
+
nested.push_back(RequestSectionType);
|
236
|
+
|
237
|
+
types = SectionProcessor<Payload>::nestedSectionTypes();
|
238
|
+
nested.insert(nested.end(), types.begin(), types.end());
|
239
|
+
|
240
|
+
return nested;
|
241
|
+
}
|
242
|
+
|
243
|
+
static void finalize(const MarkdownNodeIterator& node,
|
244
|
+
SectionParserData& pd,
|
245
|
+
Report& report,
|
246
|
+
Action& out) {
|
247
|
+
|
248
|
+
if (!out.headers.empty()) {
|
249
|
+
|
250
|
+
SectionProcessor<Headers>::injectDeprecatedHeaders(out.headers, out.examples);
|
251
|
+
out.headers.clear();
|
362
252
|
}
|
363
|
-
|
364
|
-
|
253
|
+
|
254
|
+
if (out.examples.empty()) {
|
255
|
+
|
256
|
+
// WARN: No response for action
|
257
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
258
|
+
report.warnings.push_back(Warning("action is missing a response",
|
259
|
+
EmptyDefinitionWarning,
|
260
|
+
sourceMap));
|
261
|
+
} else if (!out.examples.empty() &&
|
262
|
+
!out.examples.back().requests.empty() &&
|
263
|
+
out.examples.back().responses.empty()) {
|
264
|
+
|
265
|
+
// WARN: No response for request
|
266
|
+
std::stringstream ss;
|
267
|
+
ss << "action is missing a response for ";
|
268
|
+
|
269
|
+
if (out.examples.back().requests.back().name.empty()) {
|
270
|
+
ss << "a request";
|
271
|
+
} else {
|
272
|
+
ss << "the '" << out.examples.back().requests.back().name << "' request";
|
273
|
+
}
|
274
|
+
|
275
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
276
|
+
report.warnings.push_back(Warning(ss.str(),
|
277
|
+
EmptyDefinitionWarning,
|
278
|
+
sourceMap));
|
365
279
|
}
|
366
|
-
|
367
|
-
// Check header duplicates
|
368
|
-
CheckHeaderDuplicates(action, payload, nameBlock->sourceMap, parser.sourceData, result.first);
|
369
|
-
|
370
|
-
return result;
|
371
280
|
}
|
372
|
-
|
373
|
-
|
281
|
+
|
374
282
|
/**
|
375
283
|
* \brief Check & report payload validity.
|
376
|
-
* \param
|
284
|
+
* \param sectionType A section of the payload.
|
377
285
|
* \param sourceMap Payload signature source map.
|
378
286
|
* \param payload The payload to be checked.
|
287
|
+
* \param action The Action to which payload belongs to.
|
288
|
+
* \param report Parser report.
|
379
289
|
*/
|
380
|
-
static void
|
290
|
+
static void checkPayload(SectionType sectionType,
|
291
|
+
const mdp::CharactersRangeSet sourceMap,
|
381
292
|
const Payload& payload,
|
382
|
-
const
|
383
|
-
|
384
|
-
const SourceData& sourceData,
|
385
|
-
Result& result) {
|
386
|
-
|
387
|
-
bool warnEmptyBody = false;
|
388
|
-
|
389
|
-
std::string contentLength;
|
390
|
-
std::string transferEncoding;
|
293
|
+
const Action& action,
|
294
|
+
Report& report) {
|
391
295
|
|
392
|
-
|
393
|
-
it != payload.headers.end();
|
394
|
-
++it) {
|
296
|
+
if (isPayloadDuplicate(sectionType, payload, action.examples.back())) {
|
395
297
|
|
396
|
-
|
397
|
-
|
398
|
-
|
298
|
+
// WARN: Duplicate payload
|
299
|
+
std::stringstream ss;
|
300
|
+
ss << SectionName(sectionType) << " payload `" << payload.name << "`";
|
301
|
+
ss << " already defined for `" << action.method << "` method";
|
399
302
|
|
400
|
-
|
401
|
-
|
402
|
-
|
303
|
+
report.warnings.push_back(Warning(ss.str(),
|
304
|
+
DuplicateWarning,
|
305
|
+
sourceMap));
|
403
306
|
}
|
404
|
-
|
405
|
-
if (section == RequestSectionType) {
|
406
|
-
|
407
|
-
if (payload.body.empty()) {
|
408
|
-
|
409
|
-
// Warn when content-length or transfer-encoding is specified or both headers and body are empty
|
410
|
-
if (payload.headers.empty()) {
|
411
|
-
warnEmptyBody = true;
|
412
|
-
}
|
413
|
-
else {
|
414
|
-
warnEmptyBody = !contentLength.empty() ||
|
415
|
-
!transferEncoding.empty();
|
416
|
-
}
|
417
307
|
|
418
|
-
|
419
|
-
// WARN: empty body
|
420
|
-
std::stringstream ss;
|
421
|
-
ss << "empty " << SectionName(section) << " " << SectionName(BodySectionType);
|
308
|
+
if (sectionType == ResponseSectionType || sectionType == ResponseBodySectionType) {
|
422
309
|
|
423
|
-
|
424
|
-
ss << ", expected " << SectionName(BodySectionType) << " for '" << contentLength << "' Content-Length";
|
425
|
-
}
|
426
|
-
else if (!transferEncoding.empty()) {
|
427
|
-
ss << ", expected " << SectionName(BodySectionType) << " for '" << transferEncoding << "' Transfer-Encoding";
|
428
|
-
}
|
429
|
-
|
430
|
-
result.warnings.push_back(Warning(ss.str(),
|
431
|
-
EmptyDefinitionWarning,
|
432
|
-
MapSourceDataBlock(sourceMap, sourceData)));
|
433
|
-
}
|
434
|
-
|
435
|
-
}
|
436
|
-
}
|
437
|
-
else if (section == ResponseSectionType) {
|
438
|
-
// Check status code
|
439
|
-
HTTPStatusCode code = 0;
|
310
|
+
HTTPStatusCode code;
|
440
311
|
|
441
312
|
if (!payload.name.empty()) {
|
442
313
|
std::stringstream(payload.name) >> code;
|
443
314
|
}
|
444
315
|
|
445
|
-
|
446
|
-
HTTPMethodTraits methodTraits = GetMethodTrait(method);
|
447
|
-
|
448
|
-
if ((!statusCodeTraits.allowBody || !methodTraits.allowBody) && !payload.body.empty()) {
|
449
|
-
// WARN: not empty body
|
316
|
+
HTTPMethodTraits methodTraits = GetMethodTrait(action.method);
|
450
317
|
|
451
|
-
|
452
|
-
std::stringstream ss;
|
453
|
-
ss << "the " << code << " response MUST NOT include a " << SectionName(BodySectionType);
|
454
|
-
result.warnings.push_back(Warning(ss.str(),
|
455
|
-
EmptyDefinitionWarning,
|
456
|
-
MapSourceDataBlock(sourceMap, sourceData)));
|
457
|
-
}
|
318
|
+
if (!methodTraits.allowBody && !payload.body.empty()) {
|
458
319
|
|
459
320
|
// WARN: Edge case for 2xx CONNECT
|
460
|
-
if (method == HTTPMethodName::Connect && code/100 == 2) {
|
321
|
+
if (action.method == HTTPMethodName::Connect && code/100 == 2) {
|
322
|
+
|
461
323
|
std::stringstream ss;
|
462
|
-
ss << "the response for " << code << " " << method << " request MUST NOT include a " << SectionName(BodySectionType);
|
463
|
-
|
324
|
+
ss << "the response for " << code << " " << action.method << " request MUST NOT include a " << SectionName(BodySectionType);
|
325
|
+
|
326
|
+
report.warnings.push_back(Warning(ss.str(),
|
464
327
|
EmptyDefinitionWarning,
|
465
|
-
|
328
|
+
sourceMap));
|
329
|
+
} else if (action.method != HTTPMethodName::Connect && !methodTraits.allowBody) {
|
466
330
|
|
467
|
-
}
|
468
|
-
else if (method != HTTPMethodName::Connect && !methodTraits.allowBody) {
|
469
331
|
std::stringstream ss;
|
470
|
-
ss << "the response for " << method << " request MUST NOT include a " << SectionName(BodySectionType);
|
471
|
-
|
332
|
+
ss << "the response for " << action.method << " request MUST NOT include a " << SectionName(BodySectionType);
|
333
|
+
|
334
|
+
report.warnings.push_back(Warning(ss.str(),
|
472
335
|
EmptyDefinitionWarning,
|
473
|
-
|
336
|
+
sourceMap));
|
474
337
|
}
|
475
338
|
|
476
339
|
return;
|
@@ -482,22 +345,95 @@ namespace snowcrash {
|
|
482
345
|
* Checks whether given section payload has duplicate within its transaction examples
|
483
346
|
* \return True when a duplicate is found, false otherwise.
|
484
347
|
*/
|
485
|
-
static bool
|
486
|
-
|
487
|
-
|
348
|
+
static bool isPayloadDuplicate(SectionType& sectionType,
|
349
|
+
const Payload& payload,
|
350
|
+
const TransactionExample& example) {
|
351
|
+
|
352
|
+
if (sectionType == RequestSectionType) {
|
353
|
+
|
488
354
|
Collection<Request>::const_iterator duplicate = FindRequest(example, payload);
|
489
355
|
return duplicate != example.requests.end();
|
490
|
-
}
|
491
|
-
|
356
|
+
} else if (sectionType == ResponseSectionType) {
|
357
|
+
|
492
358
|
Collection<Response>::const_iterator duplicate = FindResponse(example, payload);
|
493
359
|
return duplicate != example.responses.end();
|
494
360
|
}
|
495
361
|
|
496
362
|
return false;
|
497
363
|
}
|
364
|
+
|
365
|
+
/** Warn about deprecated headers */
|
366
|
+
static MarkdownNodeIterator handleDeprecatedHeaders(const MarkdownNodeIterator& node,
|
367
|
+
const MarkdownNodes& siblings,
|
368
|
+
SectionParserData& pd,
|
369
|
+
Report& report,
|
370
|
+
Headers& headers) {
|
371
|
+
|
372
|
+
MarkdownNodeIterator cur = HeadersParser::parse(node, siblings, pd, report, headers);
|
373
|
+
|
374
|
+
// WARN: Deprecated header sections
|
375
|
+
std::stringstream ss;
|
376
|
+
ss << "the 'headers' section at this level is deprecated and will be removed in a future, use respective payload header section(s) instead";
|
377
|
+
|
378
|
+
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
379
|
+
report.warnings.push_back(Warning(ss.str(),
|
380
|
+
DeprecatedWarning,
|
381
|
+
sourceMap));
|
382
|
+
|
383
|
+
return cur;
|
384
|
+
}
|
385
|
+
|
386
|
+
/** \return %ActionType of a node */
|
387
|
+
static ActionType actionType(const MarkdownNodeIterator& node) {
|
388
|
+
|
389
|
+
if (node->type != mdp::HeaderMarkdownNodeType || node->text.empty())
|
390
|
+
return NotActionType;
|
391
|
+
|
392
|
+
mdp::ByteBuffer subject = node->text;
|
393
|
+
TrimString(subject);
|
394
|
+
|
395
|
+
if (RegexMatch(subject, NamedActionHeaderRegex)) {
|
396
|
+
return DependentActionType;
|
397
|
+
}
|
398
|
+
|
399
|
+
CaptureGroups captureGroups;
|
400
|
+
if (RegexCapture(subject, ActionHeaderRegex, captureGroups, 3)) {
|
401
|
+
|
402
|
+
if (captureGroups[2].empty()) {
|
403
|
+
return DependentActionType;
|
404
|
+
}
|
405
|
+
else {
|
406
|
+
return CompleteActionType;
|
407
|
+
}
|
408
|
+
}
|
409
|
+
|
410
|
+
return NotActionType;
|
411
|
+
}
|
412
|
+
|
413
|
+
/** \return HTTP request method and name of an action */
|
414
|
+
static void actionHTTPMethodAndName(const MarkdownNodeIterator& node,
|
415
|
+
mdp::ByteBuffer& method,
|
416
|
+
mdp::ByteBuffer& name) {
|
417
|
+
|
418
|
+
CaptureGroups captureGroups;
|
419
|
+
mdp::ByteBuffer subject, remaining;
|
420
|
+
|
421
|
+
subject = GetFirstLine(node->text, remaining);
|
422
|
+
TrimString(subject);
|
423
|
+
|
424
|
+
if (RegexCapture(subject, ActionHeaderRegex, captureGroups, 3)) {
|
425
|
+
method = captureGroups[1];
|
426
|
+
} else if (RegexCapture(subject, NamedActionHeaderRegex, captureGroups, 3)) {
|
427
|
+
name = captureGroups[1];
|
428
|
+
method = captureGroups[2];
|
429
|
+
}
|
430
|
+
|
431
|
+
return;
|
432
|
+
}
|
498
433
|
};
|
499
|
-
|
500
|
-
|
434
|
+
|
435
|
+
/** Action Section Parser */
|
436
|
+
typedef SectionParser<Action, HeaderSectionAdapter> ActionParser;
|
501
437
|
}
|
502
438
|
|
503
439
|
#endif
|