redsnow 0.0.8
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 +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,54 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Platform.h
|
|
3
|
+
// snowcrash
|
|
4
|
+
//
|
|
5
|
+
// Created by Zdenek Nemec on 7/2/13.
|
|
6
|
+
// Copyright (c) 2013 Apiary Inc. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
#ifndef SNOWCRASH_PLATFORM_H
|
|
10
|
+
#define SNOWCRASH_PLATFORM_H
|
|
11
|
+
|
|
12
|
+
#define AS_TYPE(Type, Obj) reinterpret_cast<Type *>(Obj)
|
|
13
|
+
#define AS_CTYPE(Type, Obj) reinterpret_cast<const Type *>(Obj)
|
|
14
|
+
|
|
15
|
+
#if defined(BUILDING_SNOWCRASH)
|
|
16
|
+
# define DEPRECATED
|
|
17
|
+
#endif
|
|
18
|
+
|
|
19
|
+
#if defined(_MSC_VER)
|
|
20
|
+
# define FORCEINLINE __forceinline
|
|
21
|
+
# if !defined(DEPRECATED)
|
|
22
|
+
# define DEPRECATED __declspec(deprecated)
|
|
23
|
+
# endif
|
|
24
|
+
#elif defined(__clang__) || defined(__GNUC__)
|
|
25
|
+
# define FORCEINLINE inline
|
|
26
|
+
# if !defined(DEPRECATED)
|
|
27
|
+
# define DEPRECATED __attribute__((deprecated))
|
|
28
|
+
# endif
|
|
29
|
+
#else
|
|
30
|
+
# define FORCEINLINE inline
|
|
31
|
+
# if !defined(DEPRECATED)
|
|
32
|
+
# define DEPRECATED
|
|
33
|
+
# endif
|
|
34
|
+
#endif
|
|
35
|
+
|
|
36
|
+
#ifndef SC_API
|
|
37
|
+
# ifdef _WIN32
|
|
38
|
+
# if defined(CSNOWCRASH_BUILD_SHARED) /* build dll */
|
|
39
|
+
# define SC_API __declspec(dllimport)
|
|
40
|
+
# elif !defined(CSNOWCRASH_BUILD_STATIC) /* use dll */
|
|
41
|
+
# define SC_API __declspec(dllexport)
|
|
42
|
+
# else /* static library */
|
|
43
|
+
# define SC_API
|
|
44
|
+
# endif
|
|
45
|
+
# else
|
|
46
|
+
# if __GNUC__ >= 4
|
|
47
|
+
# define SC_API /*__attribute__((visibility("default")))*/
|
|
48
|
+
# else
|
|
49
|
+
# define SC_API
|
|
50
|
+
# endif
|
|
51
|
+
# endif
|
|
52
|
+
#endif
|
|
53
|
+
|
|
54
|
+
#endif
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RegexMatch.h
|
|
3
|
+
// snowcrash
|
|
4
|
+
//
|
|
5
|
+
// Created by Zdenek Nemec on 5/2/13.
|
|
6
|
+
// Copyright (c) 2013 Apiary Inc. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
#ifndef SNOWCRASH_REGEXMATCH_H
|
|
10
|
+
#define SNOWCRASH_REGEXMATCH_H
|
|
11
|
+
|
|
12
|
+
#include <string>
|
|
13
|
+
#include <vector>
|
|
14
|
+
|
|
15
|
+
namespace snowcrash {
|
|
16
|
+
|
|
17
|
+
// Perform snowcrash-specific regex evaluation
|
|
18
|
+
// returns true if target string matches given expression, false otherwise
|
|
19
|
+
bool RegexMatch(const std::string& target, const std::string& expression);
|
|
20
|
+
|
|
21
|
+
// Performs posix-regex and returns first captured group (excluding whole target)
|
|
22
|
+
std::string RegexCaptureFirst(const std::string& target, const std::string& expression);
|
|
23
|
+
|
|
24
|
+
// Array of capture groups
|
|
25
|
+
typedef std::vector<std::string> CaptureGroups;
|
|
26
|
+
|
|
27
|
+
// Performs posix-regex
|
|
28
|
+
// returns true if target string matches given expression, false otherwise
|
|
29
|
+
bool RegexCapture(const std::string& target, const std::string& expression, CaptureGroups& captureGroups, size_t groupSize = 8);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#endif
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ResourceGroupParser.h
|
|
3
|
+
// snowcrash
|
|
4
|
+
//
|
|
5
|
+
// Created by Zdenek Nemec on 5/4/13.
|
|
6
|
+
// Copyright (c) 2013 Apiary Inc. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
#ifndef SNOWCRASH_RESOURCEGROUPPARSER_H
|
|
10
|
+
#define SNOWCRASH_RESOURCEGROUPPARSER_H
|
|
11
|
+
|
|
12
|
+
#include "BlueprintParserCore.h"
|
|
13
|
+
#include "Blueprint.h"
|
|
14
|
+
#include "ResourceParser.h"
|
|
15
|
+
|
|
16
|
+
namespace snowcrashconst {
|
|
17
|
+
|
|
18
|
+
const char* const GroupHeaderRegex = "^[[:blank:]]*[Gg]roup[[:blank:]]+" SYMBOL_IDENTIFIER "[[:blank:]]*$";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
namespace snowcrash {
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* \brief Find a group in the blueprint by the group name.
|
|
25
|
+
* \param blueprint A blueprint AST to be searched.
|
|
26
|
+
* \param group A resource group to look for.
|
|
27
|
+
* \returns An iterator at matching group within blueprint's resource groups collection.
|
|
28
|
+
*/
|
|
29
|
+
FORCEINLINE Collection<ResourceGroup>::const_iterator FindResourceGroup(const Blueprint& blueprint,
|
|
30
|
+
const ResourceGroup& group) {
|
|
31
|
+
|
|
32
|
+
return std::find_if(blueprint.resourceGroups.begin(),
|
|
33
|
+
blueprint.resourceGroups.end(),
|
|
34
|
+
std::bind2nd(MatchName<ResourceGroup>(), group));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* \brief Check a markdown block of Group signature, also retrieves a group name.
|
|
39
|
+
* \param block A markdown block to query for its signature and retrieve a group name from.
|
|
40
|
+
* \param name An output buffer to retrieve a Resource Group Name into.
|
|
41
|
+
* \returns True if the given markdown block has Resource group signature, false otherwise.
|
|
42
|
+
*/
|
|
43
|
+
FORCEINLINE bool GetResourceGroupSignature(const MarkdownBlock& block,
|
|
44
|
+
Name& name) {
|
|
45
|
+
if (block.type != HeaderBlockType ||
|
|
46
|
+
block.content.empty())
|
|
47
|
+
return false;
|
|
48
|
+
|
|
49
|
+
CaptureGroups captureGroups;
|
|
50
|
+
if (RegexCapture(block.content, snowcrashconst::GroupHeaderRegex, captureGroups, 3)) {
|
|
51
|
+
name = captureGroups[1];
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* \brief Query whether given block has resource group signature.
|
|
60
|
+
* \param block A markdown block to query its signature
|
|
61
|
+
* \returns True if the given markdown block has Resource group signature, false otherwise.
|
|
62
|
+
*/
|
|
63
|
+
FORCEINLINE bool HasResourceGroupSignature(const MarkdownBlock& block)
|
|
64
|
+
{
|
|
65
|
+
Name name;
|
|
66
|
+
return GetResourceGroupSignature(block, name);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Internal list items classifier, Resource Group Context */
|
|
70
|
+
template <>
|
|
71
|
+
FORCEINLINE SectionType ClassifyInternaListBlock<ResourceGroup>(const BlockIterator& begin,
|
|
72
|
+
const BlockIterator& end) {
|
|
73
|
+
return UndefinedSectionType;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Block Classifier, Resource Group Context */
|
|
77
|
+
template <>
|
|
78
|
+
FORCEINLINE SectionType ClassifyBlock<ResourceGroup>(const BlockIterator& begin,
|
|
79
|
+
const BlockIterator& end,
|
|
80
|
+
const SectionType& context) {
|
|
81
|
+
|
|
82
|
+
if (HasResourceGroupSignature(*begin))
|
|
83
|
+
return (context == UndefinedSectionType) ? ResourceGroupSectionType : UndefinedSectionType;
|
|
84
|
+
|
|
85
|
+
if (HasResourceSignature(*begin))
|
|
86
|
+
return ResourceSectionType;
|
|
87
|
+
|
|
88
|
+
return (context == ResourceGroupSectionType) ? context : UndefinedSectionType;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Resource Group SectionType Parser */
|
|
92
|
+
template<>
|
|
93
|
+
struct SectionParser<ResourceGroup> {
|
|
94
|
+
|
|
95
|
+
static ParseSectionResult ParseSection(const BlueprintSection& section,
|
|
96
|
+
const BlockIterator& cur,
|
|
97
|
+
BlueprintParserCore& parser,
|
|
98
|
+
ResourceGroup& group) {
|
|
99
|
+
|
|
100
|
+
ParseSectionResult result = std::make_pair(Result(), cur);
|
|
101
|
+
switch (section.type) {
|
|
102
|
+
|
|
103
|
+
case ResourceGroupSectionType:
|
|
104
|
+
result = HandleResourceGroupOverviewBlock(section, cur, parser, group);
|
|
105
|
+
break;
|
|
106
|
+
|
|
107
|
+
case ResourceSectionType:
|
|
108
|
+
result = HandleResource(section, cur, parser, group);
|
|
109
|
+
break;
|
|
110
|
+
|
|
111
|
+
case UndefinedSectionType:
|
|
112
|
+
break;
|
|
113
|
+
|
|
114
|
+
default:
|
|
115
|
+
result.first.error = UnexpectedBlockError(section, cur, parser.sourceData);
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
static void Finalize(const SectionBounds& bounds,
|
|
123
|
+
BlueprintParserCore& parser,
|
|
124
|
+
ResourceGroup& group,
|
|
125
|
+
Result& result) {}
|
|
126
|
+
|
|
127
|
+
static ParseSectionResult HandleResourceGroupOverviewBlock(const BlueprintSection& section,
|
|
128
|
+
const BlockIterator& cur,
|
|
129
|
+
BlueprintParserCore& parser,
|
|
130
|
+
ResourceGroup& group) {
|
|
131
|
+
|
|
132
|
+
ParseSectionResult result = std::make_pair(Result(), cur);
|
|
133
|
+
BlockIterator sectionCur(cur);
|
|
134
|
+
|
|
135
|
+
// Group Name
|
|
136
|
+
if (sectionCur == section.bounds.first) {
|
|
137
|
+
|
|
138
|
+
GetResourceGroupSignature(*cur, group.name);
|
|
139
|
+
result.second = ++sectionCur;
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Group Description
|
|
144
|
+
result = ParseDescriptionBlock<ResourceGroup>(section,
|
|
145
|
+
sectionCur,
|
|
146
|
+
parser.sourceData,
|
|
147
|
+
group);
|
|
148
|
+
return result;
|
|
149
|
+
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static ParseSectionResult HandleResource(const BlueprintSection& section,
|
|
153
|
+
const BlockIterator& cur,
|
|
154
|
+
BlueprintParserCore& parser,
|
|
155
|
+
ResourceGroup& group)
|
|
156
|
+
{
|
|
157
|
+
Resource resource;
|
|
158
|
+
ParseSectionResult result = ResourceParser::Parse(cur,
|
|
159
|
+
section.bounds.second,
|
|
160
|
+
section,
|
|
161
|
+
parser,
|
|
162
|
+
resource);
|
|
163
|
+
if (result.first.error.code != Error::OK)
|
|
164
|
+
return result;
|
|
165
|
+
|
|
166
|
+
ResourceIterator duplicate = FindResource(group, resource);
|
|
167
|
+
ResourceIteratorPair globalDuplicate;
|
|
168
|
+
if (duplicate == group.resources.end())
|
|
169
|
+
globalDuplicate = FindResource(parser.blueprint, resource);
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
if (duplicate != group.resources.end() ||
|
|
174
|
+
globalDuplicate.first != parser.blueprint.resourceGroups.end()) {
|
|
175
|
+
|
|
176
|
+
// WARN: Duplicate resource
|
|
177
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, parser.sourceData);
|
|
178
|
+
result.first.warnings.push_back(Warning("the resource '" +
|
|
179
|
+
resource.uriTemplate +
|
|
180
|
+
"' is already defined",
|
|
181
|
+
DuplicateWarning,
|
|
182
|
+
sourceBlock));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
group.resources.push_back(resource); // FIXME: C++11 move
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
typedef BlockParser<ResourceGroup, SectionParser<ResourceGroup> > ResourceGroupParser;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
#endif
|
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ResourceParser.h
|
|
3
|
+
// snowcrash
|
|
4
|
+
//
|
|
5
|
+
// Created by Zdenek Nemec on 5/4/13.
|
|
6
|
+
// Copyright (c) 2013 Apiary Inc. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
#ifndef SNOWCRASH_RESOURCEPARSER_H
|
|
10
|
+
#define SNOWCRASH_RESOURCEPARSER_H
|
|
11
|
+
|
|
12
|
+
#include <sstream>
|
|
13
|
+
#include "BlueprintParserCore.h"
|
|
14
|
+
#include "Blueprint.h"
|
|
15
|
+
#include "ActionParser.h"
|
|
16
|
+
#include "RegexMatch.h"
|
|
17
|
+
#include "StringUtility.h"
|
|
18
|
+
#include "ParametersParser.h"
|
|
19
|
+
#include "DescriptionSectionUtility.h"
|
|
20
|
+
#include "UriTemplateParser.h"
|
|
21
|
+
|
|
22
|
+
namespace snowcrashconst {
|
|
23
|
+
|
|
24
|
+
/** Nameless resource matching regex */
|
|
25
|
+
const char* const ResourceHeaderRegex = "^[[:blank:]]*(" HTTP_REQUEST_METHOD "[[:blank:]]+)?" URI_TEMPLATE "$";
|
|
26
|
+
|
|
27
|
+
/** Named resource matching regex */
|
|
28
|
+
const char* const NamedResourceHeaderRegex = "^[[:blank:]]*" SYMBOL_IDENTIFIER "[[:blank:]]+\\[" URI_TEMPLATE "]$";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
namespace snowcrash {
|
|
32
|
+
|
|
33
|
+
// Resource signature
|
|
34
|
+
enum ResourceSignature {
|
|
35
|
+
UndefinedResourceSignature,
|
|
36
|
+
NoResourceSignature,
|
|
37
|
+
URIResourceSignature,
|
|
38
|
+
MethodURIResourceSignature,
|
|
39
|
+
NamedResourceSignature
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Query resource signature
|
|
43
|
+
FORCEINLINE ResourceSignature GetResourceSignature(const MarkdownBlock& block,
|
|
44
|
+
Name& name,
|
|
45
|
+
URITemplate& uri,
|
|
46
|
+
HTTPMethod& method) {
|
|
47
|
+
if (block.type != HeaderBlockType ||
|
|
48
|
+
block.content.empty())
|
|
49
|
+
return NoResourceSignature;
|
|
50
|
+
|
|
51
|
+
CaptureGroups captureGroups;
|
|
52
|
+
// Nameless resource
|
|
53
|
+
if (RegexCapture(block.content, snowcrashconst::ResourceHeaderRegex, captureGroups, 4)) {
|
|
54
|
+
method = captureGroups[2];
|
|
55
|
+
uri = captureGroups[3];
|
|
56
|
+
return (method.empty()) ? URIResourceSignature : MethodURIResourceSignature;
|
|
57
|
+
}
|
|
58
|
+
else if (RegexCapture(block.content, snowcrashconst::NamedResourceHeaderRegex, captureGroups, 4)) {
|
|
59
|
+
method.clear();
|
|
60
|
+
name = captureGroups[1];
|
|
61
|
+
TrimString(name);
|
|
62
|
+
uri = captureGroups[2];
|
|
63
|
+
return NamedResourceSignature;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return NoResourceSignature;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Returns true if block has resource header signature, false otherwise
|
|
70
|
+
FORCEINLINE bool HasResourceSignature(const MarkdownBlock& block) {
|
|
71
|
+
|
|
72
|
+
Name name;
|
|
73
|
+
URITemplate uri;
|
|
74
|
+
HTTPMethod method;
|
|
75
|
+
return GetResourceSignature(block, name, uri, method) != NoResourceSignature;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Resource iterator in its containment group
|
|
79
|
+
typedef Collection<Resource>::const_iterator ResourceIterator;
|
|
80
|
+
|
|
81
|
+
// Finds a resource in resource group by its URI template
|
|
82
|
+
FORCEINLINE ResourceIterator FindResource(const ResourceGroup& group,
|
|
83
|
+
const Resource& resource) {
|
|
84
|
+
return std::find_if(group.resources.begin(),
|
|
85
|
+
group.resources.end(),
|
|
86
|
+
std::bind2nd(MatchResource(), resource));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Resource iterator pair: its containment group and resource iterator itself
|
|
90
|
+
typedef std::pair<Collection<ResourceGroup>::const_iterator, ResourceIterator> ResourceIteratorPair;
|
|
91
|
+
|
|
92
|
+
// Finds a resource in blueprint by its URI template
|
|
93
|
+
FORCEINLINE ResourceIteratorPair FindResource(const Blueprint& blueprint,
|
|
94
|
+
const Resource& resource) {
|
|
95
|
+
|
|
96
|
+
for (Collection<ResourceGroup>::const_iterator it = blueprint.resourceGroups.begin();
|
|
97
|
+
it != blueprint.resourceGroups.end();
|
|
98
|
+
++it) {
|
|
99
|
+
|
|
100
|
+
Collection<Resource>::const_iterator match = FindResource(*it, resource);
|
|
101
|
+
if (match != it->resources.end())
|
|
102
|
+
return std::make_pair(it, match);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return std::make_pair(blueprint.resourceGroups.end(), Collection<Resource>::iterator());
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
//
|
|
110
|
+
// Classifier of internal list items, Resource context
|
|
111
|
+
//
|
|
112
|
+
template <>
|
|
113
|
+
FORCEINLINE SectionType ClassifyInternaListBlock<Resource>(const BlockIterator& begin,
|
|
114
|
+
const BlockIterator& end) {
|
|
115
|
+
if (HasHeaderSignature(begin, end))
|
|
116
|
+
return HeadersSectionType;
|
|
117
|
+
|
|
118
|
+
if (HasParametersSignature(begin, end))
|
|
119
|
+
return ParametersSectionType;
|
|
120
|
+
|
|
121
|
+
Name name;
|
|
122
|
+
SourceData mediaType;
|
|
123
|
+
PayloadSignature payloadSignature = GetPayloadSignature(begin, end, name, mediaType);
|
|
124
|
+
if (payloadSignature == ObjectPayloadSignature)
|
|
125
|
+
return ObjectSectionType;
|
|
126
|
+
else if (payloadSignature == ModelPayloadSignature)
|
|
127
|
+
return ModelSectionType;
|
|
128
|
+
|
|
129
|
+
return UndefinedSectionType;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Children blocks classifier */
|
|
133
|
+
template <>
|
|
134
|
+
FORCEINLINE SectionType ClassifyChildrenListBlock<Resource>(const BlockIterator& begin,
|
|
135
|
+
const BlockIterator& end) {
|
|
136
|
+
|
|
137
|
+
SectionType type = ClassifyInternaListBlock<Resource>(begin, end);
|
|
138
|
+
if (type != UndefinedSectionType)
|
|
139
|
+
return type;
|
|
140
|
+
|
|
141
|
+
type = ClassifyChildrenListBlock<HeaderCollection>(begin, end);
|
|
142
|
+
if (type != UndefinedSectionType)
|
|
143
|
+
return type;
|
|
144
|
+
|
|
145
|
+
type = ClassifyChildrenListBlock<ParameterCollection>(begin, end);
|
|
146
|
+
if (type != UndefinedSectionType)
|
|
147
|
+
return type;
|
|
148
|
+
|
|
149
|
+
type = ClassifyChildrenListBlock<Payload>(begin, end);
|
|
150
|
+
if (type != UndefinedSectionType)
|
|
151
|
+
return type;
|
|
152
|
+
|
|
153
|
+
return UndefinedSectionType;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
//
|
|
157
|
+
// Block Classifier, Resource Context
|
|
158
|
+
//
|
|
159
|
+
template <>
|
|
160
|
+
FORCEINLINE SectionType ClassifyBlock<Resource>(const BlockIterator& begin,
|
|
161
|
+
const BlockIterator& end,
|
|
162
|
+
const SectionType& context) {
|
|
163
|
+
if (HasResourceGroupSignature(*begin))
|
|
164
|
+
return UndefinedSectionType;
|
|
165
|
+
|
|
166
|
+
Name name;
|
|
167
|
+
URITemplate uri;
|
|
168
|
+
HTTPMethod method;
|
|
169
|
+
ResourceSignature resourceSignature = GetResourceSignature(*begin, name, uri, method);
|
|
170
|
+
if (resourceSignature != NoResourceSignature) {
|
|
171
|
+
return (context == UndefinedSectionType) ?
|
|
172
|
+
((resourceSignature == MethodURIResourceSignature) ? ResourceMethodSectionType : ResourceSectionType) :
|
|
173
|
+
UndefinedSectionType;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (HasActionSignature(*begin))
|
|
177
|
+
return (context != ResourceMethodSectionType) ? ActionSectionType : UndefinedSectionType;
|
|
178
|
+
|
|
179
|
+
SectionType listSection = ClassifyInternaListBlock<Resource>(begin, end);
|
|
180
|
+
if (listSection != UndefinedSectionType)
|
|
181
|
+
return listSection;
|
|
182
|
+
|
|
183
|
+
// Unrecognized list item at this level
|
|
184
|
+
if (begin->type == ListItemBlockBeginType)
|
|
185
|
+
return ForeignSectionType;
|
|
186
|
+
|
|
187
|
+
return (context == ResourceSectionType) ? context : UndefinedSectionType;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
//
|
|
191
|
+
// Resource SectionType Parser
|
|
192
|
+
//
|
|
193
|
+
template<>
|
|
194
|
+
struct SectionParser<Resource> {
|
|
195
|
+
|
|
196
|
+
static ParseSectionResult ParseSection(const BlueprintSection& section,
|
|
197
|
+
const BlockIterator& cur,
|
|
198
|
+
BlueprintParserCore& parser,
|
|
199
|
+
Resource& resource) {
|
|
200
|
+
ParseSectionResult result = std::make_pair(Result(), cur);
|
|
201
|
+
|
|
202
|
+
switch (section.type) {
|
|
203
|
+
case ResourceSectionType:
|
|
204
|
+
result = HandleResourceDescriptionBlock(section, cur, parser, resource);
|
|
205
|
+
break;
|
|
206
|
+
|
|
207
|
+
case ResourceMethodSectionType:
|
|
208
|
+
result = HandleResourceMethod(section, cur, parser, resource);
|
|
209
|
+
break;
|
|
210
|
+
|
|
211
|
+
case ModelSectionType:
|
|
212
|
+
case ObjectSectionType:
|
|
213
|
+
result = HandleModel(section, cur, parser, resource);
|
|
214
|
+
break;
|
|
215
|
+
|
|
216
|
+
case ParametersSectionType:
|
|
217
|
+
result = HandleParameters(section, cur, parser, resource);
|
|
218
|
+
break;
|
|
219
|
+
|
|
220
|
+
case HeadersSectionType:
|
|
221
|
+
result = HandleDeprecatedHeaders(section, cur, parser, resource);
|
|
222
|
+
break;
|
|
223
|
+
|
|
224
|
+
case ActionSectionType:
|
|
225
|
+
result = HandleAction(section, cur, parser, resource);
|
|
226
|
+
break;
|
|
227
|
+
|
|
228
|
+
case UndefinedSectionType:
|
|
229
|
+
CheckAmbiguousMethod(section, cur, resource, parser.sourceData, result.first);
|
|
230
|
+
result.second = CloseList(cur, section.bounds.second);
|
|
231
|
+
break;
|
|
232
|
+
|
|
233
|
+
case ForeignSectionType:
|
|
234
|
+
result = HandleForeignSection<Resource>(section, cur, parser.sourceData);
|
|
235
|
+
break;
|
|
236
|
+
|
|
237
|
+
default:
|
|
238
|
+
result.first.error = UnexpectedBlockError(section, cur, parser.sourceData);
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
return result;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
static void Finalize(const SectionBounds& bounds,
|
|
247
|
+
BlueprintParserCore& parser,
|
|
248
|
+
Resource& resource,
|
|
249
|
+
Result& result)
|
|
250
|
+
{
|
|
251
|
+
|
|
252
|
+
if (!resource.uriTemplate.empty()) {
|
|
253
|
+
URITemplateParser uriTemplateParser;
|
|
254
|
+
ParsedURITemplate parsedResult;
|
|
255
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(bounds.first, bounds.first, bounds, parser.sourceData);
|
|
256
|
+
|
|
257
|
+
uriTemplateParser.parse(resource.uriTemplate, sourceBlock, parsedResult);
|
|
258
|
+
if (parsedResult.result.warnings.size() > 0) {
|
|
259
|
+
result += parsedResult.result;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Consolidate depraceted headers into subsequent payloads
|
|
264
|
+
if (!resource.headers.empty()) {
|
|
265
|
+
for (Collection<Action>::iterator it = resource.actions.begin();
|
|
266
|
+
it != resource.actions.end();
|
|
267
|
+
++it) {
|
|
268
|
+
InjectDeprecatedHeaders(resource.headers, it->examples);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
resource.headers.clear();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
static ParseSectionResult HandleResourceDescriptionBlock(const BlueprintSection& section,
|
|
277
|
+
const BlockIterator& cur,
|
|
278
|
+
BlueprintParserCore& parser,
|
|
279
|
+
Resource& resource) {
|
|
280
|
+
|
|
281
|
+
ParseSectionResult result = std::make_pair(Result(), cur);
|
|
282
|
+
BlockIterator sectionCur(cur);
|
|
283
|
+
|
|
284
|
+
// Retrieve URI
|
|
285
|
+
if (cur->type == HeaderBlockType &&
|
|
286
|
+
cur == section.bounds.first) {
|
|
287
|
+
|
|
288
|
+
HTTPMethod method;
|
|
289
|
+
GetResourceSignature(*cur, resource.name, resource.uriTemplate, method);
|
|
290
|
+
result.second = ++sectionCur;
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
result = ParseDescriptionBlock<Resource>(section,
|
|
295
|
+
sectionCur,
|
|
296
|
+
parser.sourceData,
|
|
297
|
+
resource);
|
|
298
|
+
return result;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
static ParseSectionResult HandleModel(const BlueprintSection& section,
|
|
302
|
+
const BlockIterator& cur,
|
|
303
|
+
BlueprintParserCore& parser,
|
|
304
|
+
Resource& resource)
|
|
305
|
+
{
|
|
306
|
+
Payload payload;
|
|
307
|
+
ParseSectionResult result = PayloadParser::Parse(cur,
|
|
308
|
+
section.bounds.second,
|
|
309
|
+
section,
|
|
310
|
+
parser,
|
|
311
|
+
payload);
|
|
312
|
+
if (result.first.error.code != Error::OK)
|
|
313
|
+
return result;
|
|
314
|
+
|
|
315
|
+
// Check whether there isnt a model already
|
|
316
|
+
if (!resource.model.name.empty()) {
|
|
317
|
+
|
|
318
|
+
// WARN: Model already defined
|
|
319
|
+
std::stringstream ss;
|
|
320
|
+
ss << "overshadowing previous model definiton for '";
|
|
321
|
+
|
|
322
|
+
if (!resource.name.empty())
|
|
323
|
+
ss << resource.name << "(" << resource.uriTemplate << ")";
|
|
324
|
+
else
|
|
325
|
+
ss << resource.uriTemplate;
|
|
326
|
+
|
|
327
|
+
ss << "' resource, a resource can be represented by a single model only";
|
|
328
|
+
|
|
329
|
+
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
|
330
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
|
|
331
|
+
result.first.warnings.push_back(Warning(ss.str(),
|
|
332
|
+
DuplicateWarning,
|
|
333
|
+
sourceBlock));
|
|
334
|
+
|
|
335
|
+
return result;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Check symbol name
|
|
339
|
+
if (payload.name.empty()) {
|
|
340
|
+
|
|
341
|
+
if (!resource.name.empty()) {
|
|
342
|
+
payload.name = resource.name;
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
// ERR: No name specified for resource model
|
|
346
|
+
std::stringstream ss;
|
|
347
|
+
ss << "resource model can be specified only for a named resource";
|
|
348
|
+
ss << ", name your resource, e.g. '# <resource name> [" << resource.uriTemplate << "]'";
|
|
349
|
+
|
|
350
|
+
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
|
351
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
|
|
352
|
+
result.first.error = Error(ss.str(),
|
|
353
|
+
SymbolError,
|
|
354
|
+
sourceBlock);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Check whether symbol isn't already defined
|
|
359
|
+
ResourceModelSymbolTable::const_iterator it = parser.symbolTable.resourceModels.find(payload.name);
|
|
360
|
+
if (it == parser.symbolTable.resourceModels.end()) {
|
|
361
|
+
|
|
362
|
+
parser.symbolTable.resourceModels[payload.name] = payload;
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
// ERR: Symbol already defined
|
|
366
|
+
std::stringstream ss;
|
|
367
|
+
ss << "symbol '" << payload.name << "' already defined";
|
|
368
|
+
|
|
369
|
+
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
|
370
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
|
|
371
|
+
result.first.error = Error(ss.str(),
|
|
372
|
+
SymbolError,
|
|
373
|
+
sourceBlock);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Assign model
|
|
377
|
+
resource.model = payload;
|
|
378
|
+
|
|
379
|
+
return result;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/** Parse Parameters section */
|
|
383
|
+
static ParseSectionResult HandleParameters(const BlueprintSection& section,
|
|
384
|
+
const BlockIterator& cur,
|
|
385
|
+
BlueprintParserCore& parser,
|
|
386
|
+
Resource& resource) {
|
|
387
|
+
ParameterCollection parameters;
|
|
388
|
+
ParseSectionResult result = ParametersParser::Parse(cur,
|
|
389
|
+
section.bounds.second,
|
|
390
|
+
section,
|
|
391
|
+
parser,
|
|
392
|
+
parameters);
|
|
393
|
+
if (result.first.error.code != Error::OK)
|
|
394
|
+
return result;
|
|
395
|
+
|
|
396
|
+
if (parameters.empty()) {
|
|
397
|
+
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
|
398
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
|
|
399
|
+
result.first.warnings.push_back(Warning(snowcrashconst::NoParametersMessage,
|
|
400
|
+
FormattingWarning,
|
|
401
|
+
sourceBlock));
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
// Check Eligibility
|
|
405
|
+
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
|
406
|
+
CheckParametersEligibility(resource, parameters, nameBlock->sourceMap, parser.sourceData, result.first);
|
|
407
|
+
|
|
408
|
+
// Insert
|
|
409
|
+
resource.parameters.insert(resource.parameters.end(), parameters.begin(), parameters.end());
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return result;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Check parameter eligibility, reporting if a parameter is not specified in URI template */
|
|
416
|
+
static void CheckParametersEligibility(const Resource& resource,
|
|
417
|
+
const ParameterCollection& parameters,
|
|
418
|
+
const SourceDataBlock& location,
|
|
419
|
+
const SourceData& sourceData,
|
|
420
|
+
Result& result)
|
|
421
|
+
{
|
|
422
|
+
for (ParameterCollection::const_iterator it = parameters.begin();
|
|
423
|
+
it != parameters.end();
|
|
424
|
+
++it) {
|
|
425
|
+
|
|
426
|
+
// Naive check whether parameter is present in URI Template
|
|
427
|
+
if (resource.uriTemplate.find(it->name) == std::string::npos) {
|
|
428
|
+
// WARN: parameter name not present
|
|
429
|
+
std::stringstream ss;
|
|
430
|
+
ss << "parameter '" << it->name << "' not specified in ";
|
|
431
|
+
if (!resource.name.empty())
|
|
432
|
+
ss << "'" << resource.name << "' ";
|
|
433
|
+
ss << "its '" << resource.uriTemplate << "' URI template";
|
|
434
|
+
|
|
435
|
+
result.warnings.push_back(Warning(ss.str(),
|
|
436
|
+
LogicalErrorWarning,
|
|
437
|
+
MapSourceDataBlock(location, sourceData)));
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
static ParseSectionResult HandleResourceMethod(const BlueprintSection& section,
|
|
443
|
+
const BlockIterator& cur,
|
|
444
|
+
BlueprintParserCore& parser,
|
|
445
|
+
Resource& resource) {
|
|
446
|
+
|
|
447
|
+
// Retrieve URI template
|
|
448
|
+
HTTPMethod method;
|
|
449
|
+
GetResourceSignature(*cur, resource.name, resource.uriTemplate, method);
|
|
450
|
+
|
|
451
|
+
// Parse as a resource action abbreviation
|
|
452
|
+
return HandleAction(section, cur, parser, resource, true);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
static ParseSectionResult HandleAction(const BlueprintSection& section,
|
|
456
|
+
const BlockIterator& cur,
|
|
457
|
+
BlueprintParserCore& parser,
|
|
458
|
+
Resource& resource,
|
|
459
|
+
bool abbrev = false)
|
|
460
|
+
{
|
|
461
|
+
Action action;
|
|
462
|
+
ParseSectionResult result = ActionParser::Parse(cur,
|
|
463
|
+
section.bounds.second,
|
|
464
|
+
section,
|
|
465
|
+
parser,
|
|
466
|
+
action);
|
|
467
|
+
if (result.first.error.code != Error::OK)
|
|
468
|
+
return result;
|
|
469
|
+
|
|
470
|
+
if (!abbrev) {
|
|
471
|
+
Name name;
|
|
472
|
+
HTTPMethod httpMethod;
|
|
473
|
+
ActionSignature actionSignature = GetActionSignature(*cur, name, httpMethod);
|
|
474
|
+
|
|
475
|
+
if (actionSignature == MethodURIActionSignature) {
|
|
476
|
+
// WARN: ignoring extraneous content in action header
|
|
477
|
+
std::stringstream ss;
|
|
478
|
+
ss << "ignoring additional content in method header '" << cur->content << "'";
|
|
479
|
+
ss << ", expected method-only e.g. '# " << action.method << "'";
|
|
480
|
+
|
|
481
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, parser.sourceData);
|
|
482
|
+
result.first.warnings.push_back(Warning(ss.str(),
|
|
483
|
+
IgnoringWarning,
|
|
484
|
+
sourceBlock));
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
Collection<Action>::iterator duplicate = FindAction(resource, action);
|
|
489
|
+
if (duplicate != resource.actions.end()) {
|
|
490
|
+
|
|
491
|
+
// WARN: duplicate method
|
|
492
|
+
std::stringstream ss;
|
|
493
|
+
ss << "action with method '" << action.method << "' already defined for resource '";
|
|
494
|
+
ss << resource.uriTemplate << "'";
|
|
495
|
+
|
|
496
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, parser.sourceData);
|
|
497
|
+
result.first.warnings.push_back(Warning(ss.str(),
|
|
498
|
+
DuplicateWarning,
|
|
499
|
+
sourceBlock));
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Check Eligibility
|
|
503
|
+
if (!action.parameters.empty())
|
|
504
|
+
CheckParametersEligibility(resource, action.parameters, cur->sourceMap, parser.sourceData, result.first);
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
// Check for header duplictes
|
|
508
|
+
DeepCheckHeaderDuplicates(resource, action, cur->sourceMap, parser.sourceData, result.first);
|
|
509
|
+
|
|
510
|
+
if (action.examples.empty() ||
|
|
511
|
+
action.examples.front().responses.empty()) {
|
|
512
|
+
// WARN: method has no response
|
|
513
|
+
std::stringstream ss;
|
|
514
|
+
ss << "no response defined for '" << action.method << " " << resource.uriTemplate << "'";
|
|
515
|
+
|
|
516
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, parser.sourceData);
|
|
517
|
+
result.first.warnings.push_back(Warning(ss.str(),
|
|
518
|
+
EmptyDefinitionWarning,
|
|
519
|
+
sourceBlock));
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
resource.actions.push_back(action);
|
|
523
|
+
return result;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
static void DeepCheckHeaderDuplicates(const Resource& resource,
|
|
527
|
+
const Action& action,
|
|
528
|
+
const SourceDataBlock& sourceMap,
|
|
529
|
+
const SourceData& sourceData,
|
|
530
|
+
Result& result) {
|
|
531
|
+
|
|
532
|
+
if (action.examples.empty())
|
|
533
|
+
return;
|
|
534
|
+
|
|
535
|
+
CheckHeaderDuplicates(resource, action, sourceMap, sourceData, result);
|
|
536
|
+
for (Collection<Request>::const_iterator it = action.examples.front().requests.begin();
|
|
537
|
+
it != action.examples.front().requests.end();
|
|
538
|
+
++it) {
|
|
539
|
+
|
|
540
|
+
CheckHeaderDuplicates(resource, *it, sourceMap, sourceData, result);
|
|
541
|
+
}
|
|
542
|
+
for (Collection<Response>::const_iterator it = action.examples.front().responses.begin();
|
|
543
|
+
it != action.examples.front().responses.end();
|
|
544
|
+
++it) {
|
|
545
|
+
|
|
546
|
+
CheckHeaderDuplicates(resource, *it, sourceMap, sourceData, result);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Check whether abbreviated resource action isn't followed by an
|
|
551
|
+
// action header which would imply possible additional method intended.
|
|
552
|
+
static void CheckAmbiguousMethod(const BlueprintSection& section,
|
|
553
|
+
const BlockIterator& cur,
|
|
554
|
+
const Resource& resource,
|
|
555
|
+
const SourceData& sourceData,
|
|
556
|
+
Result& result) {
|
|
557
|
+
|
|
558
|
+
if (cur == section.bounds.second ||
|
|
559
|
+
cur->type != HeaderBlockType)
|
|
560
|
+
return;
|
|
561
|
+
|
|
562
|
+
Name name;
|
|
563
|
+
HTTPMethod method;
|
|
564
|
+
ActionSignature actionSignature = GetActionSignature(*cur, name, method);
|
|
565
|
+
if (actionSignature == MethodActionSignature ||
|
|
566
|
+
actionSignature == NamedActionSignature) {
|
|
567
|
+
// WARN: ignoring possible method header
|
|
568
|
+
std::stringstream ss;
|
|
569
|
+
ss << "unexpected action '" << cur->content << "', ";
|
|
570
|
+
ss << "to the define muliple actions for the '" << resource.uriTemplate << "' resource omit the HTTP method in its definition, ";
|
|
571
|
+
ss << "e.g. '# " << resource.uriTemplate << "'";
|
|
572
|
+
|
|
573
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur, section.bounds.second, section.bounds, sourceData);
|
|
574
|
+
result.warnings.push_back(Warning(ss.str(),
|
|
575
|
+
IgnoringWarning,
|
|
576
|
+
sourceBlock));
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
typedef BlockParser<Resource, SectionParser<Resource> > ResourceParser;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
#endif
|