type enforcement
This commit is contained in:
@@ -222,6 +222,7 @@ You can define a relative icon with the following:
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| **`icon`** | string | **yes** | name of the Font-Awesome icon of the sub-element (see [Icon names](#icon-names)) |
|
| **`icon`** | string | **yes** | name of the Font-Awesome icon of the sub-element (see [Icon names](#icon-names)) |
|
||||||
| `color` | string | no | redefined the color |
|
| `color` | string | no | redefined the color |
|
||||||
|
| `scale` | number | no | redefine this icon scale |
|
||||||
|
|
||||||
## More info
|
## More info
|
||||||
*[back to top](#top)*
|
*[back to top](#top)*
|
||||||
|
|||||||
@@ -15,6 +15,18 @@ const utils = require('./utils');
|
|||||||
* @property {string|undefined} direction
|
* @property {string|undefined} direction
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const NODE_DEF = {
|
||||||
|
'name': '!string',
|
||||||
|
'x': 'number',
|
||||||
|
'y': 'number'
|
||||||
|
};
|
||||||
|
|
||||||
|
const LINK_DEF = {
|
||||||
|
'from': '!string',
|
||||||
|
'to': '!string',
|
||||||
|
'direction': 'string'
|
||||||
|
};
|
||||||
|
|
||||||
const DEFAULT_OPTIONS = {
|
const DEFAULT_OPTIONS = {
|
||||||
'max-link-length': 3,
|
'max-link-length': 3,
|
||||||
'diagonals': true,
|
'diagonals': true,
|
||||||
@@ -307,6 +319,19 @@ module.exports = (options) => {
|
|||||||
* @returns {Object<string,Node1>|null}
|
* @returns {Object<string,Node1>|null}
|
||||||
*/
|
*/
|
||||||
compute: (nodes, links) => {
|
compute: (nodes, links) => {
|
||||||
|
|
||||||
|
Object.keys(nodes).forEach(key => {
|
||||||
|
const res = utils.isValid(nodes[key], NODE_DEF);
|
||||||
|
if (res)
|
||||||
|
throw `node '${key}' is invalid at key ${res}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
links.forEach((link, i) => {
|
||||||
|
const res = utils.isValid(link, LINK_DEF);
|
||||||
|
if (res)
|
||||||
|
throw `link ${i} (${link.from}->${link.to}) is invalid at key ${res}`;
|
||||||
|
});
|
||||||
|
|
||||||
Object.values(nodes).forEach(node => {
|
Object.values(nodes).forEach(node => {
|
||||||
node.const = {
|
node.const = {
|
||||||
beforeX: [],
|
beforeX: [],
|
||||||
|
|||||||
@@ -23,6 +23,40 @@ try {
|
|||||||
* @property {string|undefined} type
|
* @property {string|undefined} type
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const SUB_DEF = {
|
||||||
|
'text': 'string',
|
||||||
|
'icon': 'string',
|
||||||
|
'color': 'string',
|
||||||
|
'font': 'string',
|
||||||
|
'font-size': 'number',
|
||||||
|
'font-style': 'string',
|
||||||
|
'scale': 'number',
|
||||||
|
};
|
||||||
|
|
||||||
|
const NODE_DEF = {
|
||||||
|
'name': '!string',
|
||||||
|
'icon': '!string',
|
||||||
|
'x': '!number',
|
||||||
|
'y': '!number',
|
||||||
|
'color': 'string',
|
||||||
|
'scale': 'number',
|
||||||
|
'top': SUB_DEF,
|
||||||
|
'bottom': SUB_DEF,
|
||||||
|
'left': SUB_DEF,
|
||||||
|
'right': SUB_DEF
|
||||||
|
};
|
||||||
|
|
||||||
|
const LINK_DEF = {
|
||||||
|
'from': '!string',
|
||||||
|
'to': '!string',
|
||||||
|
'type': 'string',
|
||||||
|
'color': 'string',
|
||||||
|
'scale': 'number',
|
||||||
|
'size': 'number',
|
||||||
|
'top': SUB_DEF,
|
||||||
|
'bottom': SUB_DEF,
|
||||||
|
};
|
||||||
|
|
||||||
const DEFAULT_OPTIONS = {
|
const DEFAULT_OPTIONS = {
|
||||||
'beautify': false,
|
'beautify': false,
|
||||||
'scale': 128,
|
'scale': 128,
|
||||||
@@ -230,8 +264,24 @@ module.exports = (options) => {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object<string,Node2>} nodes
|
||||||
|
* @param {Link2[]} links
|
||||||
|
*/
|
||||||
compute: (nodes, links) => {
|
compute: (nodes, links) => {
|
||||||
|
|
||||||
|
Object.keys(nodes).forEach(key => {
|
||||||
|
const res = utils.isValid(nodes[key], NODE_DEF);
|
||||||
|
if (res)
|
||||||
|
throw `node '${key}' is invalid at key ${res}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
links.forEach((link, i) => {
|
||||||
|
const res = utils.isValid(link, LINK_DEF);
|
||||||
|
if (res)
|
||||||
|
throw `link ${i} (${link.from}->${link.to}) is invalid at key ${res}`;
|
||||||
|
});
|
||||||
|
|
||||||
const bounds = self.getBounds(nodes);
|
const bounds = self.getBounds(nodes);
|
||||||
|
|
||||||
const data = {'g': []};
|
const data = {'g': []};
|
||||||
|
|||||||
@@ -21,6 +21,40 @@ const self = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify if an object respect it's definition
|
||||||
|
* @param obj
|
||||||
|
* @param def
|
||||||
|
* @returns {null|string}
|
||||||
|
*/
|
||||||
|
isValid: (obj, def) => {
|
||||||
|
const keys = Object.keys(def);
|
||||||
|
let key;
|
||||||
|
let type;
|
||||||
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
key = keys[i];
|
||||||
|
type = (typeof obj !== 'object' || obj[key] === undefined || obj[key] === null) ? null : typeof obj[key];
|
||||||
|
if (type === 'object' && obj[key].length > 0)
|
||||||
|
type = 'array';
|
||||||
|
if (typeof def[key] === 'object') {
|
||||||
|
if (type && type !== 'object')
|
||||||
|
return key;
|
||||||
|
const res = self.isValid(type ? obj[key] : undefined, def[key]);
|
||||||
|
if (res)
|
||||||
|
return key + '.' + res;
|
||||||
|
} else {
|
||||||
|
if (def[key][0] === '!') {
|
||||||
|
def[key] = def[key].substr(1);
|
||||||
|
if (!type)
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
if (type && type !== def[key])
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone any JS variable or object
|
* Clone any JS variable or object
|
||||||
* @param {*} arg
|
* @param {*} arg
|
||||||
|
|||||||
@@ -36,6 +36,54 @@ describe('merge', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('isValid', () => {
|
||||||
|
test('valid number', () => {
|
||||||
|
expect(utils.isValid({a: 0}, {a: 'number'})).toBe(null);
|
||||||
|
});
|
||||||
|
test('invalid number', () => {
|
||||||
|
expect(utils.isValid({b: 'number'}, {b: 'number'})).toBe('b');
|
||||||
|
});
|
||||||
|
test('valid string', () => {
|
||||||
|
expect(utils.isValid({b: ''}, {b: 'string'})).toBe(null);
|
||||||
|
});
|
||||||
|
test('invalid string', () => {
|
||||||
|
expect(utils.isValid({b: 0}, {b: 'string'})).toBe('b');
|
||||||
|
});
|
||||||
|
test('valid array', () => {
|
||||||
|
expect(utils.isValid({c: [1, 2, 3]}, {c: 'array'})).toBe(null);
|
||||||
|
});
|
||||||
|
test('invalid array', () => {
|
||||||
|
expect(utils.isValid({c: {d: 5}}, {c: 'array'})).toBe('c');
|
||||||
|
});
|
||||||
|
test('undefined optional key', () => {
|
||||||
|
expect(utils.isValid({}, {a: 'number'})).toBe(null);
|
||||||
|
});
|
||||||
|
test('undefined required key', () => {
|
||||||
|
expect(utils.isValid({}, {a: '!number'})).toBe('a');
|
||||||
|
});
|
||||||
|
test('defined required key', () => {
|
||||||
|
expect(utils.isValid({a: 5}, {a: '!number'})).toBe(null);
|
||||||
|
});
|
||||||
|
test('invalid sub-object', () => {
|
||||||
|
expect(utils.isValid({a: 5}, {a: {b: 'number'}})).toBe('a');
|
||||||
|
});
|
||||||
|
test('undefined not required sub-object', () => {
|
||||||
|
expect(utils.isValid({}, {a: {b: 'number'}})).toBe(null);
|
||||||
|
});
|
||||||
|
test('undefined required sub-object', () => {
|
||||||
|
expect(utils.isValid({}, {a: {b: '!number'}})).toBe('a.b');
|
||||||
|
});
|
||||||
|
test('invalid sub-object', () => {
|
||||||
|
expect(utils.isValid({a: {b: 'hello'}}, {a: {b: 'number'}})).toBe('a.b');
|
||||||
|
});
|
||||||
|
test('defined required sub-object', () => {
|
||||||
|
expect(utils.isValid({a: {b: 5}}, {a: {b: '!number'}})).toBe(null);
|
||||||
|
});
|
||||||
|
test('ignored extra key', () => {
|
||||||
|
expect(utils.isValid({b: 5}, {a: 'number'})).toBe(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('ezClone', () => {
|
test('ezClone', () => {
|
||||||
const a = {
|
const a = {
|
||||||
'a': 5,
|
'a': 5,
|
||||||
|
|||||||
Reference in New Issue
Block a user