redsnow 0.2.0 → 0.2.1

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -1
  3. data/README.md +12 -0
  4. data/ext/snowcrash/bin/snowcrash +0 -0
  5. data/ext/snowcrash/ext/markdown-parser/ext/sundown/src/markdown.c +5 -2
  6. data/ext/snowcrash/snowcrash.gyp +7 -2
  7. data/ext/snowcrash/src/ActionParser.h +141 -81
  8. data/ext/snowcrash/src/AssetParser.h +19 -11
  9. data/ext/snowcrash/src/Blueprint.h +44 -14
  10. data/ext/snowcrash/src/BlueprintParser.h +65 -51
  11. data/ext/snowcrash/src/BlueprintSourcemap.h +254 -0
  12. data/ext/snowcrash/src/BlueprintUtility.h +3 -24
  13. data/ext/snowcrash/src/CBlueprint.cc +40 -31
  14. data/ext/snowcrash/src/CBlueprint.h +54 -58
  15. data/ext/snowcrash/src/CBlueprintSourcemap.cc +620 -0
  16. data/ext/snowcrash/src/CBlueprintSourcemap.h +342 -0
  17. data/ext/snowcrash/src/CSourceAnnotation.cc +14 -0
  18. data/ext/snowcrash/src/CodeBlockUtility.h +42 -5
  19. data/ext/snowcrash/src/HeadersParser.h +84 -42
  20. data/ext/snowcrash/src/ParameterParser.h +110 -68
  21. data/ext/snowcrash/src/ParametersParser.h +26 -28
  22. data/ext/snowcrash/src/PayloadParser.h +164 -83
  23. data/ext/snowcrash/src/ResourceGroupParser.h +35 -41
  24. data/ext/snowcrash/src/ResourceParser.h +142 -97
  25. data/ext/snowcrash/src/SectionParser.h +15 -14
  26. data/ext/snowcrash/src/SectionParserData.h +11 -2
  27. data/ext/snowcrash/src/SectionProcessor.h +42 -18
  28. data/ext/snowcrash/src/Serialize.cc +2 -0
  29. data/ext/snowcrash/src/Serialize.h +3 -1
  30. data/ext/snowcrash/src/SerializeJSON.cc +608 -16
  31. data/ext/snowcrash/src/SerializeJSON.h +4 -1
  32. data/ext/snowcrash/src/SerializeYAML.cc +367 -19
  33. data/ext/snowcrash/src/SerializeYAML.h +4 -1
  34. data/ext/snowcrash/src/SymbolTable.h +12 -1
  35. data/ext/snowcrash/src/ValuesParser.h +12 -11
  36. data/ext/snowcrash/src/Version.h +1 -1
  37. data/ext/snowcrash/src/csnowcrash.cc +7 -3
  38. data/ext/snowcrash/src/csnowcrash.h +4 -2
  39. data/ext/snowcrash/src/snowcrash.cc +10 -11
  40. data/ext/snowcrash/src/snowcrash.h +3 -3
  41. data/ext/snowcrash/src/snowcrash/snowcrash.cc +38 -8
  42. data/ext/snowcrash/tools/homebrew/snowcrash.rb +1 -1
  43. data/lib/redsnow.rb +41 -2
  44. data/lib/redsnow/binding.rb +93 -8
  45. data/lib/redsnow/blueprint.rb +48 -25
  46. data/lib/redsnow/parseresult.rb +9 -2
  47. data/lib/redsnow/sourcemap.rb +369 -0
  48. data/lib/redsnow/version.rb +1 -1
  49. data/test/fixtures/sample-api-ast.json +1 -1
  50. data/test/fixtures/sample-api-sourcemap.json +169 -0
  51. data/test/redsnow_binding_test.rb +19 -2
  52. data/test/redsnow_options_test.rb +42 -0
  53. data/test/redsnow_parseresult_test.rb +5 -1
  54. data/test/redsnow_test.rb +5 -0
  55. metadata +11 -2
