spica
Version:
Supervisor, Coroutine, Channel, select, AtomicPromise, Cancellation, Cache, List, Queue, Stack, and some utils.
129 lines (119 loc) • 4 kB
text/typescript
import { ObjectCreate } from './alias';
import { type, isPrimitive } from './type';
import { push } from './array';
export const assign = template((prop, target, source) =>
target[prop] = source[prop]);
export const clone = template((prop, target, source) => {
switch (type(source[prop])) {
case 'Array':
return target[prop] = source[prop].slice();
case 'Object':
switch (type(target[prop])) {
case 'Object':
return target[prop] = clone(empty(source[prop]), source[prop]);
default:
return target[prop] = source[prop];
}
default:
return target[prop] = source[prop];
}
});
export const overwrite = template((prop, target, source) => {
switch (type(source[prop])) {
case 'Array':
return target[prop] = source[prop];
case 'Object':
switch (type(target[prop])) {
case 'Object':
return overwrite(target[prop], source[prop]);
default:
return target[prop] = overwrite(empty(source[prop]), source[prop]);
}
default:
return target[prop] = source[prop];
}
});
export const extend = template((prop, target, source) => {
switch (type(source[prop])) {
case 'undefined':
return;
case 'Array':
return target[prop] = source[prop];
case 'Object':
switch (type(target[prop])) {
case 'Object':
return extend(target[prop], source[prop]);
default:
return target[prop] = extend(empty(source[prop]), source[prop]);
}
default:
return target[prop] = source[prop];
}
});
export const merge = template((prop, target, source) => {
switch (type(source[prop])) {
case 'undefined':
return;
case 'Array':
switch (type(target[prop])) {
case 'Array':
return target[prop] = push(target[prop], source[prop]);
default:
return target[prop] = source[prop].slice();
}
case 'Object':
switch (type(target[prop])) {
case 'Object':
return merge(target[prop], source[prop]);
default:
return target[prop] = merge(empty(source[prop]), source[prop]);
}
default:
return target[prop] = source[prop];
}
});
export const inherit = template((prop, target, source) => {
switch (type(source[prop])) {
case 'undefined':
return;
case 'Array':
return target[prop] = source[prop].slice();
case 'Object':
switch (type(target[prop])) {
case 'Object':
assert(target.hasOwnProperty(prop));
return inherit(target[prop], source[prop]);
default:
return target[prop] = ObjectCreate(source[prop]);
}
default:
return target[prop] = source[prop];
}
});
export function template(strategy: (prop: string, target: object, source: object) => void) {
return walk;
function walk<T extends U, U extends object>(target: T, source: Partial<U>, ...sources: Partial<U>[]): T;
function walk<T extends U, U extends object>(target: Partial<U>, source1: T, source2: Partial<U>, ...sources: Partial<U>[]): T;
function walk<T extends object>(target: T, ...sources: Partial<T>[]): T;
function walk<T extends object>(target: Partial<T>, source1: T, source2: Partial<T>, ...sources: Partial<T>[]): T;
function walk<T extends object>(target: T, ...sources: T[]): T {
assert(!isPrimitive(target));
if (isPrimitive(target)) return target;
for (let i = 0; i < sources.length; ++i) {
const source = sources[i];
if (source === target) continue;
assert(!isPrimitive(source));
if (isPrimitive(source)) continue;
assert(!isPrimitive(target) && !isPrimitive(source));
const keys = Object.keys(source);
for (let i = 0; i < keys.length; ++i) {
strategy(keys[i], target, source);
}
}
return target;
}
}
function empty(source: object): object {
assert(type(source) === 'Object');
return source instanceof Object ? {} : ObjectCreate(null);
}