UNPKG

3.71 kBJavaScriptView Raw
1var objectPath = require('object-path-immutable');
2var PointerComponent = require('./components/pointer');
3var validator = new (require('ajv/lib/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 if (module.hot) {
68 // We need to hook into any hot-module replacement proxies
69 type = require('react').createElement(type).type;
70 }
71 return {
72 type: type,
73 props: Object.assign({
74 children: slice.call(arguments, 2)
75 }, props),
76 $$typeof: Symbol.for('react.element')
77 };
78};
79
80function Path() {
81 var path = slice.call(arguments);
82 if (path.length === 1 && path[0].length == 0) return '$root';
83 return path;
84}
85
86function OpReplace(value, type) {
87 arguments[1] = convertPathType(type);
88 var path = fixChildrenPath(arguments, 1);
89
90 patch.value = value;
91
92 function patch(obj) {
93 return objectPath.set(obj || {}, path, value);
94 }
95
96 return patch;
97}
98
99function OpRemove(type) {
100 arguments[0] = convertPathType(type);
101 var path = fixChildrenPath(arguments);
102 return function(obj) {
103 return objectPath.del(obj || {}, path);
104 };
105}
106
107function OpCopy(from, to) {
108 from[0] = convertPathType(from[0]);
109 to[0] = convertPathType(to[0]);
110 from = fixChildrenPath(from);
111 to = fixChildrenPath(to);
112
113 return function(obj, init) {
114 var value = getAtPath(init, from);
115 return objectPath.set(obj || {}, to, value);
116 };
117}
118
119function getAtPath(obj, path) {
120 for (var i = 0, parent = obj; i < path.length; i++) {
121 if (typeof parent !== 'object') return undefined;
122 parent = parent[path[i]];
123 }
124 return parent;
125}
126
127function fixChildrenPath(path, start) {
128 var acc = [];
129 for (var i = (start || 0), key; i < path.length; i++) {
130 key = path[i];
131 if (key == 'children') acc.push('props', 'children');
132 else acc.push(key);
133 }
134 return acc;
135}
136
137var pathTypes = {
138 0: 'components',
139 1: 'schemas'
140};
141function convertPathType(type) {
142 return pathTypes[type] || type;
143}
144
145function Schema(schema) {
146 schema = schema || {};
147 var v = validator.compile(schema);
148 function validate(data) {
149 if (data === undefined) data = null;
150 data = JSON.parse(JSON.stringify(data));
151 var isValid = v(data);
152 var errors = v.errors;
153 if (errors) errors.forEach(function(error) {
154 error.dataPath = '#' + (error.dataPath || '/');
155 });
156
157 return {
158 isValid: isValid,
159 errors: errors,
160 data: data,
161 schema: schema
162 };
163 };
164
165 validate.schema = schema;
166
167 return validate;
168}
169
170function Subscription(id) {
171 return id;
172}