redsnow 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2 -0
  3. data/ext/snowcrash/bin/snowcrash +0 -0
  4. data/ext/snowcrash/snowcrash.xcworkspace/contents.xcworkspacedata +10 -0
  5. data/ext/snowcrash/src/ActionParser.h +35 -33
  6. data/ext/snowcrash/src/AssetParser.h +17 -17
  7. data/ext/snowcrash/src/Blueprint.h +101 -66
  8. data/ext/snowcrash/src/BlueprintParser.h +219 -10
  9. data/ext/snowcrash/src/BlueprintSourcemap.h +1 -1
  10. data/ext/snowcrash/src/BlueprintUtility.h +14 -14
  11. data/ext/snowcrash/src/CBlueprint.cc +29 -10
  12. data/ext/snowcrash/src/CBlueprint.h +19 -3
  13. data/ext/snowcrash/src/CBlueprintSourcemap.cc +20 -10
  14. data/ext/snowcrash/src/CBlueprintSourcemap.h +12 -3
  15. data/ext/snowcrash/src/CodeBlockUtility.h +25 -25
  16. data/ext/snowcrash/src/HTTP.cc +3 -0
  17. data/ext/snowcrash/src/HTTP.h +9 -6
  18. data/ext/snowcrash/src/HeadersParser.h +34 -14
  19. data/ext/snowcrash/src/ParameterParser.h +21 -21
  20. data/ext/snowcrash/src/ParametersParser.h +6 -5
  21. data/ext/snowcrash/src/PayloadParser.h +174 -129
  22. data/ext/snowcrash/src/RegexMatch.h +3 -3
  23. data/ext/snowcrash/src/ResourceGroupParser.h +5 -4
  24. data/ext/snowcrash/src/ResourceParser.h +30 -26
  25. data/ext/snowcrash/src/Section.cc +6 -6
  26. data/ext/snowcrash/src/Section.h +2 -2
  27. data/ext/snowcrash/src/SectionParser.h +41 -41
  28. data/ext/snowcrash/src/SectionParserData.h +10 -10
  29. data/ext/snowcrash/src/SectionProcessor.h +70 -30
  30. data/ext/snowcrash/src/Serialize.h +3 -3
  31. data/ext/snowcrash/src/SerializeJSON.cc +124 -96
  32. data/ext/snowcrash/src/SerializeJSON.h +1 -1
  33. data/ext/snowcrash/src/SerializeYAML.cc +71 -53
  34. data/ext/snowcrash/src/SerializeYAML.h +1 -1
  35. data/ext/snowcrash/src/Signature.cc +2 -2
  36. data/ext/snowcrash/src/Signature.h +1 -1
  37. data/ext/snowcrash/src/SourceAnnotation.h +23 -23
  38. data/ext/snowcrash/src/StringUtility.h +71 -9
  39. data/ext/snowcrash/src/SymbolTable.h +17 -17
  40. data/ext/snowcrash/src/UriTemplateParser.cc +5 -5
  41. data/ext/snowcrash/src/UriTemplateParser.h +9 -9
  42. data/ext/snowcrash/src/ValuesParser.h +2 -2
  43. data/ext/snowcrash/src/Version.h +1 -1
  44. data/ext/snowcrash/src/csnowcrash.cc +10 -8
  45. data/ext/snowcrash/src/snowcrash.cc +9 -9
  46. data/ext/snowcrash/src/snowcrash.h +6 -8
  47. data/ext/snowcrash/src/snowcrash/snowcrash.cc +14 -14
  48. data/ext/snowcrash/src/win/RegexMatch.cc +7 -7
  49. data/ext/snowcrash/tools/gyp/pylib/gyp/__init__.pyc +0 -0
  50. data/ext/snowcrash/tools/gyp/pylib/gyp/common.pyc +0 -0
  51. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/__init__.pyc +0 -0
  52. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/make.pyc +0 -0
  53. data/ext/snowcrash/tools/gyp/pylib/gyp/generator/xcode.pyc +0 -0
  54. data/ext/snowcrash/tools/gyp/pylib/gyp/input.pyc +0 -0
  55. data/ext/snowcrash/tools/gyp/pylib/gyp/xcode_emulation.pyc +0 -0
  56. data/ext/snowcrash/tools/gyp/pylib/gyp/xcodeproj_file.pyc +0 -0
  57. data/ext/snowcrash/tools/homebrew/snowcrash.rb +1 -1
  58. data/lib/redsnow/binding.rb +8 -2
  59. data/lib/redsnow/blueprint.rb +4 -3
  60. data/lib/redsnow/sourcemap.rb +6 -4
  61. data/lib/redsnow/version.rb +1 -1
  62. metadata +4 -17