@@ -23,9 +23,7 @@ namespace snowcrash {
23
23
  /** No parameters specified message */
24
24
  const char* const NoParametersMessage = "no parameters specified, expected a nested list of parameters, one parameter per list item";
25
25
 
26
- /** Internal type alias for Collection of Parameter */
27
- typedef Collection<Parameter>::type Parameters;
28
-
26
+ /** Internal type alias for Collection iterator of Parameter */
29
27
  typedef Collection<Parameter>::iterator ParameterIterator;
30
28
 
31
29
  /**
@@ -38,8 +36,7 @@ namespace snowcrash {
38
36
  const MarkdownNodes& siblings,
39
37
  SectionParserData& pd,
40
38
  SectionLayout& layout,
41
- Report& report,
42
- Parameters& out) {
39
+ ParseResult<Parameters>& out) {
43
40
 
44
41
  mdp::ByteBuffer remainingContent;
45
42
 
@@ -53,9 +50,9 @@ namespace snowcrash {
53
50
  ss << " expected a nested list of parameters, one parameter per list item";
54
51
 
55
52
  mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
56
- report.warnings.push_back(Warning(ss.str(),
57
- IgnoringWarning,
58
- sourceMap));
53
+ out.report.warnings.push_back(Warning(ss.str(),
54
+ IgnoringWarning,
55
+ sourceMap));
59
56
  }
60
57
 
61
58
  return ++MarkdownNodeIterator(node);
@@ -64,8 +61,7 @@ namespace snowcrash {
64
61
  static MarkdownNodeIterator processDescription(const MarkdownNodeIterator& node,
65
62
  const MarkdownNodes& siblings,
66
63
  SectionParserData& pd,
67
- Report& report,
68
- Parameters& out) {
64
+ ParseResult<Parameters>& out) {
69
65
 
70
66
  return node;
71
67
  }
@@ -73,34 +69,37 @@ namespace snowcrash {
73
69
  static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
74
70
  const MarkdownNodes& siblings,
75
71
  SectionParserData& pd,
76
- Report& report,
77
- Parameters& out) {
72
+ ParseResult<Parameters>& out) {
78
73
 
79
74
  if (pd.sectionContext() != ParameterSectionType) {
80
75
  return node;
81
76
  }
82
77
 
83
- Parameter parameter;
84
- ParameterParser::parse(node, siblings, pd, report, parameter);
78
+ ParseResult<Parameter> parameter(out.report);
79
+ ParameterParser::parse(node, siblings, pd, parameter);
85
80
 
86
- if (!out.empty()) {
81
+ if (!out.node.empty()) {
87
82
 
88
- ParameterIterator duplicate = findParameter(out, parameter);
83
+ ParameterIterator duplicate = findParameter(out.node, parameter.node);
89
84
 
90
- if (duplicate != out.end()) {
85
+ if (duplicate != out.node.end()) {
91
86
 
92
87
  // WARN: Parameter already defined
93
88
  std::stringstream ss;
94
- ss << "overshadowing previous parameter '" << parameter.name << "' definition";
89
+ ss << "overshadowing previous parameter '" << parameter.node.name << "' definition";
95
90
 
96
91
  mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
97
- report.warnings.push_back(Warning(ss.str(),
98
- RedefinitionWarning,
99
- sourceMap));
92
+ out.report.warnings.push_back(Warning(ss.str(),
93
+ RedefinitionWarning,
94
+ sourceMap));
100
95
  }
101
96
  }
102
97
 
103
- out.push_back(parameter);
98
+ out.node.push_back(parameter.node);
99
+
100
+ if (pd.exportSourceMap()) {
101
+ out.sourceMap.collection.push_back(parameter.sourceMap);
102
+ }
104
103
 
105
104
  return ++MarkdownNodeIterator(node);
106
105
  }
@@ -147,16 +146,15 @@ namespace snowcrash {
147
146
 
148
147
  static void finalize(const MarkdownNodeIterator& node,
149
148
  SectionParserData& pd,
150
- Report& report,
151
- Parameters& out) {
149
+ ParseResult<Parameters>& out) {
152
150
 
153
- if (out.empty()) {
151
+ if (out.node.empty()) {
154
152
 
155
153
  // WARN: No parameters defined
156
154
  mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
157
- report.warnings.push_back(Warning(NoParametersMessage,
158
- FormattingWarning,
159
- sourceMap));
155
+ out.report.warnings.push_back(Warning(NoParametersMessage,
156
+ FormattingWarning,
157
+ sourceMap));
160
158
  }
161
159
  }
162
160
 
@@ -20,6 +20,10 @@
20
20
 
21
21
  namespace snowcrash {
22
22
 
23
+ /** Internal type alias for Collection iterator of Response */
24
+ typedef Collection<Response>::const_iterator ResponseIterator;
25
+ typedef Collection<Request>::const_iterator RequestIterator;
26
+
23
27
  /// Payload signature
24
28
  enum PayloadSignature {
25
29
  NoPayloadSignature = 0,
@@ -48,35 +52,42 @@ namespace snowcrash {
48
52
  const MarkdownNodes& siblings,
49
53
  SectionParserData& pd,
50
54
  SectionLayout& layout,
51
- Report& report,
52
- Payload& out) {
55
+ ParseResult<Payload>& out) {
53
56
 
54
57
  mdp::ByteBuffer signature, remainingContent;
55
58
  signature = GetFirstLine(node->text, remainingContent);
56
59
 
57
- parseSignature(node, pd, signature, report, out);
60
+ parseSignature(node, pd, signature, out);
58
61
 
59
62
  // WARN: missing status code
60
- if (out.name.empty() &&
63
+ if (out.node.name.empty() &&
61
64
  (pd.sectionContext() == ResponseSectionType || pd.sectionContext() == ResponseBodySectionType)) {
62
65
 
63
66
  mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
64
- report.warnings.push_back(Warning("missing response HTTP status code, assuming 'Response 200'",
65
- EmptyDefinitionWarning,
66
- sourceMap));
67
- out.name = "200";
67
+ out.report.warnings.push_back(Warning("missing response HTTP status code, assuming 'Response 200'",
68
+ EmptyDefinitionWarning,
69
+ sourceMap));
70
+ out.node.name = "200";
68
71
  }
69
72
 
70
73
  if (!remainingContent.empty()) {
71
74
  if (!isAbbreviated(pd.sectionContext())) {
72
- out.description = remainingContent;
73
- } else if (!parseSymbolReference(node, pd, remainingContent, report, out)) {
75
+ out.node.description = remainingContent;
76
+
77
+ if (pd.exportSourceMap() && !out.node.description.empty()) {
78
+ out.sourceMap.description.sourceMap.append(node->sourceMap);
79
+ }
80
+ } else if (!parseSymbolReference(node, pd, remainingContent, out)) {
74
81
 
75
82
  // NOTE: NOT THE CORRECT WAY TO DO THIS
76
83
  // https://github.com/apiaryio/snowcrash/commit/a7c5868e62df0048a85e2f9aeeb42c3b3e0a2f07#commitcomment-7322085
77
84
  pd.sectionsContext.push_back(BodySectionType);
78
- CodeBlockUtility::signatureContentAsCodeBlock(node, pd, report, out.body);
85
+ CodeBlockUtility::signatureContentAsCodeBlock(node, pd, out.report, out.node.body);
79
86
  pd.sectionsContext.pop_back();
87
+
88
+ if (pd.exportSourceMap() && !out.node.body.empty()) {
89
+ out.sourceMap.body.sourceMap.append(node->sourceMap);
90
+ }
80
91
  }
81
92
  }
82
93
 
@@ -86,35 +97,38 @@ namespace snowcrash {
86
97
  static MarkdownNodeIterator processContent(const MarkdownNodeIterator& node,
87
98
  const MarkdownNodes& siblings,
88
99
  SectionParserData& pd,
89
- Report& report,
90
- Payload& out) {
100
+ ParseResult<Payload>& out) {
91
101
 
92
102
  mdp::ByteBuffer content;
93
103
 
94
- if (!out.symbol.empty()) {
104
+ if (!out.node.symbol.empty()) {
95
105
  //WARN: ignoring extraneous content after symbol reference
96
106
  std::stringstream ss;
97
107
 
98
108
  ss << "ignoring extraneous content after symbol reference";
99
- ss << ", expected symbol reference only e.g. '[" << out.symbol << "][]'";
109
+ ss << ", expected symbol reference only e.g. '[" << out.node.symbol << "][]'";
100
110
 
101
111
  mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
102
- report.warnings.push_back(Warning(ss.str(),
103
- IgnoringWarning,
104
- sourceMap));
112
+ out.report.warnings.push_back(Warning(ss.str(),
113
+ IgnoringWarning,
114
+ sourceMap));
105
115
  } else {
106
116
 
107
- if (!out.body.empty() ||
117
+ if (!out.node.body.empty() ||
108
118
  node->type != mdp::ParagraphMarkdownNodeType ||
109
- !parseSymbolReference(node, pd, node->text, report, out)) {
119
+ !parseSymbolReference(node, pd, node->text, out)) {
110
120
 
111
121
  // NOTE: NOT THE CORRECT WAY TO DO THIS
112
122
  // https://github.com/apiaryio/snowcrash/commit/a7c5868e62df0048a85e2f9aeeb42c3b3e0a2f07#commitcomment-7322085
113
123
  pd.sectionsContext.push_back(BodySectionType);
114
- CodeBlockUtility::contentAsCodeBlock(node, pd, report, content);
124
+ CodeBlockUtility::contentAsCodeBlock(node, pd, out.report, content);
115
125
  pd.sectionsContext.pop_back();
116
126
 
117
- out.body += content;
127
+ out.node.body += content;
128
+
129
+ if (pd.exportSourceMap() && !content.empty()) {
130
+ out.sourceMap.body.sourceMap.append(node->sourceMap);
131
+ }
118
132
  }
119
133
  }
120
134
 
@@ -124,34 +138,42 @@ namespace snowcrash {
124
138
  static MarkdownNodeIterator processNestedSection(const MarkdownNodeIterator& node,
125
139
  const MarkdownNodes& siblings,
126
140
  SectionParserData& pd,
127
- Report& report,
128
- Payload& out) {
141
+ ParseResult<Payload>& out) {
129
142
 
130
143
  switch (pd.sectionContext()) {
131
144
  case HeadersSectionType:
132
- return HeadersParser::parse(node, siblings, pd, report, out.headers);
145
+ {
146
+ ParseResult<Headers> headers(out.report, out.node.headers, out.sourceMap.headers);
147
+ return HeadersParser::parse(node, siblings, pd, headers);
148
+ }
133
149
 
134
150
  case BodySectionType:
135
- if (!out.body.empty()) {
151
+ {
152
+ if (!out.node.body.empty()) {
136
153
  // WARN: Multiple body section
137
154
  mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
138
- report.warnings.push_back(Warning("ignoring additional 'body' content, it is already defined",
139
- RedefinitionWarning,
140
- sourceMap));
155
+ out.report.warnings.push_back(Warning("ignoring additional 'body' content, it is already defined",
156
+ RedefinitionWarning,
157
+ sourceMap));
141
158
  }
142
159
 
143
- return AssetParser::parse(node, siblings, pd, report, out.body);
160
+ ParseResult<Asset> asset(out.report, out.node.body, out.sourceMap.body);
161
+ return AssetParser::parse(node, siblings, pd, asset);
162
+ }
144
163
 
145
164
  case SchemaSectionType:
146
- if (!out.schema.empty()) {
165
+ {
166
+ if (!out.node.schema.empty()) {
147
167
  // WARN: Multiple schema section
148
168
  mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
149
- report.warnings.push_back(Warning("ignoring additional 'schema' content, it is already defined",
150
- RedefinitionWarning,
151
- sourceMap));
169
+ out.report.warnings.push_back(Warning("ignoring additional 'schema' content, it is already defined",
170
+ RedefinitionWarning,
171
+ sourceMap));
152
172
  }
153
173
 
154
- return AssetParser::parse(node, siblings, pd, report, out.schema);
174
+ ParseResult<Asset> asset(out.report, out.node.schema, out.sourceMap.schema);
175
+ return AssetParser::parse(node, siblings, pd, asset);
176
+ }
155
177
 
156
178
  default:
157
179
  break;
@@ -164,18 +186,22 @@ namespace snowcrash {
164
186
  const MarkdownNodes& siblings,
165
187
  SectionParserData& pd,
166
188
  SectionType& sectionType,
167
- Report& report,
168
- Payload& out) {
189
+ ParseResult<Payload>& out) {
169
190
 
170
191
  if ((node->type == mdp::ParagraphMarkdownNodeType ||
171
192
  node->type == mdp::CodeMarkdownNodeType) &&
172
193
  sectionType == BodySectionType) {
173
194
 
174
- CodeBlockUtility::addDanglingAsset(node, pd, sectionType, report, out.body);
195
+ mdp::ByteBuffer content = CodeBlockUtility::addDanglingAsset(node, pd, sectionType, out.report, out.node.body);
196
+
197
+ if (pd.exportSourceMap() && !content.empty()) {
198
+ out.sourceMap.body.sourceMap.append(node->sourceMap);
199
+ }
200
+
175
201
  return ++MarkdownNodeIterator(node);
176
202
  }
177
203
 
178
- return SectionProcessorBase<Payload>::processUnexpectedNode(node, siblings, pd, sectionType, report, out);
204
+ return SectionProcessorBase<Payload>::processUnexpectedNode(node, siblings, pd, sectionType, out);
179
205
  }
180
206
 
181
207
  static bool isDescriptionNode(const MarkdownNodeIterator& node,
@@ -270,8 +296,7 @@ namespace snowcrash {
270
296
 
271
297
  static void finalize(const MarkdownNodeIterator& node,
272
298
  SectionParserData& pd,
273
- Report& report,
274
- Payload& out) {
299
+ ParseResult<Payload>& out) {
275
300
 
276
301
  bool warnEmptyBody = false;
277
302
 
@@ -280,8 +305,8 @@ namespace snowcrash {
280
305
 
281
306
  SectionType sectionType = pd.sectionContext();
282
307
 
283
- for (Collection<Header>::const_iterator it = out.headers.begin();
284
- it != out.headers.end();
308
+ for (HeaderIterator it = out.node.headers.begin();
309
+ it != out.node.headers.end();
285
310
  ++it) {
286
311
 
287
312
  if (it->first == HTTPHeaderName::ContentLength) {
@@ -293,10 +318,10 @@ namespace snowcrash {
293
318
  }
294
319
  }
295
320
 
296
- if ((sectionType == RequestSectionType || sectionType == RequestBodySectionType) && out.body.empty()) {
321
+ if ((sectionType == RequestSectionType || sectionType == RequestBodySectionType) && out.node.body.empty()) {
297
322
 
298
323
  // Warn when content-length or transfer-encoding is specified or both headers and body are empty
299
- if (out.headers.empty()) {
324
+ if (out.node.headers.empty()) {
300
325
  warnEmptyBody = true;
301
326
  } else {
302
327
  warnEmptyBody = !contentLength.empty() || !transferEncoding.empty();
@@ -314,29 +339,29 @@ namespace snowcrash {
314
339
  }
315
340
 
316
341
  mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
317
- report.warnings.push_back(Warning(ss.str(),
318
- EmptyDefinitionWarning,
319
- sourceMap));
342
+ out.report.warnings.push_back(Warning(ss.str(),
343
+ EmptyDefinitionWarning,
344
+ sourceMap));
320
345
  }
321
346
  } else if ((sectionType == ResponseSectionType || sectionType == ResponseBodySectionType)) {
322
347
 
323
348
  HTTPStatusCode code = 200;
324
349
 
325
- if (!out.name.empty()) {
326
- std::stringstream(out.name) >> code;
350
+ if (!out.node.name.empty()) {
351
+ std::stringstream(out.node.name) >> code;
327
352
  }
328
353
 
329
354
  StatusCodeTraits statusCodeTraits = GetStatusCodeTrait(code);
330
355
 
331
- if (!statusCodeTraits.allowBody && !out.body.empty()) {
356
+ if (!statusCodeTraits.allowBody && !out.node.body.empty()) {
332
357
  // WARN: not empty body
333
358
  std::stringstream ss;
334
359
  ss << "the " << code << " response MUST NOT include a " << SectionName(BodySectionType);
335
360
 
336
361
  mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
337
- report.warnings.push_back(Warning(ss.str(),
338
- EmptyDefinitionWarning,
339
- sourceMap));
362
+ out.report.warnings.push_back(Warning(ss.str(),
363
+ EmptyDefinitionWarning,
364
+ sourceMap));
340
365
  }
341
366
  }
342
367
  }
@@ -396,8 +421,7 @@ namespace snowcrash {
396
421
  static bool parseSignature(const MarkdownNodeIterator& node,
397
422
  SectionParserData& pd,
398
423
  const mdp::ByteBuffer& signature,
399
- Report& report,
400
- Payload& out) {
424
+ ParseResult<Payload>& out) {
401
425
 
402
426
  const char* regex;
403
427
  mdp::ByteBuffer mediaType;
@@ -461,9 +485,9 @@ namespace snowcrash {
461
485
  }
462
486
 
463
487
  mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
464
- report.warnings.push_back(Warning(ss.str(),
465
- FormattingWarning,
466
- sourceMap));
488
+ out.report.warnings.push_back(Warning(ss.str(),
489
+ FormattingWarning,
490
+ sourceMap));
467
491
 
468
492
  return false;
469
493
  }
@@ -471,19 +495,29 @@ namespace snowcrash {
471
495
  if (pd.sectionContext() == ModelSectionType ||
472
496
  pd.sectionContext() == ModelBodySectionType) {
473
497
 
474
- out.name = captureGroups[2];
498
+ out.node.name = captureGroups[2];
475
499
  mediaType = captureGroups[4];
476
500
  } else {
477
- out.name = captureGroups[1];
501
+ out.node.name = captureGroups[1];
478
502
  mediaType = captureGroups[3];
479
503
  }
480
504
 
481
- TrimString(out.name);
505
+ TrimString(out.node.name);
482
506
  TrimString(mediaType);
483
507
 
508
+ if (pd.exportSourceMap() && !out.node.name.empty()) {
509
+ out.sourceMap.name.sourceMap = node->sourceMap;
510
+ }
511
+
484
512
  if (!mediaType.empty()) {
485
513
  Header header = std::make_pair(HTTPHeaderName::ContentType, mediaType);
486
- out.headers.push_back(header);
514
+ out.node.headers.push_back(header);
515
+
516
+ if (pd.exportSourceMap()) {
517
+ SourceMap<Header> headerSM;
518
+ headerSM.sourceMap = node->sourceMap;
519
+ out.sourceMap.headers.collection.push_back(headerSM);
520
+ }
487
521
  }
488
522
  }
489
523
 
@@ -493,16 +527,20 @@ namespace snowcrash {
493
527
  static bool parseSymbolReference(const MarkdownNodeIterator& node,
494
528
  SectionParserData& pd,
495
529
  mdp::ByteBuffer& source,
496
- Report& report,
497
- Payload& out) {
530
+ ParseResult<Payload>& out) {
498
531
 
499
532
  SymbolName symbol;
500
533
  ResourceModel model;
534
+ SourceMap<ResourceModel> modelSM;
501
535
 
502
536
  TrimString(source);
503
537
 
504
538
  if (GetSymbolReference(source, symbol)) {
505
- out.symbol = symbol;
539
+ out.node.symbol = symbol;
540
+
541
+ if (pd.exportSourceMap() && !symbol.empty()) {
542
+ out.sourceMap.symbol.sourceMap = node->sourceMap;
543
+ }
506
544
 
507
545
  // If symbol doesn't exist
508
546
  if (pd.symbolTable.resourceModels.find(symbol) == pd.symbolTable.resourceModels.end()) {
@@ -512,22 +550,22 @@ namespace snowcrash {
512
550
  ss << "Undefined symbol " << symbol;
513
551
 
514
552
  mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
515
- report.error = Error(ss.str(), SymbolError, sourceMap);
553
+ out.report.error = Error(ss.str(), SymbolError, sourceMap);
516
554
 
517
555
  return true;
518
556
  }
519
557
 
520
558
  model = pd.symbolTable.resourceModels.at(symbol);
521
559
 
522
- out.description = model.description;
523
- out.parameters = model.parameters;
560
+ out.node.description = model.description;
561
+ out.node.parameters = model.parameters;
524
562
 
525
- Collection<Header>::const_iterator modelContentType = std::find_if(model.headers.begin(),
526
- model.headers.end(),
527
- std::bind2nd(MatchFirstWith<Header, std::string>(),
528
- HTTPHeaderName::ContentType));
563
+ HeaderIterator modelContentType = std::find_if(model.headers.begin(),
564
+ model.headers.end(),
565
+ std::bind2nd(MatchFirstWith<Header, std::string>(),
566
+ HTTPHeaderName::ContentType));
529
567
 
530
- bool isPayloadContentType = !out.headers.empty();
568
+ bool isPayloadContentType = !out.node.headers.empty();
531
569
  bool isModelContentType = modelContentType != model.headers.end();
532
570
 
533
571
  if (isPayloadContentType && isModelContentType) {
@@ -539,26 +577,69 @@ namespace snowcrash {
539
577
  ss << "specify this header(s) in the referenced model definition instead";
540
578
 
541
579
  mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
542
- report.warnings.push_back(Warning(ss.str(),
543
- IgnoringWarning,
544
- sourceMap));
580
+ out.report.warnings.push_back(Warning(ss.str(),
581
+ IgnoringWarning,
582
+ sourceMap));
545
583
  }
546
584
 
547
585
  if (isPayloadContentType && !isModelContentType) {
548
- out.headers.insert(out.headers.end(), model.headers.begin(), model.headers.end());
549
- }
550
- else {
551
- out.headers = model.headers;
586
+ out.node.headers.insert(out.node.headers.end(), model.headers.begin(), model.headers.end());
587
+ } else {
588
+ out.node.headers = model.headers;
552
589
  }
553
590
 
554
- out.body = model.body;
555
- out.schema = model.schema;
591
+ out.node.body = model.body;
592
+ out.node.schema = model.schema;
593
+
594
+ if (pd.exportSourceMap()) {
595
+
596
+ modelSM = pd.symbolSourceMapTable.resourceModels.at(symbol);
597
+
598
+ out.sourceMap.description = modelSM.description;
599
+ out.sourceMap.parameters = modelSM.parameters;
600
+ out.sourceMap.body = modelSM.body;
601
+ out.sourceMap.schema = modelSM.schema;
602
+
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;
607
+ }
608
+ }
556
609
 
557
610
  return true;
558
611
  }
559
612
 
560
613
  return false;
561
614
  }
615
+
616
+ /**
617
+ * \brief Find a request within given action.
618
+ * \param transaction A transaction to check.
619
+ * \param request A request to look for.
620
+ * \return Iterator pointing to the matching request within given method requests.
621
+ */
622
+ static RequestIterator findRequest(const TransactionExample& example,
623
+ const Request& request) {
624
+
625
+ return std::find_if(example.requests.begin(),
626
+ example.requests.end(),
627
+ std::bind2nd(MatchPayload(), request));
628
+ }
629
+
630
+ /**
631
+ * \brief Find a response within responses of a given action.
632
+ * \param transaction A transaction to check.
633
+ * \param response A response to look for.
634
+ * \return Iterator pointing to the matching response within given method requests.
635
+ */
636
+ static ResponseIterator findResponse(const TransactionExample& example,
637
+ const Response& response) {
638
+
639
+ return std::find_if(example.responses.begin(),
640
+ example.responses.end(),
641
+ std::bind2nd(MatchPayload(), response));
642
+ }
562
643
  };
563
644
 
564
645
  /** Payload Section Parser */