Blame view

node_modules/d/lazy.js 3.79 KB
aaac7fed   liuqimichale   add
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  'use strict';
  
  var map        = require('es5-ext/object/map')
    , isCallable = require('es5-ext/object/is-callable')
    , validValue = require('es5-ext/object/valid-value')
    , contains   = require('es5-ext/string/#/contains')
  
    , call = Function.prototype.call
    , defineProperty = Object.defineProperty
    , getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor
    , getPrototypeOf = Object.getPrototypeOf
    , hasOwnProperty = Object.prototype.hasOwnProperty
    , cacheDesc = { configurable: false, enumerable: false, writable: false,
  		value: null }
    , define;
  
  define = function (name, options) {
  	var value, dgs, cacheName, desc, writable = false, resolvable
  	  , flat;
  	options = Object(validValue(options));
  	cacheName = options.cacheName;
  	flat = options.flat;
  	if (cacheName == null) cacheName = name;
  	delete options.cacheName;
  	value = options.value;
  	resolvable = isCallable(value);
  	delete options.value;
  	dgs = { configurable: Boolean(options.configurable),
  		enumerable: Boolean(options.enumerable) };
  	if (name !== cacheName) {
  		dgs.get = function () {
  			if (hasOwnProperty.call(this, cacheName)) return this[cacheName];
  			cacheDesc.value = resolvable ? call.call(value, this, options) : value;
  			cacheDesc.writable = writable;
  			defineProperty(this, cacheName, cacheDesc);
  			cacheDesc.value = null;
  			if (desc) defineProperty(this, name, desc);
  			return this[cacheName];
  		};
  	} else if (!flat) {
  		dgs.get = function self() {
  			var ownDesc;
  			if (hasOwnProperty.call(this, name)) {
  				ownDesc = getOwnPropertyDescriptor(this, name);
  				// It happens in Safari, that getter is still called after property
  				// was defined with a value, following workarounds that
  				// While in IE11 it may happen that here ownDesc is undefined (go figure)
  				if (ownDesc) {
  					if (ownDesc.hasOwnProperty('value')) return ownDesc.value;
  					if ((typeof ownDesc.get === 'function') && (ownDesc.get !== self)) {
  						return ownDesc.get.call(this);
  					}
  					return value;
  				}
  			}
  			desc.value = resolvable ? call.call(value, this, options) : value;
  			defineProperty(this, name, desc);
  			desc.value = null;
  			return this[name];
  		};
  	} else {
  		dgs.get = function self() {
  			var base = this, ownDesc;
  			if (hasOwnProperty.call(this, name)) {
  				// It happens in Safari, that getter is still called after property
  				// was defined with a value, following workarounds that
  				ownDesc = getOwnPropertyDescriptor(this, name);
  				if (ownDesc.hasOwnProperty('value')) return ownDesc.value;
  				if ((typeof ownDesc.get === 'function') && (ownDesc.get !== self)) {
  					return ownDesc.get.call(this);
  				}
  			}
  			while (!hasOwnProperty.call(base, name)) base = getPrototypeOf(base);
  			desc.value = resolvable ? call.call(value, base, options) : value;
  			defineProperty(base, name, desc);
  			desc.value = null;
  			return base[name];
  		};
  	}
  	dgs.set = function (value) {
  		if (hasOwnProperty.call(this, name)) {
  			throw new TypeError("Cannot assign to lazy defined '" + name + "' property of " + this);
  		}
  		dgs.get.call(this);
  		this[cacheName] = value;
  	};
  	if (options.desc) {
  		desc = {
  			configurable: contains.call(options.desc, 'c'),
  			enumerable: contains.call(options.desc, 'e')
  		};
  		if (cacheName === name) {
  			desc.writable = contains.call(options.desc, 'w');
  			desc.value = null;
  		} else {
  			writable = contains.call(options.desc, 'w');
  			desc.get = dgs.get;
  			desc.set = dgs.set;
  		}
  		delete options.desc;
  	} else if (cacheName === name) {
  		desc = {
  			configurable: Boolean(options.configurable),
  			enumerable: Boolean(options.enumerable),
  			writable: Boolean(options.writable),
  			value: null
  		};
  	}
  	delete options.configurable;
  	delete options.enumerable;
  	delete options.writable;
  	return dgs;
  };
  
  module.exports = function (props) {
  	return map(props, function (desc, name) { return define(name, desc); });
  };