redsnow 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
  /**