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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2 -0
  3. data/ext/snowcrash/Makefile +1 -1
  4. data/ext/snowcrash/bin/snowcrash +0 -0
  5. data/ext/snowcrash/configure +9 -9
  6. data/ext/snowcrash/ext/markdown-parser/Makefile +87 -0
  7. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/CONTRIBUTING.md +0 -0
  8. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/Makefile +2 -1
  9. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/Makefile.win +0 -0
  10. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/examples/smartypants.c +0 -0
  11. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/examples/sundown.c +0 -0
  12. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/houdini.h +0 -0
  13. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/houdini_href_e.c +0 -0
  14. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/houdini_html_e.c +0 -0
  15. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/html.c +0 -0
  16. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/html.h +0 -0
  17. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html/html_smartypants.c +0 -0
  18. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/html_block_names.txt +0 -0
  19. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/autolink.c +0 -0
  20. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/autolink.h +0 -0
  21. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/buffer.c +0 -0
  22. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/buffer.h +1 -1
  23. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/html_blocks.h +0 -0
  24. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/markdown.c +9 -3
  25. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/markdown.h +0 -0
  26. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/src_map.c +11 -7
  27. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/src_map.h +1 -1
  28. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/stack.c +0 -0
  29. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/src/stack.h +0 -0
  30. data/ext/snowcrash/{sundown → ext/markdown-parser/ext/sundown}/sundown.def +0 -0
  31. data/ext/snowcrash/ext/markdown-parser/msvc/markdown/markdown.vcproj +188 -0
  32. data/ext/snowcrash/ext/markdown-parser/msvc/msvc.sln +38 -0
  33. data/ext/snowcrash/ext/markdown-parser/msvc/sundown/sundown.vcproj +206 -0
  34. data/ext/snowcrash/ext/markdown-parser/src/ByteBuffer.cc +92 -0
  35. data/ext/snowcrash/ext/markdown-parser/src/ByteBuffer.h +82 -0
  36. data/ext/snowcrash/ext/markdown-parser/src/MarkdownNode.cc +152 -0
  37. data/ext/snowcrash/ext/markdown-parser/src/MarkdownNode.h +103 -0
  38. data/ext/snowcrash/ext/markdown-parser/src/MarkdownParser.cc +388 -0
  39. data/ext/snowcrash/{src → ext/markdown-parser/src}/MarkdownParser.h +43 -33
  40. data/ext/snowcrash/snowcrash.gyp +114 -63
  41. data/ext/snowcrash/src/ActionParser.h +334 -398
  42. data/ext/snowcrash/src/AssetParser.h +82 -171
  43. data/ext/snowcrash/src/Blueprint.h +7 -2
  44. data/ext/snowcrash/src/BlueprintParser.h +212 -286
  45. data/ext/snowcrash/src/BlueprintUtility.h +2 -2
  46. data/ext/snowcrash/src/CBlueprint.h +1 -1
  47. data/ext/snowcrash/src/CSourceAnnotation.cc +11 -11
  48. data/ext/snowcrash/src/CSourceAnnotation.h +9 -9
  49. data/ext/snowcrash/src/CodeBlockUtility.h +199 -149
  50. data/ext/snowcrash/src/HeadersParser.h +197 -0
  51. data/ext/snowcrash/src/ParameterParser.h +429 -0
  52. data/ext/snowcrash/src/ParametersParser.h +136 -211
  53. data/ext/snowcrash/src/PayloadParser.h +458 -562
  54. data/ext/snowcrash/src/Platform.h +0 -3
  55. data/ext/snowcrash/src/ResourceGroupParser.h +183 -164
  56. data/ext/snowcrash/src/ResourceParser.h +325 -493
  57. data/ext/snowcrash/src/Section.cc +42 -0
  58. data/ext/snowcrash/src/Section.h +47 -0
  59. data/ext/snowcrash/src/SectionParser.h +229 -0
  60. data/ext/snowcrash/src/SectionParserData.h +81 -0
  61. data/ext/snowcrash/src/SectionProcessor.h +211 -0
  62. data/ext/snowcrash/src/Signature.cc +74 -0
  63. data/ext/snowcrash/src/Signature.h +32 -0
  64. data/ext/snowcrash/src/SourceAnnotation.h +7 -20
  65. data/ext/snowcrash/src/StringUtility.h +30 -10
  66. data/ext/snowcrash/src/SymbolTable.h +7 -7
  67. data/ext/snowcrash/src/UriTemplateParser.cc +10 -10
  68. data/ext/snowcrash/src/UriTemplateParser.h +11 -14
  69. data/ext/snowcrash/src/ValuesParser.h +122 -0
  70. data/ext/snowcrash/src/Version.h +2 -2
  71. data/ext/snowcrash/src/csnowcrash.cc +5 -5
  72. data/ext/snowcrash/src/csnowcrash.h +3 -3
  73. data/ext/snowcrash/src/snowcrash.cc +74 -4
  74. data/ext/snowcrash/src/snowcrash.h +9 -4
  75. data/ext/snowcrash/src/snowcrash/snowcrash.cc +16 -16
  76. data/ext/snowcrash/tools/homebrew/snowcrash.rb +3 -2
  77. data/ext/snowcrash/vcbuild.bat +13 -4
  78. data/lib/redsnow.rb +5 -5
  79. data/lib/redsnow/binding.rb +1 -1
  80. data/lib/redsnow/blueprint.rb +33 -2
  81. data/lib/redsnow/parseresult.rb +7 -4
  82. data/lib/redsnow/version.rb +1 -1
  83. data/test/redsnow_binding_test.rb +6 -6
  84. data/test/redsnow_parseresult_test.rb +1 -1
  85. metadata +62 -42
  86. data/ext/snowcrash/src/BlockUtility.h +0 -186
  87. data/ext/snowcrash/src/BlueprintParserCore.h +0 -190
  88. data/ext/snowcrash/src/BlueprintSection.h +0 -140
  89. data/ext/snowcrash/src/DescriptionSectionUtility.h +0 -156
  90. data/ext/snowcrash/src/HeaderParser.h +0 -289
  91. data/ext/snowcrash/src/ListBlockUtility.h +0 -273
  92. data/ext/snowcrash/src/ListUtility.h +0 -95
  93. data/ext/snowcrash/src/MarkdownBlock.cc +0 -176
  94. data/ext/snowcrash/src/MarkdownBlock.h +0 -93
  95. data/ext/snowcrash/src/MarkdownParser.cc +0 -266
  96. data/ext/snowcrash/src/ParameterDefinitonParser.h +0 -645
  97. data/ext/snowcrash/src/Parser.cc +0 -71
  98. data/ext/snowcrash/src/Parser.h +0 -29
  99. data/ext/snowcrash/src/ParserCore.cc +0 -120
  100. data/ext/snowcrash/src/ParserCore.h +0 -82
  101. data/ext/snowcrash/src/SectionUtility.h +0 -142
