UNPKG

3.58 kBJavaScriptView Raw
1var objectPath = require('object-path-immutable');
2var PointerComponent = require('./components/pointer');
3var validator = new (require('ajv'))({
4 allErrors: true,
5 jsonPointers: true,
6 coerceTypes: true,
7 removeAdditional: 'all',
8 v5: true,
9 useDefaults: true
10});
11
12module.exports = function(opts) {
13 var controls = opts.controls;
14
15 function createElement(type) {
16 var control = controls[type];
17 if (!control) {
18 console.warn('Missing control ' + JSON.stringify(type));
19 return null;
20 }
21 arguments[0] = control;
22 return Element.apply(null, arguments);
23 }
24
25 return function(codec, encode, decode) {
26 var codecs = {
27 33: Affordance,
28 34: ComponentPointer,
29 31: createElement,
30 32: Path,
31 35: OpRemove,
32 36: OpReplace,
33 37: OpCopy,
34 38: Schema,
35 39: Subscription
36 };
37
38 Object.keys(codecs).forEach(function(key) {
39 var constructor = codecs[key];
40 codec.addExtUnpacker(+key, function(data) {
41 data = decode(data);
42 if (!Array.isArray(data)) data = [data];
43 return constructor.apply(null, data);
44 });
45 });
46 };
47};
48
49var slice = [].slice;
50
51function Affordance(ref, schema_id) {
52 return {
53 ref: ref,
54 schema_id: schema_id
55 };
56}
57
58function ComponentPointer() {
59 var path = Path.apply(null, arguments);
60 return Element(
61 PointerComponent,
62 {path: path}
63 );
64}
65
66function Element(type, props) {
67 return {
68 $$typeof: Symbol.for('react.element'),
69 type: type,
70 props: Object.assign({
71 children: slice.call(arguments, 2)
72 }, props)
73 };
74}
75
76function Path() {
77 var path = slice.call(arguments);
78 if (path.length === 1 && path[0].length == 0) return '$root';
79 return JSON.stringify(path);
80}
81
82function OpReplace(value, type) {
83 arguments[1] = convertPathType(type);
84 var path = fixChildrenPath(arguments, 1);
85
86 patch.value = value;
87
88 function patch(obj) {
89 return objectPath.set(obj || {}, path, value);
90 }
91
92 return patch;
93}
94
95function OpRemove(type) {
96 arguments[0] = convertPathType(type);
97 var path = fixChildrenPath(arguments);
98 return function(obj) {
99 return objectPath.del(obj || {}, path);
100 };
101}
102
103function OpCopy(from, to) {
104 from[0] = convertPathType(from[0]);
105 to[0] = convertPathType(to[0]);
106 from = fixChildrenPath(from);
107 to = fixChildrenPath(to);
108
109 return function(obj, init) {
110 var value = getAtPath(init, from);
111 return objectPath.set(obj || {}, to, value);
112 };
113}
114
115function getAtPath(obj, path) {
116 for (var i = 0, parent = obj; i < path.length; i++) {
117 if (typeof parent !== 'object') return undefined;
118 parent = parent[path[i]];
119 }
120 return parent;
121}
122
123function fixChildrenPath(path, start) {
124 var acc = [];
125 for (var i = (start || 0), key; i < path.length; i++) {
126 key = path[i];
127 if (key == 'children') acc.push('props', 'children');
128 else acc.push(key);
129 }
130 return acc;
131}
132
133var pathTypes = {
134 0: 'components',
135 1: 'schemas'
136};
137function convertPathType(type) {
138 return pathTypes[type] || type;
139}
140
141function Schema(schema) {
142 schema = schema || {};
143 var v = validator.compile(schema);
144 function validate(data) {
145 if (data === undefined) data = null;
146 data = JSON.parse(JSON.stringify(data));
147 var isValid = v(data);
148 var errors = v.errors;
149 if (errors) errors.forEach(function(error) {
150 error.dataPath = '#' + (error.dataPath || '/');
151 });
152
153 return {
154 isValid: isValid,
155 errors: errors,
156 data: data,
157 schema: schema
158 };
159 };
160
161 validate.schema = schema;
162
163 return validate;
164}
165
166function Subscription(id) {
167 return id;
168}