source: node_modules/minim/lib/Namespace.js

main
Last change on this file was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 5.5 KB
Line 
1const isNull = require('lodash/isNull');
2const isString = require('lodash/isString');
3const isNumber = require('lodash/isNumber');
4const isBoolean = require('lodash/isBoolean');
5const isObject = require('lodash/isObject');
6
7const JSONSerialiser = require('./serialisers/JSONSerialiser');
8const elements = require('./elements');
9
10/**
11 * @class
12 *
13 * A refract element implementation with an extensible namespace, able to
14 * load other namespaces into it.
15 *
16 * The namespace allows you to register your own classes to be instantiated
17 * when a particular refract element is encountered, and allows you to specify
18 * which elements get instantiated for existing Javascript objects.
19 */
20class Namespace {
21 constructor(options) {
22 this.elementMap = {};
23 this.elementDetection = [];
24 this.Element = elements.Element;
25 this.KeyValuePair = elements.KeyValuePair;
26
27 if (!options || !options.noDefault) {
28 this.useDefault();
29 }
30
31 // These provide the defaults for new elements.
32 this._attributeElementKeys = [];
33 this._attributeElementArrayKeys = [];
34 }
35
36 /**
37 * Use a namespace plugin or load a generic plugin.
38 *
39 * @param plugin
40 */
41 use(plugin) {
42 if (plugin.namespace) {
43 plugin.namespace({ base: this });
44 }
45 if (plugin.load) {
46 plugin.load({ base: this });
47 }
48 return this;
49 }
50
51 /*
52 * Use the default namespace. This preloads all the default elements
53 * into this registry instance.
54 */
55 useDefault() {
56 // Set up classes for default elements
57 this
58 .register('null', elements.NullElement)
59 .register('string', elements.StringElement)
60 .register('number', elements.NumberElement)
61 .register('boolean', elements.BooleanElement)
62 .register('array', elements.ArrayElement)
63 .register('object', elements.ObjectElement)
64 .register('member', elements.MemberElement)
65 .register('ref', elements.RefElement)
66 .register('link', elements.LinkElement);
67
68 // Add instance detection functions to convert existing objects into
69 // the corresponding refract elements.
70 this
71 .detect(isNull, elements.NullElement, false)
72 .detect(isString, elements.StringElement, false)
73 .detect(isNumber, elements.NumberElement, false)
74 .detect(isBoolean, elements.BooleanElement, false)
75 .detect(Array.isArray, elements.ArrayElement, false)
76 .detect(isObject, elements.ObjectElement, false);
77
78 return this;
79 }
80
81 /**
82 * Register a new element class for an element.
83 *
84 * @param {string} name
85 * @param elementClass
86 */
87 register(name, ElementClass) {
88 this._elements = undefined;
89 this.elementMap[name] = ElementClass;
90 return this;
91 }
92
93 /**
94 * Unregister a previously registered class for an element.
95 *
96 * @param {string} name
97 */
98 unregister(name) {
99 this._elements = undefined;
100 delete this.elementMap[name];
101 return this;
102 }
103
104 /*
105 * Add a new detection function to determine which element
106 * class to use when converting existing js instances into
107 * refract element.
108 */
109 detect(test, ElementClass, givenPrepend) {
110 const prepend = givenPrepend === undefined ? true : givenPrepend;
111
112 if (prepend) {
113 this.elementDetection.unshift([test, ElementClass]);
114 } else {
115 this.elementDetection.push([test, ElementClass]);
116 }
117
118 return this;
119 }
120
121 /*
122 * Convert an existing Javascript object into refract element instances, which
123 * can be further processed or serialized into refract.
124 * If the item passed in is already refracted, then it is returned
125 * unmodified.
126 */
127 toElement(value) {
128 if (value instanceof this.Element) { return value; }
129
130 let element;
131
132 for (let i = 0; i < this.elementDetection.length; i += 1) {
133 const test = this.elementDetection[i][0];
134 const ElementClass = this.elementDetection[i][1];
135
136 if (test(value)) {
137 element = new ElementClass(value);
138 break;
139 }
140 }
141
142 return element;
143 }
144
145 /*
146 * Get an element class given an element name.
147 */
148 getElementClass(element) {
149 const ElementClass = this.elementMap[element];
150
151 if (ElementClass === undefined) {
152 // Fall back to the base element. We may not know what
153 // to do with the `content`, but downstream software
154 // may know.
155 return this.Element;
156 }
157
158 return ElementClass;
159 }
160
161 /*
162 * Convert a refract document into refract element instances.
163 */
164 fromRefract(doc) {
165 return this.serialiser.deserialise(doc);
166 }
167
168 /*
169 * Convert an element to a Refracted JSON object.
170 */
171 toRefract(element) {
172 return this.serialiser.serialise(element);
173 }
174
175 /*
176 * Get an object that contains all registered element classes, where
177 * the key is the PascalCased element name and the value is the class.
178 */
179 get elements() {
180 if (this._elements === undefined) {
181 this._elements = {
182 Element: this.Element,
183 };
184
185 Object.keys(this.elementMap).forEach((name) => {
186 // Currently, all registered element types use a camelCaseName.
187 // Converting to PascalCase is as simple as upper-casing the first
188 // letter.
189 const pascal = name[0].toUpperCase() + name.substr(1);
190 this._elements[pascal] = this.elementMap[name];
191 });
192 }
193
194 return this._elements;
195 }
196
197 /**
198 * Convinience method for getting a JSON Serialiser configured with the
199 * current namespace
200 *
201 * @type JSONSerialiser
202 * @readonly
203 *
204 * @memberof Namespace.prototype
205 */
206 get serialiser() {
207 return new JSONSerialiser(this);
208 }
209}
210
211JSONSerialiser.prototype.Namespace = Namespace;
212
213module.exports = Namespace;
Note: See TracBrowser for help on using the repository browser.