@@ -1,87 +1,97 @@
1
1
  //
2
2
  // MarkdownParser.h
3
- // snowcrash
3
+ // markdownparser
4
4
  //
5
- // Created by Zdenek Nemec on 4/15/13.
6
- // Copyright (c) 2013 Apiary Inc. All rights reserved.
5
+ // Created by Zdenek Nemec on 4/18/14.
6
+ // Copyright (c) 2014 Apiary Inc. All rights reserved.
7
7
  //
8
8
 
9
- #ifndef SNOWCRASH_MARKDOWNPARSER_H
10
- #define SNOWCRASH_MARKDOWNPARSER_H
9
+ #ifndef MARKDOWNPARSER_MARKDOWNPARSER_H
10
+ #define MARKDOWNPARSER_MARKDOWNPARSER_H
11
11
 
12
- #include "ParserCore.h"
13
- #include "SourceAnnotation.h"
14
- #include "MarkdownBlock.h"
12
+ #include "ByteBuffer.h"
13
+ #include "MarkdownNode.h"
15
14
  #include "markdown.h"
16
15
 
17
- namespace snowcrash {
16
+ namespace mdp {
18
17
 
19
- //
20
- // Markdown Parser
21
- //
18
+ /**
19
+ * GitHub-flavored Markdown Parser
20
+ */
22
21
  class MarkdownParser {
23
22
  public:
24
- // Default sundown parser configuration
25
- static const size_t OutputUnitSize; // = 64;
26
- static const size_t MaxNesting;// = 16;
27
- static const int ParserExtensions;// = MKDEXT_FENCED_CODE | MKDEXT_NO_INTRA_EMPHASIS /*| MKDEXT_TABLES */;
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
- MarkdownBlock::Stack m_renderStack;
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 std::string& text, int level);
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 std::string& text, int flags);
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 std::string& text, int flags);
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 std::string& text, const std::string& language);
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 std::string& text);
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 std::string& text);
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 SourceDataBlock& sourceMap);
94
+ void blockDidParse(const BytesRangeSet& sourceMap);
85
95
  };
86
96
  }
87
97
 
