moddle.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import {
  2. isString,
  3. isObject,
  4. forEach
  5. } from 'min-dash';
  6. import Factory from './factory';
  7. import Registry from './registry';
  8. import Properties from './properties';
  9. import {
  10. parseName as parseNameNs
  11. } from './ns';
  12. //// Moddle implementation /////////////////////////////////////////////////
  13. /**
  14. * @class Moddle
  15. *
  16. * A model that can be used to create elements of a specific type.
  17. *
  18. * @example
  19. *
  20. * var Moddle = require('moddle');
  21. *
  22. * var pkg = {
  23. * name: 'mypackage',
  24. * prefix: 'my',
  25. * types: [
  26. * { name: 'Root' }
  27. * ]
  28. * };
  29. *
  30. * var moddle = new Moddle([pkg]);
  31. *
  32. * @param {Array<Package>} packages the packages to contain
  33. */
  34. export default function Moddle(packages) {
  35. this.properties = new Properties(this);
  36. this.factory = new Factory(this, this.properties);
  37. this.registry = new Registry(packages, this.properties);
  38. this.typeCache = {};
  39. }
  40. /**
  41. * Create an instance of the specified type.
  42. *
  43. * @method Moddle#create
  44. *
  45. * @example
  46. *
  47. * var foo = moddle.create('my:Foo');
  48. * var bar = moddle.create('my:Bar', { id: 'BAR_1' });
  49. *
  50. * @param {String|Object} descriptor the type descriptor or name know to the model
  51. * @param {Object} attrs a number of attributes to initialize the model instance with
  52. * @return {Object} model instance
  53. */
  54. Moddle.prototype.create = function(descriptor, attrs) {
  55. var Type = this.getType(descriptor);
  56. if (!Type) {
  57. throw new Error('unknown type <' + descriptor + '>');
  58. }
  59. return new Type(attrs);
  60. };
  61. /**
  62. * Returns the type representing a given descriptor
  63. *
  64. * @method Moddle#getType
  65. *
  66. * @example
  67. *
  68. * var Foo = moddle.getType('my:Foo');
  69. * var foo = new Foo({ 'id' : 'FOO_1' });
  70. *
  71. * @param {String|Object} descriptor the type descriptor or name know to the model
  72. * @return {Object} the type representing the descriptor
  73. */
  74. Moddle.prototype.getType = function(descriptor) {
  75. var cache = this.typeCache;
  76. var name = isString(descriptor) ? descriptor : descriptor.ns.name;
  77. var type = cache[name];
  78. if (!type) {
  79. descriptor = this.registry.getEffectiveDescriptor(name);
  80. type = cache[name] = this.factory.createType(descriptor);
  81. }
  82. return type;
  83. };
  84. /**
  85. * Creates an any-element type to be used within model instances.
  86. *
  87. * This can be used to create custom elements that lie outside the meta-model.
  88. * The created element contains all the meta-data required to serialize it
  89. * as part of meta-model elements.
  90. *
  91. * @method Moddle#createAny
  92. *
  93. * @example
  94. *
  95. * var foo = moddle.createAny('vendor:Foo', 'http://vendor', {
  96. * value: 'bar'
  97. * });
  98. *
  99. * var container = moddle.create('my:Container', 'http://my', {
  100. * any: [ foo ]
  101. * });
  102. *
  103. * // go ahead and serialize the stuff
  104. *
  105. *
  106. * @param {String} name the name of the element
  107. * @param {String} nsUri the namespace uri of the element
  108. * @param {Object} [properties] a map of properties to initialize the instance with
  109. * @return {Object} the any type instance
  110. */
  111. Moddle.prototype.createAny = function(name, nsUri, properties) {
  112. var nameNs = parseNameNs(name);
  113. var element = {
  114. $type: name,
  115. $instanceOf: function(type) {
  116. return type === this.$type;
  117. }
  118. };
  119. var descriptor = {
  120. name: name,
  121. isGeneric: true,
  122. ns: {
  123. prefix: nameNs.prefix,
  124. localName: nameNs.localName,
  125. uri: nsUri
  126. }
  127. };
  128. this.properties.defineDescriptor(element, descriptor);
  129. this.properties.defineModel(element, this);
  130. this.properties.define(element, '$parent', { enumerable: false, writable: true });
  131. forEach(properties, function(a, key) {
  132. if (isObject(a) && a.value !== undefined) {
  133. element[a.name] = a.value;
  134. } else {
  135. element[key] = a;
  136. }
  137. });
  138. return element;
  139. };
  140. /**
  141. * Returns a registered package by uri or prefix
  142. *
  143. * @return {Object} the package
  144. */
  145. Moddle.prototype.getPackage = function(uriOrPrefix) {
  146. return this.registry.getPackage(uriOrPrefix);
  147. };
  148. /**
  149. * Returns a snapshot of all known packages
  150. *
  151. * @return {Object} the package
  152. */
  153. Moddle.prototype.getPackages = function() {
  154. return this.registry.getPackages();
  155. };
  156. /**
  157. * Returns the descriptor for an element
  158. */
  159. Moddle.prototype.getElementDescriptor = function(element) {
  160. return element.$descriptor;
  161. };
  162. /**
  163. * Returns true if the given descriptor or instance
  164. * represents the given type.
  165. *
  166. * May be applied to this, if element is omitted.
  167. */
  168. Moddle.prototype.hasType = function(element, type) {
  169. if (type === undefined) {
  170. type = element;
  171. element = this;
  172. }
  173. var descriptor = element.$model.getElementDescriptor(element);
  174. return (type in descriptor.allTypesByName);
  175. };
  176. /**
  177. * Returns the descriptor of an elements named property
  178. */
  179. Moddle.prototype.getPropertyDescriptor = function(element, property) {
  180. return this.getElementDescriptor(element).propertiesByName[property];
  181. };
  182. /**
  183. * Returns a mapped type's descriptor
  184. */
  185. Moddle.prototype.getTypeDescriptor = function(type) {
  186. return this.registry.typeMap[type];
  187. };