<commit_before>{_} = require "./Underscore"

Utils = require "./Utils"

{EventEmitter} = require "./EventEmitter"

CounterKey = "_ObjectCounter"
DefinedPropertiesKey = "_DefinedPropertiesKey"
DefinedPropertiesValuesKey = "_DefinedPropertiesValuesKey"

capitalizeFirstLetter = (string) ->
	string.charAt(0).toUpperCase() + string.slice(1)

class exports.BaseClass extends EventEmitter

	#################################################################
	# Framer object properties

	@define = (propertyName, descriptor) ->

		# See if we need to add this property to the internal properties class
		if @ isnt BaseClass
			descriptor.enumerable = descriptor.enumerable || !descriptor.hasOwnProperty('enumerable')
			descriptor.propertyName = propertyName

			if not descriptor.excludeFromProps
				@[DefinedPropertiesKey] ?= {}
				@[DefinedPropertiesKey][propertyName] = descriptor

		# Set the getter/setter as setProperty on this object so we can access and override it easily
		getName = "get#{capitalizeFirstLetter(propertyName)}"
		@::[getName] = descriptor.get
		descriptor.get = @::[getName]

		if descriptor.set
			setName = "set#{capitalizeFirstLetter(propertyName)}"
			@::[setName] = descriptor.set
			descriptor.set = @::[setName]

		# Define the property
		Object.defineProperty(@prototype, propertyName, descriptor)

	@simpleProperty = (name, fallback, enumerable=true) ->
		# Default property, provides storage and fallback
		enumerable: enumerable
		default: fallback
		get: -> @_getPropertyValue(name)
		set: (value) -> @_setPropertyValue(name, value)

	@proxyProperty = (keyPath, enumerable=true) ->
		# Allows to easily proxy properties from an instance object
		# Object property is in the form of "object.property"
		objectKey = keyPath.split(".")[0]
		result =
			enumerable: enumerable
			get: ->
				return unless @[objectKey]
				Utils.getValueForKeyPath(@, keyPath)
			set: (value) -> 
				return unless @[objectKey]
				Utils.setValueForKeyPath(@, keyPath, value)

	_setPropertyValue: (k, v) =>
		@[DefinedPropertiesValuesKey][k] = v

	_getPropertyValue: (k) =>
		Utils.valueOrDefault @[DefinedPropertiesValuesKey][k],
			@_getPropertyDefaultValue k

	_getPropertyDefaultValue: (k) ->
		@constructor[DefinedPropertiesKey][k]["default"]

	_propertyList: ->
		@constructor[DefinedPropertiesKey]

	keys: -> _.keys(@props)

	@define "props",
		excludeFromProps: true
		get: ->
			value = {}
			for k, v of @constructor[DefinedPropertiesKey]
				value[k] = @[k]

			value

		set: (value) ->
			for k, v of value
				if @constructor[DefinedPropertiesKey].hasOwnProperty(k)
					if @constructor[DefinedPropertiesKey].exportable isnt false
						@[k] = v

	@define "id",
		get: -> @_id

	toInspect: =>
		properties = _.map(@properties, ((v, k) -> "#{k}:#{v}"), 4)
		"<#{@constructor.name} id:#{@id} #{properties.join " "}>"


	#################################################################
	# Base constructor method

	constructor: (options) ->

		super

		@_context = Framer?.CurrentContext

		# Create a holder for the property values
		@[DefinedPropertiesValuesKey] = {}

		# Count the creation for these objects and set the id
		@constructor[CounterKey] ?= 0
		@constructor[CounterKey] += 1

		@_id = @constructor[CounterKey]

		# Set the default values for this object
		for name, descriptor of @constructor[DefinedPropertiesKey]
			if descriptor.set
				initialValue = Utils.valueOrDefault(options?[name], @_getPropertyDefaultValue(name));
				if not (initialValue in [null, undefined])
					@[name] = initialValue<commit_msg>Following up on feedback (using lodash `pick`, coffeescript `not`) and removing lingering reference to `exportable`. Also leveraging `_propertyList` more for better readability.<commit_after>{_} = require "./Underscore"

