from __future__ import unicode_literals from ..conversions import * from ..func_utils import * from ..base import is_data_descriptor import six def Object(this, args): val = get_arg(args, 0) if is_null(val) or is_undefined(val): return args.space.NewObject() return to_object(val, args.space) def ObjectCreate(args, space): if len(args): val = get_arg(args, 0) if is_object(val): # Implementation dependent, but my will simply return :) return val elif type(val) in (NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE): return to_object(val, space) return space.NewObject() class ObjectMethods: def getPrototypeOf(this, args): obj = get_arg(args, 0) if not is_object(obj): raise MakeError('TypeError', 'Object.getPrototypeOf called on non-object') return null if obj.prototype is None else obj.prototype def getOwnPropertyDescriptor(this, args): obj = get_arg(args, 0) prop = get_arg(args, 1) if not is_object(obj): raise MakeError( 'TypeError', 'Object.getOwnPropertyDescriptor called on non-object') desc = obj.own.get(to_string(prop)) return convert_to_js_type(desc, args.space) def getOwnPropertyNames(this, args): obj = get_arg(args, 0) if not is_object(obj): raise MakeError( 'TypeError', 'Object.getOwnPropertyDescriptor called on non-object') return args.space.ConstructArray(obj.own.keys()) def create(this, args): obj = get_arg(args, 0) if not (is_object(obj) or is_null(obj)): raise MakeError('TypeError', 'Object prototype may only be an Object or null') temp = args.space.NewObject() temp.prototype = None if is_null(obj) else obj if len(args) > 1 and not is_undefined(args[1]): if six.PY2: args.tup = (args[1], ) ObjectMethods.defineProperties.__func__(temp, args) else: args.tup = (args[1], ) ObjectMethods.defineProperties(temp, args) return temp def defineProperty(this, args): obj = get_arg(args, 0) prop = get_arg(args, 1) attrs = get_arg(args, 2) if not is_object(obj): raise MakeError('TypeError', 'Object.defineProperty called on non-object') name = to_string(prop) if not obj.define_own_property(name, ToPropertyDescriptor(attrs), False): raise MakeError('TypeError', 'Cannot redefine property: %s' % name) return obj def defineProperties(this, args): obj = get_arg(args, 0) properties = get_arg(args, 1) if not is_object(obj): raise MakeError('TypeError', 'Object.defineProperties called on non-object') props = to_object(properties, args.space) for k, v in props.own.items(): if not v.get('enumerable'): continue desc = ToPropertyDescriptor(props.get(unicode(k))) if not obj.define_own_property(unicode(k), desc, False): raise MakeError('TypeError', 'Failed to define own property: %s' % k) return obj def seal(this, args): obj = get_arg(args, 0) if not is_object(obj): raise MakeError('TypeError', 'Object.seal called on non-object') for desc in obj.own.values(): desc['configurable'] = False obj.extensible = False return obj def freeze(this, args): obj = get_arg(args, 0) if not is_object(obj): raise MakeError('TypeError', 'Object.freeze called on non-object') for desc in obj.own.values(): desc['configurable'] = False if is_data_descriptor(desc): desc['writable'] = False obj.extensible = False return obj def preventExtensions(this, args): obj = get_arg(args, 0) if not is_object(obj): raise MakeError('TypeError', 'Object.preventExtensions on non-object') obj.extensible = False return obj def isSealed(this, args): obj = get_arg(args, 0) if not is_object(obj): raise MakeError('TypeError', 'Object.isSealed called on non-object') if obj.extensible: return False for desc in obj.own.values(): if desc.get('configurable'): return False return True def isFrozen(this, args): obj = get_arg(args, 0) if not is_object(obj): raise MakeError('TypeError', 'Object.isFrozen called on non-object') if obj.extensible: return False for desc in obj.own.values(): if desc.get('configurable'): return False if is_data_descriptor(desc) and desc.get('writable'): return False return True def isExtensible(this, args): obj = get_arg(args, 0) if not is_object(obj): raise MakeError('TypeError', 'Object.isExtensible called on non-object') return obj.extensible def keys(this, args): obj = get_arg(args, 0) if not is_object(obj): raise MakeError('TypeError', 'Object.keys called on non-object') return args.space.ConstructArray([ unicode(e) for e, d in six.iteritems(obj.own) if d.get('enumerable') ]) # some utility functions: def ToPropertyDescriptor(obj): # page 38 (50 absolute) if not is_object(obj): raise MakeError('TypeError', 'Can\'t convert non-object to property descriptor') desc = {} if obj.has_property('enumerable'): desc['enumerable'] = to_boolean(obj.get('enumerable')) if obj.has_property('configurable'): desc['configurable'] = to_boolean(obj.get('configurable')) if obj.has_property('value'): desc['value'] = obj.get('value') if obj.has_property('writable'): desc['writable'] = to_boolean(obj.get('writable')) if obj.has_property('get'): cand = obj.get('get') if not (is_undefined(cand) or is_callable(cand)): raise MakeError( 'TypeError', 'Invalid getter (it has to be a function or undefined)') desc['get'] = cand if obj.has_property('set'): cand = obj.get('set') if not (is_undefined(cand) or is_callable(cand)): raise MakeError( 'TypeError', 'Invalid setter (it has to be a function or undefined)') desc['set'] = cand if ('get' in desc or 'set' in desc) and ('value' in desc or 'writable' in desc): raise MakeError( 'TypeError', 'Invalid property. A property cannot both have accessors and be writable or have a value.' ) return desc