| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- module.exports.mixin = function(result, ...args) {
- for (const arg of args) {
- mixinObject(result, arg);
- }
- return result;
- };
- module.exports.link = function(root) {
- const visited = new Set();
- link(root);
- return root;
- function link(o) {
- if (visited.has(o)) {
- return;
- }
- visited.add(o);
- const __extends__ = o.__extends__;
- const extended = {};
- if (typeof __extends__ === 'string') {
- const base = find(__extends__);
- if (!base) {
- console.error(`Can not find the __extends__ ${__extends__}`);
- } else {
- link(base);
- mixinObject(extended, base);
- }
- }
- for (const [k, v] of Object.entries(o)) {
- if (typeof v === 'object' && v) {
- link(v);
- }
- }
- mixinObject(o, extended);
- }
- function find(path) {
- const items = path.split('.');
- if (items.length === 0) {
- return undefined;
- }
- let result = root;
- for (const item of items) {
- if (!item) {
- return undefined;
- }
- if (!(item in result)) {
- return undefined;
- }
- const r = result[item];
- if (typeof r !== 'object' || !r) {
- return undefined;
- }
- result = r;
- }
- return result;
- }
- };
- function mixinObject(o1, o2, o1FullPath, o2FullPath) {
- for (const [k, v2] of Object.entries(o2)) {
- if (typeof v2 !== 'object' || !v2) {
- if (k in o1) {
- reportMixinFailure(k);
- } else {
- o1[k] = v2;
- }
- continue;
- }
- if (Array.isArray(v2)) {
- let v1;
- if (!(k in o1)) {
- v1 = o1[k] = [];
- } else if (Array.isArray(o1[k])) {
- v1 = o1[k];
- } else {
- reportMixinFailure(k);
- continue;
- }
- v1.push(...v2);
- continue;
- }
- // v2 is object
- {
- let v1;
- if (!(k in o1)) {
- v1 = o1[k] = {};
- } else {
- v1 = o1[k];
- if (typeof v1 !== 'object' || !v1) {
- reportMixinFailure(k);
- continue;
- }
- }
- mixinObject(v1, v2, getFullPath(o1FullPath, k), getFullPath(o2FullPath, k));
- continue;
- }
- }
- function reportMixinFailure(k) {
- console.error(
- `Can not mix `
- + `${getFullPath(o2FullPath, k)}(type: ${getLogType(o2[k])}) `
- + `into `
- + `${getFullPath(o1FullPath, k)}(type: ${getLogType(o1[k])})`
- );
- }
- function getFullPath(prefix, k) {
- return `${prefix}['${k}']`;
- }
- function getLogType(v) {
- if (typeof v !== 'object') {
- return typeof v;
- } else if (!v) {
- return 'null';
- } else if (Array.isArray(v)) {
- return 'array';
- } else {
- return 'object';
- }
- }
- }
|