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
|
@@ -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
|