@@ -2,25 +2,52 @@
2
2
  "includes": [
3
3
  "common.gypi"
4
4
  ],
5
-
6
5
  'targets' : [
7
6
  {
8
- 'target_name': 'sundown',
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/buffer.c',
17
- 'sundown/html/houdini_href_e.c',
18
- 'sundown/html/houdini_html_e.c',
19
- 'sundown/html/html.c',
20
- 'sundown/html/html_smartypants.c',
21
- 'sundown/src/markdown.c',
22
- 'sundown/src/stack.c',
23
- 'sundown/src/src_map.c'
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
- 'sundown/src',
32
- 'sundown/src/html'
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/MarkdownBlock.cc',
37
- 'src/MarkdownParser.cc',
38
- 'src/Parser.cc',
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/UriTemplateParser.cc',
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/CBlueprint.cc',
49
- 'src/CSourceAnnotation.cc'
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
- 'sundown'
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
- 'sundown/src',
69
- 'sundown/src/html'
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-HeaderParser.cc',
134
+ 'test/test-HeadersParser.cc',
77
135
  'test/test-Indentation.cc',
78
- 'test/test-ListUtility.cc',
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
- 'sundown'
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
- 'sundown'
170
+ 'libmarkdownparser'
115
171
  ]
116
- }
117
- ],
118
- 'conditions': [
119
- ['OS in "mac linux"', {
120
- 'targets': [
121
- {
122
- 'target_name': 'perf-libsnowcrash',
123
- 'type': 'executable',
124
- 'include_dirs': [
125
- 'src',
126
- 'cmdline',
127
- 'test',
128
- 'test/performance',
129
- ],
130
- 'sources': [
131
- 'test/performance/perf-snowcrash.cc'
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 "DescriptionSectionUtility.h"
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
- namespace snowcrash {
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
- // Method signature
33
- enum ActionSignature {
34
- UndefinedActionSignature,
35
- NoActionSignature,
36
- MethodActionSignature, // # GET
37
- MethodURIActionSignature, // # GET /uri
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
- // Query method signature
42
- FORCEINLINE ActionSignature GetActionSignature(const MarkdownBlock& block,
43
- Name& name,
44
- HTTPMethod& method) {
45
- if (block.type != HeaderBlockType ||
46
- block.content.empty())
47
- return NoActionSignature;
48
-
49
- CaptureGroups captureGroups;
50
- if (RegexCapture(block.content, snowcrashconst::ActionHeaderRegex, captureGroups, 3)) {
51
- // Nameless action
52
- method = captureGroups[1];
53
- URITemplate uri = captureGroups[2];
54
- return (uri.empty()) ? MethodActionSignature : MethodURIActionSignature;
55
- }
56
- else if (RegexCapture(block.content, snowcrashconst::NamedActionHeaderRegex, captureGroups, 3)) {
57
- // Named action
58
- name = captureGroups[1];
59
- TrimString(name);
60
- method = captureGroups[2];
61
- return NamedActionSignature;
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
- // Returns true if block has HTTP Method signature, false otherwise
68
- FORCEINLINE bool HasActionSignature(const MarkdownBlock& block) {
69
-
70
- if (block.type != HeaderBlockType ||
71
- block.content.empty())
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
- type = ClassifyChildrenListBlock<Payload>(begin, end);
132
- if (type != UndefinedSectionType)
133
- return type;
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
- result = HandleParameters(section, cur, parser, action);
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 ResponseSectionType:
192
- result = HandlePayload(section, cur, parser, action);
193
- break;
194
-
195
- case ForeignSectionType:
196
- result = HandleForeignSection<Action>(section, cur, parser.sourceData);
197
- break;
198
-
199
- case UndefinedSectionType:
200
- result.second = CloseList(cur, section.bounds.second);
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 ModelSectionType:
204
- case ObjectSectionType:
205
- {
206
- // ERR: Unexpected model definition
207
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur,
208
- section.bounds.second,
209
- section.bounds,
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
- return result;
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 void Finalize(const SectionBounds& bounds,
226
- BlueprintParserCore& parser,
227
- Action& action,
228
- Result& result)
229
- {
230
- // Consolidate deprecated headers into subsequent payloads
231
- if (!action.headers.empty()) {
232
- InjectDeprecatedHeaders(action.headers, action.examples);
233
- action.headers.clear();
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
- // Check whether transaction example request is followed by a response
237
- if (action.examples.size() > 1 &&
238
- !action.examples.back().requests.empty() &&
239
- action.examples.back().responses.empty()) {
240
- // WARN: No response for request
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
- std::stringstream ss;
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
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(bounds.first, bounds.first, bounds, parser.sourceData);
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
- ParseSectionResult result = std::make_pair(Result(), cur);
262
- BlockIterator sectionCur(cur);
161
+ SectionType assetType = SectionProcessor<Asset>::sectionType(node);
263
162
 
264
- if (cur->type == HeaderBlockType &&
265
- cur == section.bounds.first) {
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
- GetActionSignature(*cur, action.name, action.method);
268
- result.second = ++sectionCur;
269
- return result;
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
- result = ParseDescriptionBlock<Action>(section,
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
- /** Parse Parameters section */
280
- static ParseSectionResult HandleParameters(const BlueprintSection& section,
281
- const BlockIterator& cur,
282
- BlueprintParserCore& parser,
283
- Action& action) {
284
- ParameterCollection parameters;
285
- ParseSectionResult result = ParametersParser::Parse(cur,
286
- section.bounds.second,
287
- section,
288
- parser,
289
- parameters);
290
- if (result.first.error.code != Error::OK)
291
- return result;
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 result;
196
+
197
+ return UndefinedSectionType;
305
198
  }
306
-
307
- /**
308
- * \brief Parse action payload
309
- * \param section Actual section being parsed.
310
- * \param cur Cursor within the section boundaries.
311
- * \param parser A parser's instance.
312
- * \param action An output buffer to store parsed payload into.
313
- * \return A block parser section result.
314
- */
315
- static ParseSectionResult HandlePayload(const BlueprintSection& section,
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
- else if (section.type == RequestSectionType) {
334
- // Automatic request response pairing:
335
- // If a request follows a response create a new transaction example
336
- if (!action.examples.back().responses.empty()) {
337
- action.examples.push_back(TransactionExample());
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
- SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
351
- result.first.warnings.push_back(Warning(ss.str(),
352
- DuplicateWarning,
353
- sourceBlock));
218
+ // Check if payload section
219
+ nestedType = SectionProcessor<Payload>::sectionType(node);
220
+
221
+ if (nestedType != UndefinedSectionType) {
222
+ return nestedType;
354
223
  }
355
224
 
356
- // Check payload integrity
357
- CheckPayload(section.type, payload, action.method, nameBlock->sourceMap, parser.sourceData, result.first);
358
-
359
- // Inject parsed payload into the action
360
- if (section.type == RequestSectionType) {
361
- action.examples.back().requests.push_back(payload);
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
- else if (section.type == ResponseSectionType) {
364
- action.examples.back().responses.push_back(payload);
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 section A section of the payload.
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 CheckPayload(const SectionType& section,
290
+ static void checkPayload(SectionType sectionType,
291
+ const mdp::CharactersRangeSet sourceMap,
381
292
  const Payload& payload,
382
- const HTTPMethod method,
383
- const SourceDataBlock& sourceMap,
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
- for (Collection<Header>::const_iterator it = payload.headers.begin();
393
- it != payload.headers.end();
394
- ++it) {
296
+ if (isPayloadDuplicate(sectionType, payload, action.examples.back())) {
395
297
 
396
- if (it->first == HTTPHeaderName::ContentLength) {
397
- contentLength = it->second;
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
- if (it->first == HTTPHeaderName::TransferEncoding) {
401
- transferEncoding = it->second;
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
- if (warnEmptyBody) {
419
- // WARN: empty body
420
- std::stringstream ss;
421
- ss << "empty " << SectionName(section) << " " << SectionName(BodySectionType);
308
+ if (sectionType == ResponseSectionType || sectionType == ResponseBodySectionType) {
422
309
 
423
- if (!contentLength.empty()) {
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
- StatusCodeTraits statusCodeTraits = GetStatusCodeTrait(code);
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
- if (!statusCodeTraits.allowBody) {
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
- result.warnings.push_back(Warning(ss.str(),
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
- MapSourceDataBlock(sourceMap, sourceData)));
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
- result.warnings.push_back(Warning(ss.str(),
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
- MapSourceDataBlock(sourceMap, sourceData)));
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 IsPayloadDuplicate(const SectionType& section, const Payload& payload, TransactionExample& example) {
486
-
487
- if (section == RequestSectionType) {
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
- else if (section == ResponseSectionType) {
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
- typedef BlockParser<Action, SectionParser<Action> > ActionParser;
434
+
435
+ /** Action Section Parser */
436
+ typedef SectionParser<Action, HeaderSectionAdapter> ActionParser;
501
437
  }
502
438
 
503
439
  #endif