ext/snowcrash/src/ActionParser.h in redsnow-0.2.0 vs ext/snowcrash/src/ActionParser.h in redsnow-0.2.1
- old
+ new
@@ -21,13 +21,11 @@
const char* const ActionHeaderRegex = "^[[:blank:]]*" HTTP_REQUEST_METHOD "[[:blank:]]*" URI_TEMPLATE "?$";
/** Named action matching regex */
const char* const NamedActionHeaderRegex = "^[[:blank:]]*" SYMBOL_IDENTIFIER "\\[" HTTP_REQUEST_METHOD "]$";
- /** Internal type alias for Collection of Action */
- typedef Collection<Action>::type Actions;
-
+ /** Internal type alias for Collection iterator of Action */
typedef Collection<Action>::const_iterator ActionIterator;
/** Action Definition Type */
enum ActionType {
NotActionType = 0,
@@ -44,73 +42,118 @@
static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
const MarkdownNodes& siblings,
SectionParserData& pd,
SectionLayout& layout,
- Report& report,
- Action& out) {
+ ParseResult<Action>& out) {
- actionHTTPMethodAndName(node, out.method, out.name);
- TrimString(out.name);
+ actionHTTPMethodAndName(node, out.node.method, out.node.name);
+ TrimString(out.node.name);
mdp::ByteBuffer remainingContent;
GetFirstLine(node->text, remainingContent);
+ if (pd.exportSourceMap()) {
+ if (!out.node.method.empty()) {
+ out.sourceMap.method.sourceMap = node->sourceMap;
+ }
+
+ if (!out.node.name.empty()) {
+ out.sourceMap.name.sourceMap = node->sourceMap;
+ }
+ }
+
if (!remainingContent.empty()) {
- out.description += remainingContent;
+ out.node.description += remainingContent;
+
+ if (pd.exportSourceMap()) {
+ out.sourceMap.description.sourceMap.append(node->sourceMap);
+ }
}
return ++MarkdownNodeIterator(node);
}
static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
const MarkdownNodes& siblings,
SectionParserData& pd,
- Report& report,
- Action& out) {
+ ParseResult<Action>& out) {
SectionType sectionType = pd.sectionContext();
MarkdownNodeIterator cur = node;
- Payload payload;
std::stringstream ss;
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
switch (sectionType) {
case ParametersSectionType:
- return ParametersParser::parse(node, siblings, pd, report, out.parameters);
+ {
+ ParseResult<Parameters> parameters(out.report, out.node.parameters, out.sourceMap.parameters);
+ return ParametersParser::parse(node, siblings, pd, parameters);
+ }
case RequestSectionType:
case RequestBodySectionType:
- cur = PayloadParser::parse(node, siblings, pd, report, payload);
+ {
+ ParseResult<Payload> payload(out.report);
+ cur = PayloadParser::parse(node, siblings, pd, payload);
- if (out.examples.empty() || !out.examples.back().responses.empty()) {
+ if (out.node.examples.empty() || !out.node.examples.back().responses.empty()) {
TransactionExample transaction;
- out.examples.push_back(transaction);
+ SourceMap<TransactionExample> transactionSM;
+
+ out.node.examples.push_back(transaction);
+
+ if (pd.exportSourceMap()) {
+ out.sourceMap.examples.collection.push_back(transactionSM);
+ }
}
- checkPayload(sectionType, sourceMap, payload, out, report);
+ checkPayload(sectionType, sourceMap, payload.node, out);
- out.examples.back().requests.push_back(payload);
+ out.node.examples.back().requests.push_back(payload.node);
+
+ if (pd.exportSourceMap()) {
+ out.sourceMap.examples.collection.back().requests.collection.push_back(payload.sourceMap);
+ }
+
break;
+ }
case ResponseSectionType:
case ResponseBodySectionType:
- cur = PayloadParser::parse(node, siblings, pd, report, payload);
+ {
+ ParseResult<Payload> payload(out.report);
+ cur = PayloadParser::parse(node, siblings, pd, payload);
- if (out.examples.empty()) {
+ if (out.node.examples.empty()) {
TransactionExample transaction;
- out.examples.push_back(transaction);
+ SourceMap<TransactionExample> transactionSM;
+
+ out.node.examples.push_back(transaction);
+
+ if (pd.exportSourceMap()) {
+ out.sourceMap.examples.collection.push_back(transactionSM);
+ }
}
- checkPayload(sectionType, sourceMap, payload, out, report);
+ checkPayload(sectionType, sourceMap, payload.node, out);
- out.examples.back().responses.push_back(payload);
+ out.node.examples.back().responses.push_back(payload.node);
+
+ if (pd.exportSourceMap()) {
+ out.sourceMap.examples.collection.back().responses.collection.push_back(payload.sourceMap);
+ }
+
break;
+ }
case HeadersSectionType:
- return SectionProcessor<Action>::handleDeprecatedHeaders(node, siblings, pd, report, out.headers);
+ {
+ ParseResult<Headers> headers(out.report, out.node.headers, out.sourceMap.headers);
+ return SectionProcessor<Action>::handleDeprecatedHeaders(node, siblings, pd, headers);
+ }
default:
break;
}
@@ -118,45 +161,52 @@
}
static bool isUnexpectedNode(const MarkdownNodeIterator& node,
SectionType sectionType) {
- if ( SectionProcessor<Asset>::sectionType(node) != UndefinedSectionType) {
+ if (SectionProcessor<Asset>::sectionType(node) != UndefinedSectionType) {
return true;
}
return SectionProcessorBase<Action>::isUnexpectedNode(node, sectionType);
}
static MarkdownNodeIterator processUnexpectedNode(const MarkdownNodeIterator& node,
const MarkdownNodes& siblings,
SectionParserData& pd,
SectionType& sectionType,
- Report& report,
- Action& out) {
+ ParseResult<Action>& out) {
if ((node->type == mdp::ParagraphMarkdownNodeType ||
node->type == mdp::CodeMarkdownNodeType) &&
(sectionType == ResponseBodySectionType ||
sectionType == ResponseSectionType) &&
- !out.examples.empty() &&
- !out.examples.back().responses.empty()) {
+ !out.node.examples.empty() &&
+ !out.node.examples.back().responses.empty()) {
- CodeBlockUtility::addDanglingAsset(node, pd, sectionType, report, out.examples.back().responses.back().body);
-
+ mdp::ByteBuffer content = CodeBlockUtility::addDanglingAsset(node, pd, sectionType, out.report, out.node.examples.back().responses.back().body);
+
+ if (pd.exportSourceMap() && !content.empty()) {
+ out.sourceMap.examples.collection.back().responses.collection.back().body.sourceMap.append(node->sourceMap);
+ }
+
return ++MarkdownNodeIterator(node);
}
if ((node->type == mdp::ParagraphMarkdownNodeType ||
node->type == mdp::CodeMarkdownNodeType) &&
(sectionType == RequestBodySectionType ||
sectionType == RequestSectionType) &&
- !out.examples.empty() &&
- !out.examples.back().requests.empty()) {
+ !out.node.examples.empty() &&
+ !out.node.examples.back().requests.empty()) {
- CodeBlockUtility::addDanglingAsset(node, pd, sectionType, report, out.examples.back().requests.back().body);
-
+ mdp::ByteBuffer content = CodeBlockUtility::addDanglingAsset(node, pd, sectionType, out.report, out.node.examples.back().requests.back().body);
+
+ if (pd.exportSourceMap() && !content.empty()) {
+ out.sourceMap.examples.collection.back().requests.collection.back().body.sourceMap.append(node->sourceMap);
+ }
+
return ++MarkdownNodeIterator(node);
}
SectionType assetType = SectionProcessor<Asset>::sectionType(node);
@@ -167,18 +217,18 @@
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
ss << "Ignoring " << SectionName(assetType) << " list item, ";
ss << SectionName(assetType) << " list item is expected to be indented by 4 spaces or 1 tab";
- report.warnings.push_back(Warning(ss.str(),
- IgnoringWarning,
- sourceMap));
+ out.report.warnings.push_back(Warning(ss.str(),
+ IgnoringWarning,
+ sourceMap));
return ++MarkdownNodeIterator(node);
}
- return SectionProcessorBase<Action>::processUnexpectedNode(node, siblings, pd, sectionType, report, out);
+ return SectionProcessorBase<Action>::processUnexpectedNode(node, siblings, pd, sectionType, out);
}
static SectionType sectionType(const MarkdownNodeIterator& node) {
if (node->type == mdp::HeaderMarkdownNodeType
@@ -240,44 +290,47 @@
return nested;
}
static void finalize(const MarkdownNodeIterator& node,
SectionParserData& pd,
- Report& report,
- Action& out) {
+ ParseResult<Action>& out) {
- if (!out.headers.empty()) {
+ if (!out.node.headers.empty()) {
- SectionProcessor<Headers>::injectDeprecatedHeaders(out.headers, out.examples);
- out.headers.clear();
+ SectionProcessor<Headers>::injectDeprecatedHeaders(pd, out.node.headers, out.sourceMap.headers, out.node.examples, out.sourceMap.examples);
+ out.node.headers.clear();
+
+ if (pd.exportSourceMap()) {
+ out.sourceMap.headers.collection.clear();
+ }
}
- if (out.examples.empty()) {
+ if (out.node.examples.empty()) {
// WARN: No response for action
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
- report.warnings.push_back(Warning("action is missing a response",
- EmptyDefinitionWarning,
- sourceMap));
- } else if (!out.examples.empty() &&
- !out.examples.back().requests.empty() &&
- out.examples.back().responses.empty()) {
+ out.report.warnings.push_back(Warning("action is missing a response",
+ EmptyDefinitionWarning,
+ sourceMap));
+ } else if (!out.node.examples.empty() &&
+ !out.node.examples.back().requests.empty() &&
+ out.node.examples.back().responses.empty()) {
// WARN: No response for request
std::stringstream ss;
ss << "action is missing a response for ";
- if (out.examples.back().requests.back().name.empty()) {
+ if (out.node.examples.back().requests.back().name.empty()) {
ss << "a request";
} else {
- ss << "the '" << out.examples.back().requests.back().name << "' request";
+ ss << "the '" << out.node.examples.back().requests.back().name << "' request";
}
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
- report.warnings.push_back(Warning(ss.str(),
- EmptyDefinitionWarning,
- sourceMap));
+ out.report.warnings.push_back(Warning(ss.str(),
+ EmptyDefinitionWarning,
+ sourceMap));
}
}
/**
* \brief Check & report payload validity.
@@ -288,54 +341,53 @@
* \param report Parser report.
*/
static void checkPayload(SectionType sectionType,
const mdp::CharactersRangeSet sourceMap,
const Payload& payload,
- const Action& action,
- Report& report) {
+ ParseResult<Action>& out) {
- if (isPayloadDuplicate(sectionType, payload, action.examples.back())) {
+ if (isPayloadDuplicate(sectionType, payload, out.node.examples.back())) {
// WARN: Duplicate payload
std::stringstream ss;
ss << SectionName(sectionType) << " payload `" << payload.name << "`";
- ss << " already defined for `" << action.method << "` method";
+ ss << " already defined for `" << out.node.method << "` method";
- report.warnings.push_back(Warning(ss.str(),
- DuplicateWarning,
- sourceMap));
+ out.report.warnings.push_back(Warning(ss.str(),
+ DuplicateWarning,
+ sourceMap));
}
if (sectionType == ResponseSectionType || sectionType == ResponseBodySectionType) {
HTTPStatusCode code;
if (!payload.name.empty()) {
std::stringstream(payload.name) >> code;
}
- HTTPMethodTraits methodTraits = GetMethodTrait(action.method);
+ HTTPMethodTraits methodTraits = GetMethodTrait(out.node.method);
if (!methodTraits.allowBody && !payload.body.empty()) {
// WARN: Edge case for 2xx CONNECT
- if (action.method == HTTPMethodName::Connect && code/100 == 2) {
+ if (out.node.method == HTTPMethodName::Connect && code/100 == 2) {
std::stringstream ss;
- ss << "the response for " << code << " " << action.method << " request MUST NOT include a " << SectionName(BodySectionType);
+ ss << "the response for " << code << " " << out.node.method << " request MUST NOT include a " << SectionName(BodySectionType);
- report.warnings.push_back(Warning(ss.str(),
- EmptyDefinitionWarning,
- sourceMap));
- } else if (action.method != HTTPMethodName::Connect && !methodTraits.allowBody) {
+ out.report.warnings.push_back(Warning(ss.str(),
+ EmptyDefinitionWarning,
+ sourceMap));
+ } else if (out.node.method != HTTPMethodName::Connect && !methodTraits.allowBody) {
std::stringstream ss;
- ss << "the response for " << action.method << " request MUST NOT include a " << SectionName(BodySectionType);
+ ss << "the response for " << out.node.method << " request MUST NOT include a " << SectionName(BodySectionType);
- report.warnings.push_back(Warning(ss.str(),
- EmptyDefinitionWarning,
- sourceMap));
+ out.report.warnings.push_back(Warning(ss.str(),
+ EmptyDefinitionWarning,
+ sourceMap));
}
return;
}
}
@@ -349,38 +401,37 @@
const Payload& payload,
const TransactionExample& example) {
if (sectionType == RequestSectionType) {
- Collection<Request>::const_iterator duplicate = FindRequest(example, payload);
+ RequestIterator duplicate = SectionProcessor<Payload>::findRequest(example, payload);
return duplicate != example.requests.end();
} else if (sectionType == ResponseSectionType) {
- Collection<Response>::const_iterator duplicate = FindResponse(example, payload);
+ ResponseIterator duplicate = SectionProcessor<Payload>::findResponse(example, payload);
return duplicate != example.responses.end();
}
return false;
}
/** Warn about deprecated headers */
static MarkdownNodeIterator handleDeprecatedHeaders(const MarkdownNodeIterator& node,
const MarkdownNodes& siblings,
SectionParserData& pd,
- Report& report,
- Headers& headers) {
+ ParseResult<Headers>& out) {
- MarkdownNodeIterator cur = HeadersParser::parse(node, siblings, pd, report, headers);
+ MarkdownNodeIterator cur = HeadersParser::parse(node, siblings, pd, out);
// WARN: Deprecated header sections
std::stringstream ss;
ss << "the 'headers' section at this level is deprecated and will be removed in a future, use respective payload header section(s) instead";
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
- report.warnings.push_back(Warning(ss.str(),
- DeprecatedWarning,
- sourceMap));
+ out.report.warnings.push_back(Warning(ss.str(),
+ DeprecatedWarning,
+ sourceMap));
return cur;
}
/** \return %ActionType of a node */
@@ -427,9 +478,18 @@
name = captureGroups[1];
method = captureGroups[2];
}
return;
+ }
+
+ /** Finds an action inside an actions collection */
+ static ActionIterator findAction(const Actions& actions,
+ const Action& action) {
+
+ return std::find_if(actions.begin(),
+ actions.end(),
+ std::bind2nd(MatchAction<Action>(), action));
}
};
/** Action Section Parser */
typedef SectionParser<Action, HeaderSectionAdapter> ActionParser;