redsnow 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +34 -0
- data/.gitmodules +3 -0
- data/.travis.yml +20 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +62 -0
- data/Rakefile +36 -0
- data/Vagrantfile +20 -0
- data/ext/snowcrash/Makefile +64 -0
- data/ext/snowcrash/Vagrantfile +20 -0
- data/ext/snowcrash/bin/snowcrash +0 -0
- data/ext/snowcrash/common.gypi +163 -0
- data/ext/snowcrash/config.gypi +10 -0
- data/ext/snowcrash/config.mk +5 -0
- data/ext/snowcrash/configure +213 -0
- data/ext/snowcrash/provisioning.sh +15 -0
- data/ext/snowcrash/snowcrash.gyp +141 -0
- data/ext/snowcrash/src/ActionParser.h +503 -0
- data/ext/snowcrash/src/AssetParser.h +215 -0
- data/ext/snowcrash/src/BlockUtility.h +186 -0
- data/ext/snowcrash/src/Blueprint.h +283 -0
- data/ext/snowcrash/src/BlueprintParser.h +347 -0
- data/ext/snowcrash/src/BlueprintParserCore.h +190 -0
- data/ext/snowcrash/src/BlueprintSection.h +140 -0
- data/ext/snowcrash/src/BlueprintUtility.h +126 -0
- data/ext/snowcrash/src/CBlueprint.cc +600 -0
- data/ext/snowcrash/src/CBlueprint.h +354 -0
- data/ext/snowcrash/src/CSourceAnnotation.cc +140 -0
- data/ext/snowcrash/src/CSourceAnnotation.h +106 -0
- data/ext/snowcrash/src/CodeBlockUtility.h +189 -0
- data/ext/snowcrash/src/DescriptionSectionUtility.h +156 -0
- data/ext/snowcrash/src/HTTP.cc +46 -0
- data/ext/snowcrash/src/HTTP.h +105 -0
- data/ext/snowcrash/src/HeaderParser.h +289 -0
- data/ext/snowcrash/src/ListBlockUtility.h +273 -0
- data/ext/snowcrash/src/ListUtility.h +95 -0
- data/ext/snowcrash/src/MarkdownBlock.cc +176 -0
- data/ext/snowcrash/src/MarkdownBlock.h +93 -0
- data/ext/snowcrash/src/MarkdownParser.cc +266 -0
- data/ext/snowcrash/src/MarkdownParser.h +88 -0
- data/ext/snowcrash/src/ParameterDefinitonParser.h +570 -0
- data/ext/snowcrash/src/ParametersParser.h +252 -0
- data/ext/snowcrash/src/Parser.cc +71 -0
- data/ext/snowcrash/src/Parser.h +29 -0
- data/ext/snowcrash/src/ParserCore.cc +120 -0
- data/ext/snowcrash/src/ParserCore.h +82 -0
- data/ext/snowcrash/src/PayloadParser.h +672 -0
- data/ext/snowcrash/src/Platform.h +54 -0
- data/ext/snowcrash/src/RegexMatch.h +32 -0
- data/ext/snowcrash/src/ResourceGroupParser.h +195 -0
- data/ext/snowcrash/src/ResourceParser.h +584 -0
- data/ext/snowcrash/src/SectionUtility.h +142 -0
- data/ext/snowcrash/src/Serialize.cc +52 -0
- data/ext/snowcrash/src/Serialize.h +69 -0
- data/ext/snowcrash/src/SerializeJSON.cc +601 -0
- data/ext/snowcrash/src/SerializeJSON.h +21 -0
- data/ext/snowcrash/src/SerializeYAML.cc +336 -0
- data/ext/snowcrash/src/SerializeYAML.h +21 -0
- data/ext/snowcrash/src/SourceAnnotation.h +177 -0
- data/ext/snowcrash/src/StringUtility.h +109 -0
- data/ext/snowcrash/src/SymbolTable.h +83 -0
- data/ext/snowcrash/src/UriTemplateParser.cc +195 -0
- data/ext/snowcrash/src/UriTemplateParser.h +243 -0
- data/ext/snowcrash/src/Version.h +39 -0
- data/ext/snowcrash/src/csnowcrash.cc +23 -0
- data/ext/snowcrash/src/csnowcrash.h +38 -0
- data/ext/snowcrash/src/posix/RegexMatch.cc +99 -0
- data/ext/snowcrash/src/snowcrash.cc +18 -0
- data/ext/snowcrash/src/snowcrash.h +41 -0
- data/ext/snowcrash/src/snowcrash/snowcrash.cc +170 -0
- data/ext/snowcrash/src/win/RegexMatch.cc +78 -0
- data/ext/snowcrash/sundown/CONTRIBUTING.md +10 -0
- data/ext/snowcrash/sundown/Makefile +83 -0
- data/ext/snowcrash/sundown/Makefile.win +33 -0
- data/ext/snowcrash/sundown/examples/smartypants.c +72 -0
- data/ext/snowcrash/sundown/examples/sundown.c +80 -0
- data/ext/snowcrash/sundown/html/houdini.h +37 -0
- data/ext/snowcrash/sundown/html/houdini_href_e.c +108 -0
- data/ext/snowcrash/sundown/html/houdini_html_e.c +84 -0
- data/ext/snowcrash/sundown/html/html.c +647 -0
- data/ext/snowcrash/sundown/html/html.h +77 -0
- data/ext/snowcrash/sundown/html/html_smartypants.c +389 -0
- data/ext/snowcrash/sundown/html_block_names.txt +25 -0
- data/ext/snowcrash/sundown/src/autolink.c +297 -0
- data/ext/snowcrash/sundown/src/autolink.h +51 -0
- data/ext/snowcrash/sundown/src/buffer.c +225 -0
- data/ext/snowcrash/sundown/src/buffer.h +96 -0
- data/ext/snowcrash/sundown/src/html_blocks.h +206 -0
- data/ext/snowcrash/sundown/src/markdown.c +2701 -0
- data/ext/snowcrash/sundown/src/markdown.h +147 -0
- data/ext/snowcrash/sundown/src/src_map.c +200 -0
- data/ext/snowcrash/sundown/src/src_map.h +58 -0
- data/ext/snowcrash/sundown/src/stack.c +81 -0
- data/ext/snowcrash/sundown/src/stack.h +29 -0
- data/ext/snowcrash/sundown/sundown.def +20 -0
- data/ext/snowcrash/tools/gyp/AUTHORS +11 -0
- data/ext/snowcrash/tools/gyp/DEPS +24 -0
- data/ext/snowcrash/tools/gyp/OWNERS +1 -0
- data/ext/snowcrash/tools/gyp/PRESUBMIT.py +120 -0
- data/ext/snowcrash/tools/gyp/buildbot/buildbot_run.py +190 -0
- data/ext/snowcrash/tools/gyp/codereview.settings +10 -0
- data/ext/snowcrash/tools/gyp/data/win/large-pdb-shim.cc +12 -0
- data/ext/snowcrash/tools/gyp/gyp +8 -0
- data/ext/snowcrash/tools/gyp/gyp.bat +5 -0
- data/ext/snowcrash/tools/gyp/gyp_main.py +18 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSNew.py +340 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSProject.py +208 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSSettings.py +1063 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSToolFile.py +58 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSUserFile.py +147 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSUtil.py +267 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSVersion.py +409 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/__init__.py +537 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/__init__.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/common.py +521 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/common.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/easy_xml.py +157 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/flock_tool.py +49 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/__init__.py +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/__init__.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/android.py +1069 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/cmake.py +1143 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/dump_dependency_json.py +81 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/eclipse.py +335 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/gypd.py +87 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/gypsh.py +56 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/make.py +2181 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/make.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/msvs.py +3335 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/ninja.py +2156 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/xcode.py +1224 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/xcode.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/input.py +2809 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/input.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/mac_tool.py +510 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/msvs_emulation.py +972 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/ninja_syntax.py +160 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/ordered_dict.py +289 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/win_tool.py +292 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/xcode_emulation.py +1440 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/xcode_emulation.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/xcodeproj_file.py +2889 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/xcodeproj_file.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/xml_fix.py +69 -0
- data/ext/snowcrash/tools/gyp/pylintrc +307 -0
- data/ext/snowcrash/tools/gyp/samples/samples +81 -0
- data/ext/snowcrash/tools/gyp/samples/samples.bat +5 -0
- data/ext/snowcrash/tools/gyp/setup.py +19 -0
- data/ext/snowcrash/tools/gyp/tools/Xcode/Specifications/gyp.pbfilespec +27 -0
- data/ext/snowcrash/tools/gyp/tools/Xcode/Specifications/gyp.xclangspec +226 -0
- data/ext/snowcrash/tools/gyp/tools/emacs/gyp.el +252 -0
- data/ext/snowcrash/tools/gyp/tools/graphviz.py +100 -0
- data/ext/snowcrash/tools/gyp/tools/pretty_gyp.py +155 -0
- data/ext/snowcrash/tools/gyp/tools/pretty_sln.py +168 -0
- data/ext/snowcrash/tools/gyp/tools/pretty_vcproj.py +329 -0
- data/ext/snowcrash/tools/homebrew/snowcrash.rb +11 -0
- data/ext/snowcrash/vcbuild.bat +184 -0
- data/lib/redsnow.rb +31 -0
- data/lib/redsnow/binding.rb +132 -0
- data/lib/redsnow/blueprint.rb +365 -0
- data/lib/redsnow/object.rb +18 -0
- data/lib/redsnow/parseresult.rb +107 -0
- data/lib/redsnow/version.rb +4 -0
- data/provisioning.sh +20 -0
- data/redsnow.gemspec +35 -0
- data/test/_helper.rb +15 -0
- data/test/fixtures/sample-api-ast.json +97 -0
- data/test/fixtures/sample-api.apib +20 -0
- data/test/redsnow_binding_test.rb +35 -0
- data/test/redsnow_parseresult_test.rb +50 -0
- data/test/redsnow_test.rb +285 -0
- metadata +358 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
//
|
2
|
+
// HTTP.cc
|
3
|
+
// snowcrash
|
4
|
+
//
|
5
|
+
// Created by Zdenek Nemec on 7/11/13.
|
6
|
+
// Copyright (c) 2013 Apiary Inc. All rights reserved.
|
7
|
+
//
|
8
|
+
|
9
|
+
#include "HTTP.h"
|
10
|
+
|
11
|
+
using namespace snowcrash;
|
12
|
+
|
13
|
+
const std::string HTTPHeaderName::Accept = "Accept";
|
14
|
+
const std::string HTTPHeaderName::ContentLength = "Content-Length";
|
15
|
+
const std::string HTTPHeaderName::ContentType = "Content-Type";
|
16
|
+
const std::string HTTPHeaderName::TransferEncoding = "Transfer-Encoding";
|
17
|
+
|
18
|
+
const std::string HTTPMethodName::Head = "HEAD";
|
19
|
+
const std::string HTTPMethodName::Connect = "CONNECT";
|
20
|
+
|
21
|
+
StatusCodeTraits snowcrash::GetStatusCodeTrait(HTTPStatusCode code)
|
22
|
+
{
|
23
|
+
StatusCodeTraits traits;
|
24
|
+
traits.code = code;
|
25
|
+
|
26
|
+
// Following status codes MUST NOT contain response body
|
27
|
+
if (code == 204 || code == 304 || code/100 == 1) {
|
28
|
+
traits.allowBody = false;
|
29
|
+
}
|
30
|
+
|
31
|
+
return traits;
|
32
|
+
}
|
33
|
+
|
34
|
+
HTTPMethodTraits snowcrash::GetMethodTrait(HTTPMethod method)
|
35
|
+
{
|
36
|
+
HTTPMethodTraits traits;
|
37
|
+
traits.method = method;
|
38
|
+
|
39
|
+
// Following HTTP methods MUST NOT contain response body
|
40
|
+
// FIXME: When refactoring traits don't forget that 'CONNECT' has no body only when 1xx-2xx
|
41
|
+
if (method == HTTPMethodName::Head || method == HTTPMethodName::Connect) {
|
42
|
+
traits.allowBody = false;
|
43
|
+
}
|
44
|
+
|
45
|
+
return traits;
|
46
|
+
}
|
@@ -0,0 +1,105 @@
|
|
1
|
+
//
|
2
|
+
// HTTP.h
|
3
|
+
// snowcrash
|
4
|
+
//
|
5
|
+
// Created by Zdenek Nemec on 7/11/13.
|
6
|
+
// Copyright (c) 2013 Apiary Inc. All rights reserved.
|
7
|
+
//
|
8
|
+
|
9
|
+
#ifndef SNOWCRASH_HTTP_H
|
10
|
+
#define SNOWCRASH_HTTP_H
|
11
|
+
|
12
|
+
#include <string>
|
13
|
+
#include "Blueprint.h"
|
14
|
+
|
15
|
+
/**
|
16
|
+
* \brief HTTP Methods
|
17
|
+
*
|
18
|
+
* Technical note: Using preprocessor macro instead of strict
|
19
|
+
* defined type due to C++98 string concatenation limitations.
|
20
|
+
* FIXME: To be improved with migration to C++11.
|
21
|
+
*/
|
22
|
+
#define HTTP_REQUEST_METHOD "(GET|POST|PUT|DELETE|OPTIONS|PATCH|PROPPATCH|LOCK|UNLOCK|COPY|MOVE|MKCOL|HEAD|LINK|UNLINK|CONNECT)"
|
23
|
+
|
24
|
+
/**
|
25
|
+
* \brief URI Template.
|
26
|
+
*
|
27
|
+
* See previous technical note (using macro).
|
28
|
+
*/
|
29
|
+
#define URI_TEMPLATE "(/.*)"
|
30
|
+
|
31
|
+
namespace snowcrash {
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Selected HTTP Header names.
|
35
|
+
*/
|
36
|
+
struct HTTPHeaderName {
|
37
|
+
static const std::string Accept;
|
38
|
+
static const std::string ContentLength;
|
39
|
+
static const std::string ContentType;
|
40
|
+
static const std::string TransferEncoding;
|
41
|
+
};
|
42
|
+
|
43
|
+
/**
|
44
|
+
* Selected HTTP Method names.
|
45
|
+
*/
|
46
|
+
struct HTTPMethodName {
|
47
|
+
static const std::string Head;
|
48
|
+
static const std::string Connect;
|
49
|
+
};
|
50
|
+
|
51
|
+
/**
|
52
|
+
* A HTTP Status code.
|
53
|
+
*/
|
54
|
+
typedef unsigned int HTTPStatusCode;
|
55
|
+
|
56
|
+
/**
|
57
|
+
* Traits of a HTTP response.
|
58
|
+
*/
|
59
|
+
struct HTTPResponseTraits {
|
60
|
+
|
61
|
+
bool allowBody; /// < Response body is allowed.
|
62
|
+
|
63
|
+
HTTPResponseTraits() : allowBody(true) {}
|
64
|
+
};
|
65
|
+
|
66
|
+
/**
|
67
|
+
* Response traits for a HTTP method.
|
68
|
+
*
|
69
|
+
* HTTP request method related response prescription
|
70
|
+
* Ref: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
|
71
|
+
*/
|
72
|
+
struct HTTPMethodTraits : HTTPResponseTraits
|
73
|
+
{
|
74
|
+
HTTPMethod method;
|
75
|
+
HTTPMethodTraits() : method("") {}
|
76
|
+
};
|
77
|
+
|
78
|
+
/**
|
79
|
+
* Response traits for a HTTP status code.
|
80
|
+
*
|
81
|
+
* Status-related response prescription.
|
82
|
+
* Ref: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
83
|
+
*/
|
84
|
+
struct StatusCodeTraits : HTTPResponseTraits
|
85
|
+
{
|
86
|
+
HTTPStatusCode code;
|
87
|
+
StatusCodeTraits() : code(0) {}
|
88
|
+
};
|
89
|
+
|
90
|
+
/**
|
91
|
+
* \brief Retrieve response traits for given HTTP method.
|
92
|
+
* \param method HTTP method to retrieve traits for.
|
93
|
+
* \return A %HTTPMethodTraits for given method.
|
94
|
+
*/
|
95
|
+
extern HTTPMethodTraits GetMethodTrait(HTTPMethod method);
|
96
|
+
|
97
|
+
/**
|
98
|
+
* \brief Retrieve response traits for given status code.
|
99
|
+
* \param code A HTTP status code to retrieve traits for.
|
100
|
+
* \return A %StatusCodeTraits for given code.
|
101
|
+
*/
|
102
|
+
extern StatusCodeTraits GetStatusCodeTrait(HTTPStatusCode code);
|
103
|
+
}
|
104
|
+
|
105
|
+
#endif
|
@@ -0,0 +1,289 @@
|
|
1
|
+
//
|
2
|
+
// HeaderParser.h
|
3
|
+
// snowcrash
|
4
|
+
//
|
5
|
+
// Created by Zdenek Nemec on 5/22/13.
|
6
|
+
// Copyright (c) 2013 Apiary Inc. All rights reserved.
|
7
|
+
//
|
8
|
+
|
9
|
+
#ifndef SNOWCRASH_HEADERPARSER_H
|
10
|
+
#define SNOWCRASH_HEADERPARSER_H
|
11
|
+
|
12
|
+
#include <sstream>
|
13
|
+
#include "BlueprintParserCore.h"
|
14
|
+
#include "Blueprint.h"
|
15
|
+
#include "RegexMatch.h"
|
16
|
+
#include "StringUtility.h"
|
17
|
+
#include "ListBlockUtility.h"
|
18
|
+
|
19
|
+
namespace snowcrashconst {
|
20
|
+
|
21
|
+
/** Headers matching regex */
|
22
|
+
const char* const HeadersRegex = "^[[:blank:]]*[Hh]eaders?[[:blank:]]*$";
|
23
|
+
}
|
24
|
+
|
25
|
+
namespace snowcrash {
|
26
|
+
|
27
|
+
// Internal type alias for Collection of Headers
|
28
|
+
typedef Collection<Header>::type HeaderCollection;
|
29
|
+
|
30
|
+
// Query header signature a of given block
|
31
|
+
FORCEINLINE bool HasHeaderSignature(const BlockIterator& begin,
|
32
|
+
const BlockIterator& end) {
|
33
|
+
|
34
|
+
if (begin->type == ListBlockBeginType || begin->type == ListItemBlockBeginType) {
|
35
|
+
|
36
|
+
BlockIterator cur = ListItemNameBlock(begin, end);
|
37
|
+
if (cur == end)
|
38
|
+
return false;
|
39
|
+
|
40
|
+
if (cur->type != ParagraphBlockType &&
|
41
|
+
cur->type != ListItemBlockEndType)
|
42
|
+
return false;
|
43
|
+
|
44
|
+
std::string content = GetFirstLine(cur->content);
|
45
|
+
return RegexMatch(content, snowcrashconst::HeadersRegex);
|
46
|
+
}
|
47
|
+
|
48
|
+
return false;
|
49
|
+
}
|
50
|
+
|
51
|
+
// Header iterator in its containment group
|
52
|
+
typedef Collection<Header>::const_iterator HeaderIterator;
|
53
|
+
|
54
|
+
// Finds a header in its containment group by its key (first)
|
55
|
+
FORCEINLINE HeaderIterator FindHeader(const HeaderCollection& headers,
|
56
|
+
const Header& header) {
|
57
|
+
|
58
|
+
return std::find_if(headers.begin(),
|
59
|
+
headers.end(),
|
60
|
+
std::bind2nd(MatchFirsts<Header>(), header));
|
61
|
+
}
|
62
|
+
|
63
|
+
/** Internal list items classifier, Headers Context */
|
64
|
+
template <>
|
65
|
+
FORCEINLINE SectionType ClassifyInternaListBlock<HeaderCollection>(const BlockIterator& begin,
|
66
|
+
const BlockIterator& end) {
|
67
|
+
return UndefinedSectionType;
|
68
|
+
}
|
69
|
+
|
70
|
+
/** Children List Block Classifier, HeaderCollection context. */
|
71
|
+
template <>
|
72
|
+
FORCEINLINE SectionType ClassifyChildrenListBlock<HeaderCollection>(const BlockIterator& begin,
|
73
|
+
const BlockIterator& end){
|
74
|
+
return UndefinedSectionType;
|
75
|
+
}
|
76
|
+
|
77
|
+
/** Block Classifier, Headers Context */
|
78
|
+
template <>
|
79
|
+
FORCEINLINE SectionType ClassifyBlock<HeaderCollection>(const BlockIterator& begin,
|
80
|
+
const BlockIterator& end,
|
81
|
+
const SectionType& context) {
|
82
|
+
|
83
|
+
if (context == UndefinedSectionType &&
|
84
|
+
HasHeaderSignature(begin, end)) {
|
85
|
+
return HeadersSectionType;
|
86
|
+
}
|
87
|
+
else if (context == HeadersSectionType) {
|
88
|
+
|
89
|
+
// SectionType closure
|
90
|
+
if (begin->type == ListItemBlockEndType ||
|
91
|
+
begin->type == ListBlockEndType)
|
92
|
+
return UndefinedSectionType;
|
93
|
+
|
94
|
+
// Adjacent list item
|
95
|
+
if (begin->type == ListItemBlockBeginType)
|
96
|
+
return UndefinedSectionType;
|
97
|
+
}
|
98
|
+
|
99
|
+
return (context == HeadersSectionType) ? context : UndefinedSectionType;
|
100
|
+
}
|
101
|
+
|
102
|
+
//
|
103
|
+
// Headers SectionType Parser
|
104
|
+
//
|
105
|
+
template<>
|
106
|
+
struct SectionParser<HeaderCollection> {
|
107
|
+
|
108
|
+
static ParseSectionResult ParseSection(const BlueprintSection& section,
|
109
|
+
const BlockIterator& cur,
|
110
|
+
BlueprintParserCore& parser,
|
111
|
+
HeaderCollection& headers) {
|
112
|
+
|
113
|
+
ParseSectionResult result = std::make_pair(Result(), cur);
|
114
|
+
switch (section.type) {
|
115
|
+
case HeadersSectionType:
|
116
|
+
result = HandleHeadersSectionBlock(section, cur, parser, headers);
|
117
|
+
break;
|
118
|
+
|
119
|
+
case UndefinedSectionType:
|
120
|
+
result.second = CloseList(cur, section.bounds.second);
|
121
|
+
break;
|
122
|
+
|
123
|
+
default:
|
124
|
+
result.first.error = UnexpectedBlockError(section, cur, parser.sourceData);
|
125
|
+
break;
|
126
|
+
}
|
127
|
+
|
128
|
+
return result;
|
129
|
+
}
|
130
|
+
|
131
|
+
static void Finalize(const SectionBounds& bounds,
|
132
|
+
BlueprintParserCore& parser,
|
133
|
+
HeaderCollection& headers,
|
134
|
+
Result& result) {}
|
135
|
+
|
136
|
+
static ParseSectionResult HandleHeadersSectionBlock(const BlueprintSection& section,
|
137
|
+
const BlockIterator& cur,
|
138
|
+
BlueprintParserCore& parser,
|
139
|
+
HeaderCollection& headers) {
|
140
|
+
|
141
|
+
SourceData data;
|
142
|
+
SourceDataBlock sourceMap;
|
143
|
+
ParseSectionResult result = ParseListPreformattedBlock<HeaderCollection>(section,
|
144
|
+
cur,
|
145
|
+
parser,
|
146
|
+
data,
|
147
|
+
sourceMap);
|
148
|
+
if (result.first.error.code != Error::OK ||
|
149
|
+
parser.sourceData.empty())
|
150
|
+
return result;
|
151
|
+
|
152
|
+
// Proces raw data
|
153
|
+
std::vector<std::string> lines = Split(data, '\n');
|
154
|
+
for (std::vector<std::string>::iterator line = lines.begin();
|
155
|
+
line != lines.end();
|
156
|
+
++line) {
|
157
|
+
|
158
|
+
Header header;
|
159
|
+
if (KeyValueFromLine(*line, header)) {
|
160
|
+
|
161
|
+
if (FindHeader(headers, header) != headers.end()) {
|
162
|
+
// WARN: duplicate header on this level
|
163
|
+
std::stringstream ss;
|
164
|
+
ss << "duplicate definition of '" << header.first << "' header";
|
165
|
+
|
166
|
+
result.first.warnings.push_back(Warning(ss.str(),
|
167
|
+
DuplicateWarning,
|
168
|
+
MapSourceDataBlock(sourceMap, parser.sourceData)));
|
169
|
+
|
170
|
+
}
|
171
|
+
|
172
|
+
headers.push_back(header);
|
173
|
+
}
|
174
|
+
else {
|
175
|
+
// WARN: unable to parse header
|
176
|
+
result.first.warnings.push_back(Warning("unable to parse HTTP header, expected"
|
177
|
+
" '<header name> : <header value>', one header per line",
|
178
|
+
FormattingWarning,
|
179
|
+
MapSourceDataBlock(sourceMap, parser.sourceData)));
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
return result;
|
184
|
+
}
|
185
|
+
};
|
186
|
+
|
187
|
+
typedef BlockParser<HeaderCollection, SectionParser<HeaderCollection> > HeadersParser;
|
188
|
+
|
189
|
+
/**
|
190
|
+
* Generic HeaderSection parser handler
|
191
|
+
*/
|
192
|
+
template <class T>
|
193
|
+
ParseSectionResult HandleHeaders(const BlueprintSection& section,
|
194
|
+
const BlockIterator& cur,
|
195
|
+
BlueprintParserCore& parser,
|
196
|
+
T& t)
|
197
|
+
{
|
198
|
+
size_t headerCount = t.headers.size();
|
199
|
+
ParseSectionResult result = HeadersParser::Parse(cur,
|
200
|
+
section.bounds.second,
|
201
|
+
section,
|
202
|
+
parser,
|
203
|
+
t.headers);
|
204
|
+
if (result.first.error.code != Error::OK)
|
205
|
+
return result;
|
206
|
+
|
207
|
+
if (t.headers.size() == headerCount) {
|
208
|
+
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
209
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
|
210
|
+
result.first.warnings.push_back(Warning("no headers specified",
|
211
|
+
FormattingWarning,
|
212
|
+
sourceBlock));
|
213
|
+
}
|
214
|
+
return result;
|
215
|
+
}
|
216
|
+
|
217
|
+
|
218
|
+
/** Helper for handling parsing of deprecated header sections */
|
219
|
+
template <typename T>
|
220
|
+
ParseSectionResult HandleDeprecatedHeaders(const BlueprintSection& section,
|
221
|
+
const BlockIterator& cur,
|
222
|
+
BlueprintParserCore& parser,
|
223
|
+
T& t) {
|
224
|
+
|
225
|
+
ParseSectionResult result = HandleHeaders<T>(section, cur, parser, t);
|
226
|
+
|
227
|
+
// WARN: Deprecated header sections
|
228
|
+
std::stringstream ss;
|
229
|
+
ss << "the 'headers' section at this level is deprecated and will be removed in a future, use respective payload header section(s) instead";
|
230
|
+
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
231
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
|
232
|
+
result.first.warnings.push_back(Warning(ss.str(),
|
233
|
+
DeprecatedWarning,
|
234
|
+
sourceBlock));
|
235
|
+
return result;
|
236
|
+
}
|
237
|
+
|
238
|
+
/** \brief Copy headers into example paylods headers. */
|
239
|
+
FORCEINLINE void InjectDeprecatedHeaders(const Collection<Header>::type& headers,
|
240
|
+
Collection<TransactionExample>::type& examples)
|
241
|
+
{
|
242
|
+
for (Collection<TransactionExample>::iterator exampleIt = examples.begin();
|
243
|
+
exampleIt != examples.end();
|
244
|
+
++exampleIt) {
|
245
|
+
|
246
|
+
// Requests
|
247
|
+
for (Collection<Request>::iterator reqIt = exampleIt->requests.begin();
|
248
|
+
reqIt != exampleIt->requests.end();
|
249
|
+
++reqIt) {
|
250
|
+
|
251
|
+
reqIt->headers.insert(reqIt->headers.begin(),
|
252
|
+
headers.begin(),
|
253
|
+
headers.end());
|
254
|
+
}
|
255
|
+
|
256
|
+
// Responses
|
257
|
+
for (Collection<Response>::iterator resIt = exampleIt->responses.begin();
|
258
|
+
resIt != exampleIt->responses.end();
|
259
|
+
++resIt) {
|
260
|
+
|
261
|
+
resIt->headers.insert(resIt->headers.begin(),
|
262
|
+
headers.begin(),
|
263
|
+
headers.end());
|
264
|
+
}
|
265
|
+
}
|
266
|
+
}
|
267
|
+
|
268
|
+
// Checks T's headers for occurence of R's headers, warns if a match is found.
|
269
|
+
template <class T, class R>
|
270
|
+
void CheckHeaderDuplicates(const T& left,
|
271
|
+
const R& right,
|
272
|
+
const SourceDataBlock& rightSourceMap,
|
273
|
+
const SourceData& sourceData,
|
274
|
+
Result& result) {
|
275
|
+
|
276
|
+
for (HeaderIterator it = right.headers.begin(); it != right.headers.end(); ++it) {
|
277
|
+
if (FindHeader(left.headers, *it) != left.headers.end()) {
|
278
|
+
// WARN: overshadowing header definition
|
279
|
+
std::stringstream ss;
|
280
|
+
ss << "overshadowing previous '" << it->first << "' header definition";
|
281
|
+
result.warnings.push_back(Warning(ss.str(),
|
282
|
+
RedefinitionWarning,
|
283
|
+
MapSourceDataBlock(rightSourceMap, sourceData)));
|
284
|
+
}
|
285
|
+
}
|
286
|
+
}
|
287
|
+
}
|
288
|
+
|
289
|
+
#endif
|
@@ -0,0 +1,273 @@
|
|
1
|
+
//
|
2
|
+
// ListBlockUtility.h
|
3
|
+
// snowcrash
|
4
|
+
//
|
5
|
+
// All the cool kids from ListUtility.h live here.
|
6
|
+
//
|
7
|
+
// Created by Zdenek Nemec on 11/11/13.
|
8
|
+
// Copyright (c) 2013 Apiary Inc. All rights reserved.
|
9
|
+
//
|
10
|
+
|
11
|
+
#ifndef SNOWCRASH_LISTBLOCKUTILITY_H
|
12
|
+
#define SNOWCRASH_LISTBLOCKUTILITY_H
|
13
|
+
|
14
|
+
#include "ListUtility.h"
|
15
|
+
|
16
|
+
namespace snowcrash {
|
17
|
+
|
18
|
+
/**
|
19
|
+
* \brief Return a first non-signature content block of a list(item).
|
20
|
+
* \param begin Begin of the block buffer to examine.
|
21
|
+
* \param end End of the block buffer.
|
22
|
+
* \return First non-signature content block or begin.
|
23
|
+
*
|
24
|
+
* Returns first block with the actual content of a list or list item.
|
25
|
+
*/
|
26
|
+
FORCEINLINE BlockIterator ContentBlock(const BlockIterator& begin,
|
27
|
+
const BlockIterator& end) {
|
28
|
+
|
29
|
+
BlockIterator cur = begin;
|
30
|
+
if (cur->type == ListBlockBeginType) {
|
31
|
+
if (++cur == end)
|
32
|
+
return end;
|
33
|
+
|
34
|
+
return cur;
|
35
|
+
}
|
36
|
+
|
37
|
+
if (cur->type == ListItemBlockBeginType) {
|
38
|
+
if (++cur == end)
|
39
|
+
return end;
|
40
|
+
|
41
|
+
if (cur->type == ListItemBlockEndType)
|
42
|
+
return begin;
|
43
|
+
|
44
|
+
if (cur->type == ParagraphBlockType)
|
45
|
+
if (++cur == end)
|
46
|
+
return end;
|
47
|
+
}
|
48
|
+
|
49
|
+
return cur;
|
50
|
+
}
|
51
|
+
|
52
|
+
/**
|
53
|
+
* \brief Skips first list item signature block.
|
54
|
+
*
|
55
|
+
* This function effectively returns the first content block of
|
56
|
+
* a list item that is not a signature block. If no such a block exists.
|
57
|
+
* a block following the list item is returned. If a list is provided it
|
58
|
+
* uses its first list item.
|
59
|
+
*/
|
60
|
+
FORCEINLINE BlockIterator SkipSignatureBlock(const BlockIterator& begin,
|
61
|
+
const BlockIterator& end) {
|
62
|
+
|
63
|
+
BlockIterator cur = begin;
|
64
|
+
|
65
|
+
// Skip to fist list item if appropriate
|
66
|
+
if (cur->type == ListBlockBeginType) {
|
67
|
+
cur = ContentBlock(cur, end);
|
68
|
+
}
|
69
|
+
|
70
|
+
// Skip to first list item content
|
71
|
+
if (cur->type == ListItemBlockBeginType) {
|
72
|
+
BlockIterator firstContent = ContentBlock(cur, end);
|
73
|
+
if (cur != firstContent) {
|
74
|
+
cur = firstContent;
|
75
|
+
}
|
76
|
+
else {
|
77
|
+
// No content, just move to the next block
|
78
|
+
++cur;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
return cur;
|
83
|
+
}
|
84
|
+
|
85
|
+
// Return name block of list item; that is either FirstContentBlock() or
|
86
|
+
// matching closing item block for inline items
|
87
|
+
FORCEINLINE BlockIterator ListItemNameBlock(const BlockIterator& begin,
|
88
|
+
const BlockIterator& end) {
|
89
|
+
|
90
|
+
BlockIterator cur = FirstContentBlock(begin, end);
|
91
|
+
if (cur == end ||
|
92
|
+
cur->type != ListBlockBeginType)
|
93
|
+
return cur;
|
94
|
+
|
95
|
+
// Inline list block
|
96
|
+
cur = SkipToClosingBlock(cur, end, ListBlockBeginType, ListBlockEndType);
|
97
|
+
if (cur != end)
|
98
|
+
return ++cur;
|
99
|
+
|
100
|
+
return cur;
|
101
|
+
}
|
102
|
+
|
103
|
+
/**
|
104
|
+
* \brief Eats closing blocks of a list / list item block.
|
105
|
+
* \param begin Cursor to a list or list item closing block.
|
106
|
+
* \param end End of a block buffer.
|
107
|
+
* \return Block AFTER closed list / list item.
|
108
|
+
*
|
109
|
+
* Skips over subsequent ListItemBlockEndType and ListBlockEndType returning the fist
|
110
|
+
* other block after.
|
111
|
+
*/
|
112
|
+
FORCEINLINE BlockIterator CloseList(const BlockIterator& begin,
|
113
|
+
const BlockIterator& end) {
|
114
|
+
|
115
|
+
BlockIterator cur = begin;
|
116
|
+
if (cur != end &&
|
117
|
+
cur->type == ListItemBlockEndType) {
|
118
|
+
++cur; // eat list item end
|
119
|
+
}
|
120
|
+
|
121
|
+
if (cur != end &&
|
122
|
+
cur->type == ListBlockEndType) {
|
123
|
+
++cur; // eat list end
|
124
|
+
}
|
125
|
+
|
126
|
+
return cur;
|
127
|
+
}
|
128
|
+
|
129
|
+
/**
|
130
|
+
* \brief Skips COMPLETE consecutive (nested) closing elements of a list or a list item.
|
131
|
+
* \param begin The begin of a list or a list item.
|
132
|
+
* \param end End of markdown block buffer.
|
133
|
+
* \return An iterator pointing AFTER the last closing list / list item block.
|
134
|
+
*/
|
135
|
+
FORCEINLINE BlockIterator CloseNestedList(const BlockIterator& begin,
|
136
|
+
const BlockIterator& end) {
|
137
|
+
BlockIterator cur = begin;
|
138
|
+
while (cur != end &&
|
139
|
+
(cur->type == ListItemBlockEndType || cur->type == ListBlockEndType)) {
|
140
|
+
cur = CloseList(cur, end);
|
141
|
+
}
|
142
|
+
return cur;
|
143
|
+
}
|
144
|
+
|
145
|
+
/**
|
146
|
+
* \brief Extract the first line of a list item content - its signature
|
147
|
+
* \param cur The begining of the list item to get its signature.
|
148
|
+
* \param end The begining of a block buffer.
|
149
|
+
* \param remainingContent Any additonal content after the first line of signature.
|
150
|
+
* \return First line of the list item signature.
|
151
|
+
*/
|
152
|
+
FORCEINLINE SourceData GetListItemSignature(const BlockIterator& cur,
|
153
|
+
const BlockIterator& end,
|
154
|
+
SourceData& remainingContent) {
|
155
|
+
|
156
|
+
BlockIterator sectionCur = ListItemNameBlock(cur, end);
|
157
|
+
if (sectionCur == end)
|
158
|
+
return SourceData();
|
159
|
+
|
160
|
+
ContentParts content = ExtractFirstLine(*sectionCur);
|
161
|
+
if (content.empty() ||
|
162
|
+
content.front().empty())
|
163
|
+
return SourceData();
|
164
|
+
|
165
|
+
if (content.size() == 2)
|
166
|
+
remainingContent = content[1];
|
167
|
+
|
168
|
+
return content[0];
|
169
|
+
}
|
170
|
+
|
171
|
+
/**
|
172
|
+
* \brief Check List Item signature for an addtional content and issue a warning.
|
173
|
+
* \param section Current section to be checked.
|
174
|
+
* \param cur The begining of the list item to check.
|
175
|
+
* \param bounds Bounds within the block buffer.
|
176
|
+
* \param sourceData Source data byte buffer.
|
177
|
+
* \param placeHint A string explaining the possible place of failure. Might be empty.
|
178
|
+
* \param expectedHint A string defining expected content. Might be empty.
|
179
|
+
* \param result Result to append the possible warning into.
|
180
|
+
* \return True if signagure contains no additional content, false otherwise.
|
181
|
+
*/
|
182
|
+
FORCEINLINE bool CheckSignatureAdditionalContent(const BlueprintSection& section,
|
183
|
+
const BlockIterator& cur,
|
184
|
+
const SourceData& sourceData,
|
185
|
+
const std::string& placeHint,
|
186
|
+
const std::string& expectedHint,
|
187
|
+
Result& result)
|
188
|
+
{
|
189
|
+
SourceData remainingContent;
|
190
|
+
SourceData signature = GetListItemSignature(cur, section.bounds.second, remainingContent);
|
191
|
+
|
192
|
+
if (!remainingContent.empty()) {
|
193
|
+
// WARN: Superfluous content in signature
|
194
|
+
|
195
|
+
std::stringstream ss;
|
196
|
+
ss << "ignoring additional content";
|
197
|
+
|
198
|
+
if (!placeHint.empty())
|
199
|
+
ss << " after " << placeHint;
|
200
|
+
|
201
|
+
if (!expectedHint.empty())
|
202
|
+
ss << ", expected " << expectedHint;
|
203
|
+
|
204
|
+
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
205
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, sourceData);
|
206
|
+
result.warnings.push_back(Warning(ss.str(),
|
207
|
+
IgnoringWarning,
|
208
|
+
sourceBlock));
|
209
|
+
}
|
210
|
+
|
211
|
+
return remainingContent.empty();
|
212
|
+
}
|
213
|
+
|
214
|
+
/**
|
215
|
+
* \brief Parses list (item) block as a preformatted code block.
|
216
|
+
* \param section Actual section being parsed.
|
217
|
+
* \param cur Cursor within the section boundaries.
|
218
|
+
* \param parser Parser instance.
|
219
|
+
* \param action An output data buffer.
|
220
|
+
* \param sourceMap An output source map buffer.
|
221
|
+
* \return A block parser section result, pointing AFTER the last block parsed.
|
222
|
+
*/
|
223
|
+
template <class T>
|
224
|
+
FORCEINLINE ParseSectionResult ParseListPreformattedBlock(const BlueprintSection& section,
|
225
|
+
const BlockIterator& cur,
|
226
|
+
BlueprintParserCore& parser,
|
227
|
+
SourceData& data,
|
228
|
+
SourceDataBlock& sourceMap) {
|
229
|
+
|
230
|
+
ParseSectionResult result = std::make_pair(Result(), cur);
|
231
|
+
BlockIterator sectionCur = cur;
|
232
|
+
|
233
|
+
if (sectionCur != section.bounds.first) {
|
234
|
+
// Parse subsequent blocks as standalone pre blocks.
|
235
|
+
return ParsePreformattedBlock<T>(section, sectionCur, parser, data, sourceMap);
|
236
|
+
}
|
237
|
+
|
238
|
+
// Parse first block of list, throwing away its first line (signature)
|
239
|
+
SourceData content;
|
240
|
+
SourceData signature = GetListItemSignature(cur, section.bounds.second, content);
|
241
|
+
|
242
|
+
// Retrieve any extra lines after signature & warn
|
243
|
+
if (!content.empty()) {
|
244
|
+
|
245
|
+
data = content;
|
246
|
+
|
247
|
+
// WARN: not a preformatted code block
|
248
|
+
std::stringstream ss;
|
249
|
+
|
250
|
+
size_t level = CodeBlockIndentationLevel(section);
|
251
|
+
ss << SectionName(section.type) << " asset ";
|
252
|
+
ss << "is expected to be a pre-formatted code block, separate it by a newline and ";
|
253
|
+
ss << "indent every of its line by ";
|
254
|
+
ss << level * 4 << " spaces or " << level << " tabs";
|
255
|
+
|
256
|
+
BlockIterator nameBlock = ListItemNameBlock(sectionCur, section.bounds.second);
|
257
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
|
258
|
+
result.first.warnings.push_back(Warning(ss.str(),
|
259
|
+
IndentationWarning,
|
260
|
+
sourceBlock));
|
261
|
+
}
|
262
|
+
|
263
|
+
sectionCur = FirstContentBlock(cur, section.bounds.second);
|
264
|
+
sourceMap = sectionCur->sourceMap;
|
265
|
+
|
266
|
+
if (sectionCur != section.bounds.second)
|
267
|
+
result.second = ++sectionCur;
|
268
|
+
|
269
|
+
return result;
|
270
|
+
}
|
271
|
+
}
|
272
|
+
|
273
|
+
#endif
|