flux.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /* jshint esversion: 6 */
  2. // Experimental
  3. var flux = flux || {};
  4. flux.ModelFactory = class {
  5. match(context) {
  6. const identifier = context.identifier;
  7. const extension = identifier.split('.').pop().toLowerCase();
  8. if (extension === 'bson') {
  9. return true;
  10. }
  11. return false;
  12. }
  13. open(context, host) {
  14. return host.require('./bson').then((bson) => {
  15. let model = null;
  16. const identifier = context.identifier;
  17. try {
  18. const reader = new bson.Reader(context.buffer);
  19. const root = reader.read();
  20. const obj = flux.ModelFactory._backref(root, root);
  21. model = obj.model;
  22. if (!model) {
  23. throw new flux.Error('File does not contain Flux model.');
  24. }
  25. }
  26. catch (error) {
  27. const message = error && error.message ? error.message : error.toString();
  28. throw new flux.Error(message.replace(/\.$/, '') + " in '" + identifier + "'.");
  29. }
  30. return flux.Metadata.open(host).then((metadata) => {
  31. try {
  32. return new flux.Model(metadata, model);
  33. }
  34. catch (error) {
  35. const message = error && error.message ? error.message : error.toString();
  36. throw new flux.Error(message.replace(/\.$/, '') + " in '" + identifier + "'.");
  37. }
  38. });
  39. });
  40. }
  41. static _backref(obj, root) {
  42. if (Array.isArray(obj)) {
  43. for (let i = 0; i < obj.length; i++) {
  44. obj[i] = flux.ModelFactory._backref(obj[i], root);
  45. }
  46. }
  47. else if (obj === Object(obj)) {
  48. if (obj.tag == 'backref' && obj.ref) {
  49. if (!root._backrefs[obj.ref - 1]) {
  50. throw new flux.Error("Invalid backref '" + obj.ref + "'.");
  51. }
  52. obj = root._backrefs[obj.ref - 1];
  53. }
  54. for (const key of Object.keys(obj)) {
  55. if (obj !== root || key !== '_backrefs') {
  56. obj[key] = flux.ModelFactory._backref(obj[key], root);
  57. }
  58. }
  59. }
  60. return obj;
  61. }
  62. };
  63. flux.Model = class {
  64. constructor(/* root */) {
  65. this._format = 'Flux';
  66. this._graphs = [];
  67. }
  68. get format() {
  69. return this._format;
  70. }
  71. get graphs() {
  72. return this._graphs;
  73. }
  74. };
  75. flux.Metadata = class {
  76. static open(host) {
  77. if (flux.Metadata._metadata) {
  78. return Promise.resolve(flux.Metadata._metadata);
  79. }
  80. return host.request(null, 'flux-metadata.json', 'utf-8').then((data) => {
  81. flux.Metadata._metadata = new flux.Metadata(data);
  82. return flux.Metadata._metadata;
  83. }).catch(() => {
  84. flux.Metadata._metadata = new flux.Metadata(null);
  85. return flux.Metadata._metadatas;
  86. });
  87. }
  88. constructor(data) {
  89. this._map = {};
  90. this._attributeCache = {};
  91. if (data) {
  92. const items = JSON.parse(data);
  93. if (items) {
  94. for (const item of items) {
  95. if (item.name && item.schema) {
  96. this._map[item.name] = item.schema;
  97. }
  98. }
  99. }
  100. }
  101. }
  102. type(name) {
  103. return this._map[name] || null;
  104. }
  105. attribute(type, name) {
  106. let map = this._attributeCache[type];
  107. if (!map) {
  108. map = {};
  109. const schema = this.type(type);
  110. if (schema && schema.attributes && schema.attributes.length > 0) {
  111. for (const attribute of schema.attributes) {
  112. map[attribute.name] = attribute;
  113. }
  114. }
  115. this._attributeCache[type] = map;
  116. }
  117. return map[name] || null;
  118. }
  119. };
  120. flux.Error = class extends Error {
  121. constructor(message) {
  122. super(message);
  123. this.name = 'Flux Error';
  124. }
  125. };
  126. if (module && module.exports) {
  127. module.exports.ModelFactory = flux.ModelFactory;
  128. }