base-xform.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. const parseSax = require('../../utils/parse-sax');
  2. const XmlStream = require('../../utils/xml-stream');
  3. /* 'virtual' methods used as a form of documentation */
  4. /* eslint-disable class-methods-use-this */
  5. // Base class for Xforms
  6. class BaseXform {
  7. // constructor(/* model, name */) {}
  8. // ============================================================
  9. // Virtual Interface
  10. prepare(/* model, options */) {
  11. // optional preparation (mutation) of model so it is ready for write
  12. }
  13. render(/* xmlStream, model */) {
  14. // convert model to xml
  15. }
  16. parseOpen(node) {
  17. // XML node opened
  18. }
  19. parseText(text) {
  20. // chunk of text encountered for current node
  21. }
  22. parseClose(name) {
  23. // XML node closed
  24. }
  25. reconcile(model, options) {
  26. // optional post-parse step (opposite to prepare)
  27. }
  28. // ============================================================
  29. reset() {
  30. // to make sure parses don't bleed to next iteration
  31. this.model = null;
  32. // if we have a map - reset them too
  33. if (this.map) {
  34. Object.values(this.map).forEach(xform => {
  35. if (xform instanceof BaseXform) {
  36. xform.reset();
  37. } else if (xform.xform) {
  38. xform.xform.reset();
  39. }
  40. });
  41. }
  42. }
  43. mergeModel(obj) {
  44. // set obj's props to this.model
  45. this.model = Object.assign(this.model || {}, obj);
  46. }
  47. async parse(saxParser) {
  48. for await (const events of saxParser) {
  49. for (const {eventType, value} of events) {
  50. if (eventType === 'opentag') {
  51. this.parseOpen(value);
  52. } else if (eventType === 'text') {
  53. this.parseText(value);
  54. } else if (eventType === 'closetag') {
  55. if (!this.parseClose(value.name)) {
  56. return this.model;
  57. }
  58. }
  59. }
  60. }
  61. return this.model;
  62. }
  63. async parseStream(stream) {
  64. return this.parse(parseSax(stream));
  65. }
  66. get xml() {
  67. // convenience function to get the xml of this.model
  68. // useful for manager types that are built during the prepare phase
  69. return this.toXml(this.model);
  70. }
  71. toXml(model) {
  72. const xmlStream = new XmlStream();
  73. this.render(xmlStream, model);
  74. return xmlStream.xml;
  75. }
  76. // ============================================================
  77. // Useful Utilities
  78. static toAttribute(value, dflt, always = false) {
  79. if (value === undefined) {
  80. if (always) {
  81. return dflt;
  82. }
  83. } else if (always || value !== dflt) {
  84. return value.toString();
  85. }
  86. return undefined;
  87. }
  88. static toStringAttribute(value, dflt, always = false) {
  89. return BaseXform.toAttribute(value, dflt, always);
  90. }
  91. static toStringValue(attr, dflt) {
  92. return attr === undefined ? dflt : attr;
  93. }
  94. static toBoolAttribute(value, dflt, always = false) {
  95. if (value === undefined) {
  96. if (always) {
  97. return dflt;
  98. }
  99. } else if (always || value !== dflt) {
  100. return value ? '1' : '0';
  101. }
  102. return undefined;
  103. }
  104. static toBoolValue(attr, dflt) {
  105. return attr === undefined ? dflt : attr === '1';
  106. }
  107. static toIntAttribute(value, dflt, always = false) {
  108. return BaseXform.toAttribute(value, dflt, always);
  109. }
  110. static toIntValue(attr, dflt) {
  111. return attr === undefined ? dflt : parseInt(attr, 10);
  112. }
  113. static toFloatAttribute(value, dflt, always = false) {
  114. return BaseXform.toAttribute(value, dflt, always);
  115. }
  116. static toFloatValue(attr, dflt) {
  117. return attr === undefined ? dflt : parseFloat(attr);
  118. }
  119. }
  120. module.exports = BaseXform;