Skip to content

Commit 5305515

Browse files
authored
Merge pull request #8 from VisualSJ/master-schema
Support inheritance
2 parents bbaa34b + e94e998 commit 5305515

2 files changed

Lines changed: 123 additions & 3 deletions

File tree

lib/main.js

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ const path = require('path');
1010
const schema = require('./utils/schema');
1111

1212
let _url2profile = {};
13-
let _type2path = {};
1413
let _url2schema = {};
1514

15+
let _type2path = {};
16+
let _type2parent = {};
17+
1618
// register profile://
1719
protocols.register('profile', uri => {
1820
let base = _type2path[uri.hostname];
@@ -119,6 +121,21 @@ profile.register = function ( type, path ) {
119121
_type2path[type] = path;
120122
};
121123

124+
/**
125+
* @method inherit
126+
* @param {string} type - Current type
127+
* @param {string} parent - The parent type
128+
*
129+
* Set up a type of inheritance relationship
130+
* When the data cannot be found, it will query the data at the parent type
131+
*/
132+
profile.inherit = function ( type, parent ) {
133+
if (!_type2path[parent]) {
134+
console.warn(`The type of inheritance is not registered yet - ${parent}`);
135+
}
136+
_type2parent[type] = parent;
137+
};
138+
122139
/**
123140
* @method reset
124141
*
@@ -146,6 +163,17 @@ profile.registerSchema = function ( url, json ) {
146163
if (!_url2profile[url] || !json) {
147164
return;
148165
}
166+
167+
if ( url.indexOf('profile://') !== 0 ) {
168+
console.error(`Failed to load profile ${url}: invalid protocol.`);
169+
return;
170+
}
171+
172+
let type = url.match(/^profile:\/\/([^\/]+)/)[1];
173+
174+
if (_type2parent[type]) {
175+
console.log(`Failed to register schema ${url}: only root profile can register schema`);
176+
}
149177
_url2schema[url] = schema.json2schema(json);
150178
};
151179

@@ -158,12 +186,26 @@ class _Profile extends EventEmitter {
158186
super();
159187
this._url = url;
160188
this._data = data;
189+
190+
let match = url.match(/^profile\:\/\/([^\/]+)\/(.*)$/);
191+
this._type = match[1];
192+
this._file = match[2];
161193
}
162194

163195
get (key) {
164-
let schema = _url2schema[this._url];
196+
let schema = this.getSchema(this._type, this._file);
165197
let target = this._data[key];
166198

199+
// Find the data on the inheritance chain
200+
let type = this._type;
201+
while (target === undefined && _type2parent[type]) {
202+
let parent = _type2parent[type];
203+
let parentUrl = `profile://${parent}/${this._file}`;
204+
let patentProfile = _url2profile[parentUrl];
205+
target = patentProfile ? patentProfile._data[key] : undefined;
206+
type = parent;
207+
}
208+
167209
if (schema && target === undefined) {
168210
let property = schema.properties[key];
169211
target = property ? property.default : target;
@@ -177,7 +219,8 @@ class _Profile extends EventEmitter {
177219
}
178220

179221
set (key, value) {
180-
let error = schema.validate(_url2schema[this._url], key, value);
222+
let json = this.getSchema(this._type, this._file);
223+
let error = schema.validate(json, key, value);
181224
if (error) {
182225
return console.warn(`Failed to set profile ${key}: ${error}`);
183226
}
@@ -218,6 +261,14 @@ class _Profile extends EventEmitter {
218261
this._data = data;
219262
}
220263

264+
getSchema () {
265+
let type = this._type;
266+
while (_type2parent[type]) {
267+
type = _type2parent[type];
268+
}
269+
return _url2schema[`profile://${type}/${this._file}`];
270+
}
271+
221272
} // end class Profile
222273

223274
// ==========================

test/unit/inherit.spec.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
const fsJetpack = require('fs-jetpack');
5+
const profile = require('../../index');
6+
7+
suite(tap, 'profile inherit', { timeout: 2000 }, t => {
8+
let global = path.join(__dirname, '../fixtures/global');
9+
let local = path.join(__dirname, '../fixtures/local');
10+
fsJetpack.dir(global);
11+
fsJetpack.dir(local);
12+
13+
profile.register('global', global);
14+
profile.register('local', local);
15+
16+
profile.inherit('local', 'global');
17+
18+
let globalJson = {
19+
foo: 'foo',
20+
bar: 'bar'
21+
};
22+
let localJson = {
23+
bar: ''
24+
};
25+
26+
let globalJsonPath = path.join(global, 'inherit.json');
27+
let localJsonPath = path.join(local, 'inherit.json');
28+
fsJetpack.write(globalJsonPath, globalJson);
29+
fsJetpack.write(localJsonPath, localJson);
30+
31+
let globalProfile = profile.load('profile://global/inherit.json');
32+
let localProfile = profile.load('profile://local/inherit.json');
33+
34+
let globalSchema = {
35+
'foo': '',
36+
'bar': '',
37+
'boolean': true,
38+
};
39+
let localSchema = {
40+
'foo': 0,
41+
'bar': 0,
42+
};
43+
profile.registerSchema('profile://global/inherit.json', globalSchema);
44+
profile.registerSchema('profile://local/inherit.json', localSchema);
45+
46+
t.test('profile inherit', (t) => {
47+
t.equal(globalProfile.get('foo'), globalJson['foo']);
48+
t.equal(globalProfile.get('bar'), globalJson['bar']);
49+
t.equal(localProfile.get('foo'), globalJson['foo']);
50+
t.equal(localProfile.get('bar'), localJson['bar']);
51+
t.end();
52+
});
53+
54+
t.test('profile inherit and schema', (t) => {
55+
56+
localProfile.set('foo', 2);
57+
t.equal(globalProfile.get('foo'), globalJson['foo']);
58+
t.equal(localProfile.get('foo'), globalJson['foo']);
59+
60+
globalProfile.set('foo', 'abc');
61+
t.equal(globalProfile.get('foo'), 'abc');
62+
t.equal(localProfile.get('foo'), 'abc');
63+
64+
t.end();
65+
});
66+
67+
fsJetpack.remove(global);
68+
fsJetpack.remove(local);
69+
});

0 commit comments

Comments
 (0)