Utils = require "./Utils"

{EventEmitter} = require "./EventEmitter"

CounterKey = "_ObjectCounter"
DefinedPropertiesKey = "_DefinedPropertiesKey"
DefinedPropertiesValuesKey = "_DefinedPropertiesValuesKey"

capitalizeFirstLetter = (string) ->
	string.charAt(0).toUpperCase() + string.slice(1)

class exports.BaseClass extends EventEmitter

	#################################################################
	# Framer object properties

	@define = (propertyName, descriptor) ->

		# See if we need to add this property to the internal properties class
		if @ isnt BaseClass
			descriptor.enumerable ?= not descriptor.hasOwnProperty('enumerable')
			descriptor.propertyName = propertyName

			if not descriptor.excludeFromProps
				@[DefinedPropertiesKey] ?= {}
				@[DefinedPropertiesKey][propertyName] = descriptor

		# Set the getter/setter as setProperty on this object so we can access and override it easily
		getName = "get#{capitalizeFirstLetter(propertyName)}"
		@::[getName] = descriptor.get
		descriptor.get = @::[getName]

		if descriptor.set
			setName = "set#{capitalizeFirstLetter(propertyName)}"
			@::[setName] = descriptor.set
			descriptor.set = @::[setName]

		# Define the property
		Object.defineProperty(@prototype, propertyName, descriptor)

	@simpleProperty = (name, fallback, enumerable=true) ->
		# Default property, provides storage and fallback
		enumerable: enumerable
		default: fallback
		get: -> @_getPropertyValue(name)
		set: (value) -> @_setPropertyValue(name, value)

	@proxyProperty = (keyPath, enumerable=true) ->
		# Allows to easily proxy properties from an instance object
		# Object property is in the form of "object.property"
		objectKey = keyPath.split(".")[0]
		result =
			enumerable: enumerable
			get: ->
				return unless @[objectKey]
				Utils.getValueForKeyPath(@, keyPath)
			set: (value) -> 
				return unless @[objectKey]
				Utils.setValueForKeyPath(@, keyPath, value)

	_setPropertyValue: (k, v) =>
		@[DefinedPropertiesValuesKey][k] = v

	_getPropertyValue: (k) =>
		Utils.valueOrDefault @[DefinedPropertiesValuesKey][k],
			@_getPropertyDefaultValue k

	_getPropertyDefaultValue: (k) ->
		@_propertyList()[k]["default"]

	_propertyList: ->
		@constructor[DefinedPropertiesKey]

	keys: -> _.keys(@props)

	@define "props",
		excludeFromProps: true
		get: ->
			_.pick(@, _.keys(@_propertyList()))

		set: (value) ->
			propertyList = @_propertyList()
			for k,v of value
				if propertyList.hasOwnProperty(k)
					@[k] = v

	@define "id",
		get: -> @_id

	toInspect: =>
		properties = _.map(@properties, ((v, k) -> "#{k}:#{v}"), 4)
		"<#{@constructor.name} id:#{@id} #{properties.join " "}>"


	#################################################################
	# Base constructor method

	constructor: (options) ->

		super

		@_context = Framer?.CurrentContext

		# Create a holder for the property values
		@[DefinedPropertiesValuesKey] = {}

		# Count the creation for these objects and set the id
		@constructor[CounterKey] ?= 0
		@constructor[CounterKey] += 1

		@_id = @constructor[CounterKey]

		# Set the default values for this object
		for name, descriptor of @_propertyList()
			if descriptor.set
				initialValue = Utils.valueOrDefault(options?[name], @_getPropertyDefaultValue(name));
				if not (initialValue in [null, undefined])
					@[name] = initialValue
{'fraction_non_alphanumeric': 0.15610923423423423, 'fraction_numerical': 0.0016891891891891893, 'mean_word_length': 4.716009654062751, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7113931', 'n_tokens_mistral': 2365, 'n_tokens_neox': 2087, 'n_words': 548}