@@ -39,13 +39,13 @@ namespace snowcrash {
39
39
 
40
40
  /** Additonal Parameter Traits Type matching regex */
41
41
  const char* const AdditionalTraitsTypeRegex = CSV_LEADINOUT "([^,]*)" CSV_LEADINOUT;
42
-
42
+
43
43
  /** Parameter Values matching regex */
44
44
  const char* const ParameterValuesRegex = "^[[:blank:]]*[Vv]alues[[:blank:]]*$";
45
45
 
46
46
  /** Values expected content */
47
47
  const char* const ExpectedValuesContent = "nested list of possible parameter values, one element per list item e.g. '`value`'";
48
-
48
+
49
49
  /** Parameter description delimiter */
50
50
  const std::string DescriptionIdentifier = "...";
51
51
 
@@ -59,7 +59,7 @@ namespace snowcrash {
59
59
  const MarkdownNodes& siblings,
60
60
  SectionParserData& pd,
61
61
  SectionLayout& layout,
62
- ParseResult<Parameter>& out) {
62
+ const ParseResultRef<Parameter>& out) {
63
63
 
64
64
  mdp::ByteBuffer signature, remainingContent;
65
65
  signature = GetFirstLine(node->text, remainingContent);
@@ -81,7 +81,7 @@ namespace snowcrash {
81
81
  static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
82
82
  const MarkdownNodes& siblings,
83
83
  SectionParserData& pd,
84
- ParseResult<Parameter>& out) {
84
+ const ParseResultRef<Parameter>& out) {
85
85
 
86
86
  if (pd.sectionContext() != ValuesSectionType) {
87
87
  return node;
@@ -107,7 +107,7 @@ namespace snowcrash {
107
107
  out.sourceMap.values.collection.clear();
108
108
  }
109
109
 
110
- ParseResult<Values> values(out.report, out.node.values, out.sourceMap.values);
110
+ ParseResultRef<Values> values(out.report, out.node.values, out.sourceMap.values);
111
111
  ValuesParser::parse(node, siblings, pd, values);
112
112
 
113
113
  if (out.node.values.empty()) {
@@ -163,7 +163,7 @@ namespace snowcrash {
163
163
  static void parseSignature(const mdp::MarkdownNodeIterator& node,
164
164
  SectionParserData& pd,
165
165
  mdp::ByteBuffer& signature,
166
- ParseResult<Parameter>& out) {
166
+ const ParseResultRef<Parameter>& out) {
167
167
 
168
168
  out.node.use = UndefinedParameterUse;
169
169
 
@@ -172,10 +172,10 @@ namespace snowcrash {
172
172
  CaptureGroups captureGroups;
173
173
 
174
174
  if (isValidParameterSignature(signature)) {
175
-
175
+
176
176
  mdp::ByteBuffer innerSignature = signature;
177
177
  innerSignature = TrimString(innerSignature);
178
-
178
+
179
179
  size_t firstSpace = innerSignature.find(" ");
180
180
 
181
181
  if (firstSpace == std::string::npos) {
@@ -196,7 +196,7 @@ namespace snowcrash {
196
196
  innerSignature = innerSignature.substr(0, descriptionPos);
197
197
  innerSignature = TrimString(innerSignature);
198
198
  }
199
-
199
+
200
200
  size_t attributesPos = innerSignature.find("(");
201
201
 
202
202
  if (attributesPos != std::string::npos) {
@@ -212,7 +212,7 @@ namespace snowcrash {
212
212
  innerSignature = TrimString(innerSignature);
213
213
  }
214
214
  }
215
-
215
+
216
216
  if (innerSignature.length() > 0) {
217
217
  // Remove =
218
218
  out.node.defaultValue = innerSignature;
@@ -264,7 +264,7 @@ namespace snowcrash {
264
264
  static void parseAdditionalTraits(const mdp::MarkdownNodeIterator& node,
265
265
  SectionParserData& pd,
266
266
  mdp::ByteBuffer& traits,
267
- ParseResult<Parameter>& out) {
267
+ const ParseResultRef<Parameter>& out) {
268
268
 
269
269
  TrimString(traits);
270
270
 
@@ -351,7 +351,7 @@ namespace snowcrash {
351
351
 
352
352
  static void checkExampleAndDefaultValue(const mdp::MarkdownNodeIterator& node,
353
353
  SectionParserData& pd,
354
- ParseResult<Parameter>& out) {
354
+ const ParseResultRef<Parameter>& out) {
355
355
 
356
356
  bool isExampleFound = false;
357
357
  bool isDefaultFound = false;
@@ -395,23 +395,23 @@ namespace snowcrash {
395
395
  sourceMap));
396
396
  }
397
397
  }
398
-
398
+
399
399
  /** Determine if a signature is a valid parameter*/
400
400
  static bool isValidParameterSignature(const mdp::ByteBuffer& signature) {
401
-
401
+
402
402
  mdp::ByteBuffer innerSignature = signature;
403
403
  innerSignature = TrimString(innerSignature);
404
-
404
+
405
405
  if (innerSignature.length() == 0) {
406
406
  return false; // Empty string, invalid
407
407
  }
408
-
408
+
409
409
  size_t firstSpace = innerSignature.find(" ");
410
410
 
411
411
  if (firstSpace == std::string::npos) {
412
412
  return RegexMatch(innerSignature, "^" PARAMETER_IDENTIFIER "$");
413
413
  }
414
-
414
+
415
415
  std::string paramName = innerSignature.substr(0, firstSpace);
416
416
 
417
417
  if (!RegexMatch(paramName, "^" PARAMETER_IDENTIFIER "$")) {
@@ -427,7 +427,7 @@ namespace snowcrash {
427
427
  innerSignature = innerSignature.substr(0, descriptionPos);
428
428
  innerSignature = TrimString(innerSignature);
429
429
  }
430
-
430
+
431
431
  size_t attributesPos = innerSignature.find("(");
432
432
 
433
433
  if (attributesPos != std::string::npos) {
@@ -441,11 +441,11 @@ namespace snowcrash {
441
441
  innerSignature = innerSignature.substr(0, attributesPos);
442
442
  innerSignature = TrimString(innerSignature);
443
443
  }
444
-
444
+
445
445
  if (innerSignature.length() == 0) {
446
446
  return true;
447
447
  }
448
-
448
+
449
449
  if (innerSignature.substr(0,1) == "=") {
450
450
  innerSignature = innerSignature.substr(1);
451
451
  innerSignature = TrimString(innerSignature);
@@ -458,7 +458,7 @@ namespace snowcrash {
458
458
  return true;
459
459
  }
460
460
  }
461
-
461
+
462
462
  return false;
463
463
  }
464
464
 
@@ -36,7 +36,7 @@ namespace snowcrash {
36
36
  const MarkdownNodes& siblings,
37
37
  SectionParserData& pd,
38
38
  SectionLayout& layout,
39
- ParseResult<Parameters>& out) {
39
+ const ParseResultRef<Parameters>& out) {
40
40
 
41
41
  mdp::ByteBuffer remainingContent;
42
42
 
@@ -61,7 +61,7 @@ namespace snowcrash {
61
61
  static MarkdownNodeIterator processDescription(const MarkdownNodeIterator& node,
62
62
  const MarkdownNodes& siblings,
63
63
  SectionParserData& pd,
64
- ParseResult<Parameters>& out) {
64
+ const ParseResultRef<Parameters>& out) {
65
65
 
66
66
  return node;
67
67
  }
@@ -69,13 +69,14 @@ namespace snowcrash {
69
69
  static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
70
70
  const MarkdownNodes& siblings,
71
71
  SectionParserData& pd,
72
- ParseResult<Parameters>& out) {
72
+ const ParseResultRef<Parameters>& out) {
73
73
 
74
74
  if (pd.sectionContext() != ParameterSectionType) {
75
75
  return node;
76
76
  }
77
77
 
78
- ParseResult<Parameter> parameter(out.report);
78
+ IntermediateParseResult<Parameter> parameter(out.report);
79
+
79
80
  ParameterParser::parse(node, siblings, pd, parameter);
80
81
 
81
82
  if (!out.node.empty()) {
@@ -146,7 +147,7 @@ namespace snowcrash {
146
147
 
147
148
  static void finalize(const MarkdownNodeIterator& node,
148
149
  SectionParserData& pd,
149
- ParseResult<Parameters>& out) {
150
+ const ParseResultRef<Parameters>& out) {
150
151
 
151
152
  if (out.node.empty()) {
152
153
 
@@ -52,7 +52,7 @@ namespace snowcrash {
52
52
  const MarkdownNodes& siblings,
53
53
  SectionParserData& pd,
54
54
  SectionLayout& layout,
55
- ParseResult<Payload>& out) {
55
+ const ParseResultRef<Payload>& out) {
56
56
 
57
57
  mdp::ByteBuffer signature, remainingContent;
58
58
  signature = GetFirstLine(node->text, remainingContent);
@@ -97,16 +97,16 @@ namespace snowcrash {
97
97
  static MarkdownNodeIterator processContent(const MarkdownNodeIterator& node,
98
98
  const MarkdownNodes& siblings,
99
99
  SectionParserData& pd,
100
- ParseResult<Payload>& out) {
100
+ const ParseResultRef<Payload>& out) {
101
101
 
102
102
  mdp::ByteBuffer content;
103
103
 
104
- if (!out.node.symbol.empty()) {
104
+ if (!out.node.reference.id.empty()) {
105
105
  //WARN: ignoring extraneous content after symbol reference
106
106
  std::stringstream ss;
107
107
 
108
108
  ss << "ignoring extraneous content after symbol reference";
109
- ss << ", expected symbol reference only e.g. '[" << out.node.symbol << "][]'";
109
+ ss << ", expected symbol reference only e.g. '[" << out.node.reference.id << "][]'";
110
110
 
111
111
  mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
112
112
  out.report.warnings.push_back(Warning(ss.str(),
@@ -138,12 +138,12 @@ namespace snowcrash {
138
138
  static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
139
139
  const MarkdownNodes& siblings,
140
140
  SectionParserData& pd,
141
- ParseResult<Payload>& out) {
141
+ const ParseResultRef<Payload>& out) {
142
142
 
143
143
  switch (pd.sectionContext()) {
144
144
  case HeadersSectionType:
145
145
  {
146
- ParseResult<Headers> headers(out.report, out.node.headers, out.sourceMap.headers);
146
+ ParseResultRef<Headers> headers(out.report, out.node.headers, out.sourceMap.headers);
147
147
  return HeadersParser::parse(node, siblings, pd, headers);
148
148
  }
149
149
 
@@ -157,7 +157,7 @@ namespace snowcrash {
157
157
  sourceMap));
158
158
  }
159
159
 
160
- ParseResult<Asset> asset(out.report, out.node.body, out.sourceMap.body);
160
+ ParseResultRef<Asset> asset(out.report, out.node.body, out.sourceMap.body);
161
161
  return AssetParser::parse(node, siblings, pd, asset);
162
162
  }
163
163
 
@@ -171,7 +171,7 @@ namespace snowcrash {
171
171
  sourceMap));
172
172
  }
173
173
 
174
- ParseResult<Asset> asset(out.report, out.node.schema, out.sourceMap.schema);
174
+ ParseResultRef<Asset> asset(out.report, out.node.schema, out.sourceMap.schema);
175
175
  return AssetParser::parse(node, siblings, pd, asset);
176
176
  }
177
177
 
@@ -186,7 +186,7 @@ namespace snowcrash {
186
186
  const MarkdownNodes& siblings,
187
187
  SectionParserData& pd,
188
188
  SectionType& sectionType,
189
- ParseResult<Payload>& out) {
189
+ const ParseResultRef<Payload>& out) {
190
190
 
191
191
  if ((node->type == mdp::ParagraphMarkdownNodeType ||
192
192
  node->type == mdp::CodeMarkdownNodeType) &&
@@ -200,7 +200,7 @@ namespace snowcrash {
200
200
 
201
201
  return ++MarkdownNodeIterator(node);
202
202
  }
203
-
203
+
204
204
  return SectionProcessorBase<Payload>::processUnexpectedNode(node, siblings, pd, sectionType, out);
205
205
  }
206
206
 
@@ -296,73 +296,16 @@ namespace snowcrash {
296
296
 
297
297
  static void finalize(const MarkdownNodeIterator& node,
298
298
  SectionParserData& pd,
299
- ParseResult<Payload>& out) {
300
-
301
- bool warnEmptyBody = false;
302
-
303
- mdp::ByteBuffer contentLength;
304
- mdp::ByteBuffer transferEncoding;
299
+ const ParseResultRef<Payload>& out) {
305
300
 
306
301
  SectionType sectionType = pd.sectionContext();
307
302
 
308
- for (HeaderIterator it = out.node.headers.begin();
309
- it != out.node.headers.end();
310
- ++it) {
303
+ if (sectionType == RequestSectionType || sectionType == RequestBodySectionType) {
311
304
 
312
- if (it->first == HTTPHeaderName::ContentLength) {
313
- contentLength = it->second;
314
- }
305
+ checkRequest(node, pd, out);
306
+ } else if (sectionType == ResponseSectionType || sectionType == ResponseBodySectionType) {
315
307
 
316
- if (it->first == HTTPHeaderName::TransferEncoding) {
317
- transferEncoding = it->second;
318
- }
319
- }
320
-
321
- if ((sectionType == RequestSectionType || sectionType == RequestBodySectionType) && out.node.body.empty()) {
322
-
323
- // Warn when content-length or transfer-encoding is specified or both headers and body are empty
324
- if (out.node.headers.empty()) {
325
- warnEmptyBody = true;
326
- } else {
327
- warnEmptyBody = !contentLength.empty() || !transferEncoding.empty();
328
- }
329
-
330
- if (warnEmptyBody) {
331
- // WARN: empty body
332
- std::stringstream ss;
333
- ss << "empty " << SectionName(sectionType) << " " << SectionName(BodySectionType);
334
-
335
- if (!contentLength.empty()) {
336
- ss << ", expected " << SectionName(BodySectionType) << " for '" << contentLength << "' Content-Length";
337
- } else if (!transferEncoding.empty()) {
338
- ss << ", expected " << SectionName(BodySectionType) << " for '" << transferEncoding << "' Transfer-Encoding";
339
- }
340
-
341
- mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
342
- out.report.warnings.push_back(Warning(ss.str(),
343
- EmptyDefinitionWarning,
344
- sourceMap));
345
- }
346
- } else if ((sectionType == ResponseSectionType || sectionType == ResponseBodySectionType)) {
347
-
348
- HTTPStatusCode code = 200;
349
-
350
- if (!out.node.name.empty()) {
351
- std::stringstream(out.node.name) >> code;
352
- }
353
-
354
- StatusCodeTraits statusCodeTraits = GetStatusCodeTrait(code);
355
-
356
- if (!statusCodeTraits.allowBody && !out.node.body.empty()) {
357
- // WARN: not empty body
358
- std::stringstream ss;
359
- ss << "the " << code << " response MUST NOT include a " << SectionName(BodySectionType);
360
-
361
- mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
362
- out.report.warnings.push_back(Warning(ss.str(),
363
- EmptyDefinitionWarning,
364
- sourceMap));
365
- }
308
+ checkResponse(node, pd, out);
366
309
  }
367
310
  }
368
311
 
@@ -421,7 +364,7 @@ namespace snowcrash {
421
364
  static bool parseSignature(const MarkdownNodeIterator& node,
422
365
  SectionParserData& pd,
423
366
  const mdp::ByteBuffer& signature,
424
- ParseResult<Payload>& out) {
367
+ const ParseResultRef<Payload>& out) {
425
368
 
426
369
  const char* regex;
427
370
  mdp::ByteBuffer mediaType;
@@ -524,93 +467,195 @@ namespace snowcrash {
524
467
  return true;
525
468
  }
526
469
 
470
+ /** Given the reference id(name), initializes reference of the payload accordingly(if possible resolve it) */
527
471
  static bool parseSymbolReference(const MarkdownNodeIterator& node,
528
472
  SectionParserData& pd,
529
473
  mdp::ByteBuffer& source,
530
- ParseResult<Payload>& out) {
474
+ const ParseResultRef<Payload>& out) {
531
475
 
532
- SymbolName symbol;
533
- ResourceModel model;
534
- SourceMap<ResourceModel> modelSM;
476
+ Identifier symbol;
535
477
 
536
478
  TrimString(source);
537
479
 
538
480
  if (GetSymbolReference(source, symbol)) {
539
- out.node.symbol = symbol;
481
+
482
+ out.node.reference.id = symbol;
483
+ out.node.reference.meta.node = node;
484
+ out.node.reference.type = Reference::SymbolReference;
540
485
 
541
486
  if (pd.exportSourceMap() && !symbol.empty()) {
542
- out.sourceMap.symbol.sourceMap = node->sourceMap;
487
+ out.sourceMap.reference.sourceMap = node->sourceMap;
543
488
  }
544
489
 
545
- // If symbol doesn't exist
490
+ // If symbol has not been defined yet in symbol table
546
491
  if (pd.symbolTable.resourceModels.find(symbol) == pd.symbolTable.resourceModels.end()) {
547
492
 
548
- // ERR: Undefined symbol
549
- std::stringstream ss;
550
- ss << "Undefined symbol " << symbol;
551
-
552
- mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
553
- out.report.error = Error(ss.str(), SymbolError, sourceMap);
493
+ out.node.reference.meta.state = Reference::StatePending;
554
494
 
555
495
  return true;
556
496
  }
557
497
 
558
- model = pd.symbolTable.resourceModels.at(symbol);
559
-
560
- out.node.description = model.description;
561
- out.node.parameters = model.parameters;
562
-
563
- HeaderIterator modelContentType = std::find_if(model.headers.begin(),
564
- model.headers.end(),
565
- std::bind2nd(MatchFirstWith<Header, std::string>(),
566
- HTTPHeaderName::ContentType));
567
-
568
- bool isPayloadContentType = !out.node.headers.empty();
569
- bool isModelContentType = modelContentType != model.headers.end();
570
-
571
- if (isPayloadContentType && isModelContentType) {
572
-
573
- // WARN: Ignoring payload content-type, when referencing a model with headers
574
- std::stringstream ss;
575
-
576
- ss << "ignoring additional " << SectionName(pd.sectionContext()) << " header(s), ";
577
- ss << "specify this header(s) in the referenced model definition instead";
578
-
579
- mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
580
- out.report.warnings.push_back(Warning(ss.str(),
581
- IgnoringWarning,
582
- sourceMap));
583
- }
498
+ out.node.reference.meta.state = Reference::StateResolved;
499
+
500
+ assingReferredPayload(pd, out);
501
+
502
+ return true;
503
+ }
504
+
505
+ return false;
506
+ }
507
+
508
+ /**
509
+ * \brief Assigns the reference, referred as reference id(name), into the payload
510
+ * \param pd Section parser state
511
+ * \param out Processed output
512
+ */
513
+ static void assingReferredPayload(SectionParserData& pd,
514
+ const ParseResultRef<Payload>& out) {
515
+
516
+ SourceMap<ResourceModel> modelSM;
517
+ ResourceModel model = pd.symbolTable.resourceModels.at(out.node.reference.id);
518
+
519
+
520
+ out.node.description = model.description;
521
+ out.node.parameters = model.parameters;
522
+
523
+ HeaderIterator modelContentTypeIt = std::find_if(model.headers.begin(),
524
+ model.headers.end(),
525
+ std::bind2nd(MatchFirstWith<Header, std::string>(),
526
+ HTTPHeaderName::ContentType));
527
+
528
+ bool isPayloadContentType = !out.node.headers.empty();
529
+ bool isModelContentType = modelContentTypeIt != model.headers.end();
530
+
531
+ if (isPayloadContentType && isModelContentType) {
532
+
533
+ // WARN: Ignoring payload content-type, when referencing a model with headers
534
+ std::stringstream ss;
535
+
536
+ ss << "ignoring additional " << SectionName(pd.sectionContext()) << " header(s), ";
537
+ ss << "specify this header(s) in the referenced model definition instead";
538
+
539
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(out.node.reference.meta.node->sourceMap, pd.sourceData);
540
+ out.report.warnings.push_back(Warning(ss.str(),
541
+ IgnoringWarning,
542
+ sourceMap));
543
+ }
544
+
545
+ if (isPayloadContentType && !isModelContentType) {
546
+ out.node.headers.insert(out.node.headers.end(), model.headers.begin(), model.headers.end());
547
+ } else {
548
+ out.node.headers = model.headers;
549
+ }
550
+
551
+ out.node.body = model.body;
552
+ out.node.schema = model.schema;
553
+
554
+ if (pd.exportSourceMap()) {
555
+
556
+ modelSM = pd.symbolSourceMapTable.resourceModels.at(out.node.reference.id);
557
+
558
+ out.sourceMap.description = modelSM.description;
559
+ out.sourceMap.parameters = modelSM.parameters;
560
+ out.sourceMap.body = modelSM.body;
561
+ out.sourceMap.schema = modelSM.schema;
584
562
 
585
563
  if (isPayloadContentType && !isModelContentType) {
586
- out.node.headers.insert(out.node.headers.end(), model.headers.begin(), model.headers.end());
564
+ out.sourceMap.headers.collection.insert(out.sourceMap.headers.collection.end(), modelSM.headers.collection.begin(), modelSM.headers.collection.end());
587
565
  } else {
588
- out.node.headers = model.headers;
566
+ out.sourceMap.headers = modelSM.headers;
567
+ }
568
+ }
569
+ }
570
+
571
+ /**
572
+ * \brief Checks request given as out
573
+ * \param node Markdown node
574
+ * \param pd Section parser state
575
+ * \param out Processed output
576
+ */
577
+ static void checkRequest(const MarkdownNodeIterator& node,
578
+ SectionParserData& pd,
579
+ const ParseResultRef<Payload>& out) {
580
+
581
+ bool warnEmptyBody = false;
582
+
583
+ mdp::ByteBuffer contentLength;
584
+ mdp::ByteBuffer transferEncoding;
585
+
586
+ for (HeaderIterator it = out.node.headers.begin();
587
+ it != out.node.headers.end();
588
+ ++it) {
589
+
590
+ if (it->first == HTTPHeaderName::ContentLength) {
591
+ contentLength = it->second;
592
+ }
593
+
594
+ if (it->first == HTTPHeaderName::TransferEncoding) {
595
+ transferEncoding = it->second;
589
596
  }
590
-
591
- out.node.body = model.body;
592
- out.node.schema = model.schema;
597
+ }
593
598
 
594
- if (pd.exportSourceMap()) {
599
+ if (out.node.body.empty() && out.node.reference.meta.state != Reference::StatePending) {
595
600
 
596
- modelSM = pd.symbolSourceMapTable.resourceModels.at(symbol);
601
+ // Warn when content-length or transfer-encoding is specified or both headers and body are empty
602
+ if (out.node.headers.empty()) {
603
+ warnEmptyBody = true;
604
+ } else {
605
+ warnEmptyBody = !contentLength.empty() || !transferEncoding.empty();
606
+ }
597
607
 
598
- out.sourceMap.description = modelSM.description;
599
- out.sourceMap.parameters = modelSM.parameters;
600
- out.sourceMap.body = modelSM.body;
601
- out.sourceMap.schema = modelSM.schema;
608
+ if (warnEmptyBody) {
602
609
 
603
- if (isPayloadContentType && !isModelContentType) {
604
- out.sourceMap.headers.collection.insert(out.sourceMap.headers.collection.end(), modelSM.headers.collection.begin(), modelSM.headers.collection.end());
605
- } else {
606
- out.sourceMap.headers = modelSM.headers;
610
+ // WARN: empty body
611
+ std::stringstream ss;
612
+ ss << "empty " << SectionName(RequestSectionType) << " " << SectionName(BodySectionType);
613
+
614
+ if (!contentLength.empty()) {
615
+ ss << ", expected " << SectionName(BodySectionType) << " for '" << contentLength << "' Content-Length";
616
+ } else if (!transferEncoding.empty()) {
617
+ ss << ", expected " << SectionName(BodySectionType) << " for '" << transferEncoding << "' Transfer-Encoding";
607
618
  }
619
+
620
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
621
+ out.report.warnings.push_back(Warning(ss.str(),
622
+ EmptyDefinitionWarning,
623
+ sourceMap));
608
624
  }
625
+ }
626
+ }
609
627
 
610
- return true;
628
+ /**
629
+ * \brief Checks response given as out
630
+ * \param node Markdown node
631
+ * \param pd Section parser state
632
+ * \param out Processed output
633
+ */
634
+ static void checkResponse(const MarkdownNodeIterator& node,
635
+ SectionParserData& pd,
636
+ const ParseResultRef<Payload>& out) {
637
+
638
+ HTTPStatusCode code = 200;
639
+
640
+ if (!out.node.name.empty()) {
641
+ std::stringstream(out.node.name) >> code;
611
642
  }
612
643
 
613
- return false;
644
+ StatusCodeTraits statusCodeTraits = GetStatusCodeTrait(code);
645
+
646
+ if (!statusCodeTraits.allowBody &&
647
+ !out.node.body.empty() &&
648
+ out.node.reference.meta.state != Reference::StatePending) {
649
+
650
+ // WARN: not empty body
651
+ std::stringstream ss;
652
+ ss << "the " << code << " response MUST NOT include a " << SectionName(BodySectionType);
653
+
654
+ mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
655
+ out.report.warnings.push_back(Warning(ss.str(),
656
+ EmptyDefinitionWarning,
657
+ sourceMap));
658
+ }
614
659
  }
615
660
 
616
661
  /**