make it easier to manage the properties/attributes of your class.
Features:
- Inherited properties with class.
- Assign properties from a plain object(JSON Object).
- Clone object.
- Compare object whether is the same.
- Export properties to a plain object(JSON Object).
- Declare properties with type and default value.
- Supports
arrayOfproperty with type - Supports property with
template(the property value is determined by the template content):template{string | (this) => string}:- the template string, eg,
'${author}-${uuid()}' - or customize template function,
function() {return this.author + '-' + uuid()}
- the template string, eg,
imports:{Object}the optional functions could be used in the template string.- NOTE: the template property is readonly by default. You can make it writeable. Once a new value has been written, the template will be no useful unless the new value is null or undefined.
- Supports
We often need to manage the properties of an object, consider the following:
- Set the options to the properties of object when the object was created
var myObj = new MyObject({opt1:value1, opt2:value2})
- Assign the options value from another object:
myObj.assign({opt1:v1, opt2:v2})
- Clone an object:
var newObj = myObj.clone()
- Compare two objects whether is the same by their options(assigned properties).
myObj.isSame(anotherObj)
- Export the properties as a plain object or JSON to make recreate the object easier in the future.
- There are some internal attributes should not be exported.
- The empty or default value of an attribute should not be exported.
- the meaningful(non-english) name should be exported and assigned.
myObj.toObject()andmyObj.toJSON()JSON.stringify(myObj)
- Problem: how to assign an object value of a property?
- replace the standard
assignPropertyTo()method. - define the attribute's
assign(value, dest, src, name)method on the$attributes.- the custom attribute's
assignthe value. return the changed value.
- the custom attribute's
- replace the standard
- Problem: how to decide which property should be assign value or get default value of an attribute?
- define all attributes on this object even though the value is null.
- no default value feature.
- define a simple
$attributesproperty to manage this:{attrName: {value:'defaultValue'}, ...}
- define a complex
$attributes(usePropertiesclass) to manage attributes.
- define all attributes on this object even though the value is null.
So we have these classes: SimplePropertyManager,NormalPropertyManager and AdvancePropertyManager.
first the rules of the properties:
- exported attributes means they are the JSON.stringify(aObj) attributes only.
- The non-enumerable attributes can not be exported and assigned.
- The enumerable attributes beginning with '$' can not be exported. but can be assigned.
undefinedvalue can not be exported.- the readonly(writable is false) attributes can not be assigned.
- IMPORTANT: By default, readonly properties (
writable: false) are NOT exported. If you want a readonly property to be exported (e.g., to appear intoObject()ortoJSON()), you must explicitly setexported: true.
- IMPORTANT: By default, readonly properties (
- the assignment order of properties is the order of defined properties.
SimplePropertyManager: /lib/simple- use the object's property descriptor directly.
- so do not support default value.
- do not support object value assignment hook function.
- do not support meaningful(non-english) name.
- When defining properties, you must not use
nonExported1stCharanddefaultOptionsas property names.
NormalPropertyManager: /lib/normal- use the
$attributesplain object to hold the declaration properties - support default value.
- support object value assignment hook function.
- support meaningful(non-english) name.
- Recommendation: To facilitate future upgrades to
AdvancePropertyManager, it is recommended to avoid using the reserved keywords ofAdvancePropertyManagerwhen defining properties. These names include:_names,_ixNames,nonExported1stChar,extends,merge,mergeTo,mergePropertyTo,_initialize,initialize,updateNames,initializeTo,getRealAttrName,validatePropertyValue,assignPropertyTo,assignTo,isDefaultObject,getValue.
- use the
AdvancePropertyManager: /lib/advance- use the
$attributesto hold the declaration properties - the
$attributesis an instance ofPropertiesclass. - so you can custom your
Propertiesclass inherited from. - support default value.
- support object value assignment hook function.
- support meaningful(non-english) name.
- support type check if possible.
- NOTE: Because
$attributesis an instance of thePropertiesclass, property names cannot conflict with the reserved method names of thePropertiesclass when defining properties. These reserved names include:_names,_ixNames,nonExported1stChar,extends,merge,mergeTo,mergePropertyTo,_initialize,initialize,updateNames,initializeTo,getRealAttrName,validatePropertyValue,assignPropertyTo,assignTo,isDefaultObject,getValue.
- use the
The $attributes holds all attributes(like the property descriptor) of an object.
The key is the property name. the value is the property descriptor:
name(String): the non-english name to export, Defaults to thekeyname.value: the property's default value if exists. Defaults toundefined.type(String): the property's type name. defaults to undefined.enumerable(Boolean): defaults to true- true if and only if this property shows up during enumeration of the properties on the corresponding object.
configurable(Boolean): defaults to true- true if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object.
writable(Boolean): defaults to true- true if and only if the value associated with the property may be changed with an assignment operator.
assign(Function(value, dest, src, name)):the custom attribute assignment function. justreturnthe changed value. defaults to undefined. It means do not assign this value if returnundefined- Note: It only used on assign the options from another object.
- It's no effect if the assign the property individually. use the property descriptor
setto do so. - Wrap it as smart-assign feature(only on Advance Property Manager):
- automatically add a hidden internal property with prefix
- automatically add descriptor
getfunction to read the property - automatically add descriptor
setfunction to assign the property(call theassigndescriptor).
- only available on Normal and Advance Property Manager:
assigned(Boolean): whether the property can be assigned. defaults: undefined- if undefined then
=enumerable isn't false and (writable isn't false or isFunction(set))
- if undefined then
- Smart Assign Support only available on AdvancePropertyManager
assigned(Boolean|String): enable smart-assign support when the assigned is string- it uses the
nonExported1stChar+nameas the internal property name if the string is empty - the
assignedstring is the internal property name if it's non-empty.
exported(Boolean): whether the property can be exported. defaults: undefined- if
undefinedthen=enumerable isn't false and the first char isn't "$"
- if
alias(String|ArrayOf String): add the alias(es) to the property. It used via assignment from options.clone(Boolean): Whether clone default property value if the value is an object when initializing. defaults to true.skipDefault(Boolean): Whether to skip default values when exporting. defaults to true.
'$attributes': {
'attrName': {
name: 'exportedName',
value: 123,
enumerable: false,
type: 'String',
configurable: true,
writable: true,
assign: function(value, dest, src, name)
get: ...,
set: ....
}
}these methods will be added(replaced):
initialize(options): overwrite this for assign options from constructor?- apply the initialized value of the properties to the object if possible.
- then call
assignmethod.
assign(options): assign the options' attributes to this object.- how to decide which attribute should be assign?
- I need an attributes manage class? or just a simple attributes list?
- or define all attributes even the value is null when initialize
- this must be an optional feature.
assignPropertyTo(dest, options, attributeName, value): assign an attribute to dest.- you can override it to determine howto assign an object value.
assignProperty(options, attributeName, value): assign an atrribute. called byassign
assignTo(dest): assign the attributes to thisdestobject.mergeTo(dest): merge the attributes itself todestobject.- do not overwrite the already exist attributes of the
dest.
- do not overwrite the already exist attributes of the
isSame(obj): compare theobj's attributes whether is the same value with itself.clone(options): create a new object with the same attributes' value.toObject(options): convert it as plain object.- do not export the non-enumerable attributes or beginning with '$'
- do not export the attribute's value is null
- do not export the attribute's value is default value.
- where to get the default value?
toJSON(): this will call thetoObject()to return.
Note: you should specify the position of the argument if the first argument is not the options
there are three ways to make your class manage the attributes.
- Class inherits from
- inherits from PropertyManager directly.
- Ability to hook on any class
- You need confirm these method names are not be used.
The
$attributesis used via normal and advance PropertyManager. thenonExported1stCharis used to change the first char of non-exported property, defaults to '$'. It must be exist. The first four methods must be exist. others are optional. But be care of their dependencies.- $attributes (unless use simple PropertyManager)
- nonExported1stChar
- assign
- assignPropertyTo
- getProperties
- defineProperties
- clone (optional)
- mergeTo
- initialize (optional)
- getProperties
- assign
- assignProperty (optional)
- assignPropertyTo
- mergeTo (optional)
- getProperties
- assignPropertyTo
- exportTo (optional)
- mergeTo
- assignTo (optional)
- getProperties
- assignPropertyTo
- toObject (optional)
- exportTo
- toJSON (optional)
- toObject
- isSame (optional)
- mergeTo
- You need confirm these method names are not be used.
The
- Decorator: property-manager-decorator
there are three PropertyManager class to use, the default is NormalPropertyManager.
// var inherits = require('inherits-ex/lib/inherits');
// var PropertyManager = require('property-manager');
// var PropertyManager = require('property-manager/lib/normal');
// var SimplePropertyManager = require('property-manager/lib/simple');
// var AdvancePropertyManager = require('property-manager/lib/advance');
import {inherits} from 'inherits-ex'
import {SimplePropertyManager, NormaPropertyManager, AdvancePropertyManager} from 'property-manager'
const ProperManager = NormaPropertyManager
//# Only for Normal or Advance PropertyManager
var defineProperties = ProperManager.defineProperties
class MyClass extends ProperManager {
constructor(name, options) {
super()
this.name = name
// if you use the SimplePropertyManager
// you should define your properties here:
//this.defineProperties({
// 'attr1': {value:123}
// 'hidden': {value:1, enumerable: false},
// '$dontExport': {value:3, enumerable: true}
//})
// initialize ProperManager
this.initialize(options)
}
}
/*
function MyClass(name, options) {
this.name = name;
// if you use the SimplePropertyManager
// you should define your properties here:
//this.defineProperties({
// 'attr1': {value:123}
// 'hidden': {value:1, enumerable: false},
// '$dontExport': {value:3, enumerable: true}
//})
PropertyManager.call(this, options);
}
inherits(MyClass, PropertyManager);
*/
// Only for normal and advance property manager
defineProperties(MyClass, {
'attr1': {value:123},
'hidden': {value:1, enumerable: false},
'$dontExport': {value:3, enumerable: true},
'custom': {
value: {},
assign: function(value, dest, src, name) {
if (value == null) {
value = {};
}
value.exta = 123;
return value;
}
}
});
/*
function MyClassEx() {
MyClassEx.__super__.constructor.apply(this, arguments)
}
inherits(MyClassEx, MyClass);
*/
class MyClassEx extends MyClass {}
// Inherited properties from MyClass
defineProperties(MyClassEx, {'extra': {value: 'extra'}});Inject PropertyManger ability into any class via the PropertyAbility function.
PropertyAbility(target:Function|Object, options?) If there is no parameter then it is the default normal property manager.
options:
name:{'simple' | 'advance' | 'normal' | 'abstract'}Selected PropertyManger, defaultnormaloptionsPosition:{number}, optional attribute option parameter position, used when the constructor needs to import Json object attributes.exclude:{string[]}A list of attribute capability method names that do not need to be injected, the default is empty.
// var PropertyAbility = require('property-manager/ability');
import {PropertyAbility} from 'property-manager'
class MyClass {
constructor(name, options) {
// if you use the SimplePropertyManager
// you should define your properties here:
//this.defineProperties({
// 'attr1': {value:123}
// 'hidden': {value:1, enumerable: false},
// '$dontExport': {value:3, enumerable: false}
//})
this.name = name;
// initialize PropertyManager
this.initialize.apply(this, arguments);
}
}
/*
function MyClass(name, options) {
// if you use the SimplePropertyManager
// you should define your properties here:
//this.defineProperties({
// 'attr1': {value:123}
// 'hidden': {value:1, enumerable: false},
// '$dontExport': {value:3, enumerable: false}
//})
this.name = name;
this.initialize.apply(this, arguments);
}
*/
// add the property manager ability to MyClass
// the default is normal property manager
// PropertyAbility(MyClass)
// you can specified the property manager 'simple', 'advance', 'normal':
// PropertyAbility(MyClass, 'simple')
// PropertyAbility(MyClass, {name: 'simple'})
// and you can specified the options position in the arguments
// the first argument(arguments[0]) is `name`, and the second(arguments[1]) is the options
PropertyAbility(MyClass, {optionsPosition: 1});
// you can exclude some non-core methods:
//PropertyAbility(MyClass, {optionsPosition:1, exclude: ['assignTo', ...]})
// You can define your properties here to:
var defineProperties = MyClass.defineProperties;
//only for normal, advance property manager
defineProperties(MyClass, {
'attr1': {value: 123},
'hidden': {value: 1, enumerable: false},
'$dontExport': {value: 3, enumerable: true},
'date': {
assign(value, dest, src, name, {isExported}) {
let result;
if (isExported) {
result = value.toISOString()
} else if (!(value instanceof Date)) {
result = new Date(value)
}
return result;
}
},
'custom': {
value: {},
assign: function(value, dest, src, name, opts) {
if (value == null) {
value = {};
}
value.exta = 123;
return value;
}
}
});
class MyClassEx extends MyClass {}
/*
function MyClassEx() {
MyClassEx.__super__.constructor.apply(this, arguments)
}
inherits(MyClassEx, MyClass);
*/
// Inherited properties from MyClass
defineProperties(MyClassEx, {'extra': {value: 'extra'}});It's very simple, and it is no different from the use of ordinary object properties. Defining properties is also similar to Object.defineProperties.
Now the MyClass class should have these attributes:
attr1: can be exported and assignedhidden: can not be exported and assigned$dontExport: can be assigned, can not be exported.date: can be exported and assignedcustom: can be exported and assigned, the value be changed byassignfunction in the property descriptor.
the MyClassEx inherits from MyClass (NOTE: only for normal or advance property manager)
extra: can be exported and assigned.- others inherited from
MyClass
var assert = require('assert');
var my = new MyClass('aName', {
attr1: 3,
hidden: 11222,
$dontExport: 1,
custom: {
b: 12
}
});
assert.deepEqual(my.mergeTo(), {
attr1: 3,
$dontExport: 1,
custom: {
b: 12,
exta: 123
}
});
// the `hidden` can not be assigned and exported
assert.equal(my.hidden, 1);
// the `$dontExport` can not be exported
assert.deepEqual(my.toObject(), {
attr1: 3
});
assert.equal(JSON.stringify(my), '{"attr1":3,"custom":{"b":12,"exta":123}}');
var obj = my.clone();
// compare each assigned properties.
assert.ok(obj.isSame(my));
assert.deepEqual(obj.mergeTo(), {
attr1: 3,
$dontExport: 1,
custom: {
b: 12,
exta: 123
}
});
var myEx = new MyClassEx('theClassEx', {attr1: 3, hidden:11222, $dontExport: 1, custom:{b:12}})
assert.deepEqual(myEx.mergeTo(), {extra:'extra', attr1:3, $dontExport:1, custom:{b:12, exta: 123}})Beyond basic property management, property-manager also supports more complex scenarios, such as handling arrays with specific element types or automatically converting plain objects into class instances. This is extremely useful for building structured, type-safe data models.
When you need an array property and want to ensure that all elements within that array are instances of a specific class, you can use the arrayOf helper function.
arrayOf(Type) creates a special array that automatically converts new elements (if they are plain objects) into instances of Type upon being added.
Example:
import { AdvancePropertyManager, defineProperties } from 'property-manager';
import { arrayOf } from 'property-manager/lib/array';
// Define a Phone class
class Phone extends AdvancePropertyManager { /* ... */ }
defineProperties(Phone, { number: { type: String } });
// Define a Contact class with an array of phones
class Contact extends AdvancePropertyManager { /* ... */ }
defineProperties(Contact, {
name: { type: String },
phones: { type: arrayOf(Phone) } // Each element in phones will be an instance of Phone
});
const contact = new Contact({
name: 'John',
phones: [
{ number: '123-456-7890' }, // This is a plain object
{ number: '098-765-4321' } // This is also a plain object
]
});
// Verify the automatic conversion
// contact.phones[0] is now an instance of the Phone class, not a plain object
console.log(contact.phones[0] instanceof Phone); // Outputs: trueIf a property of an object is itself another complex object (also managed by property-manager), you simply need to specify its corresponding class in the type definition. property-manager will automatically handle the conversion from a plain object to a class instance upon assignment.
This makes building nested data models simple and intuitive.
Example:
import { AdvancePropertyManager, defineProperties } from 'property-manager';
// 1. Define the inner Address class
class Address extends AdvancePropertyManager { /* ... */ }
defineProperties(Address, {
street: { type: String },
city: { type: String }
});
// 2. Define the outer Person class
class Person extends AdvancePropertyManager { /* ... */ }
// 3. In Person's properties, use the Address class directly as the type
defineProperties(Person, {
name: { type: String },
address: { type: Address } // <-- The key is here
});
// 4. Instantiate with a nested plain object
const person = new Person({
name: 'John Doe',
address: {
street: '123 Main St',
city: 'Anytown'
}
});
// 5. Verify the automatic conversion
// person.address is now an instance of the Address class
console.log(person.address instanceof Address); // Outputs: true
console.log(person.address.city); // Outputs: AnytownThe toJsonSchema helper function converts properties defined in a PropertyManager instance into a JSON Schema. This is particularly useful for generating schema definitions for data validation, API documentation, or form generation based on your PropertyManager models.
Usage
import { AdvancePropertyManager, defineProperties } from 'property-manager';
import { toJsonSchema } from 'property-manager/lib/to-json-schema';
class MyDataModel extends AdvancePropertyManager { }
defineProperties(MyDataModel, {
id: { type: Number, value: 0 },
name: { type: String, value: '' },
isActive: { type: Boolean, value: true },
tags: { type: Array, value: [], itemType: String },
address: {
type: Object,
properties: {
street: { type: String },
city: { type: String }
}
}
});
const schema = toJsonSchema(MyDataModel);
console.log(JSON.stringify(schema, null, 2));
/*
Output:
{
"type": "object",
"properties": {
"id": {
"type": "number",
"default": 0
},
"name": {
"type": "string",
"default": ""
},
"isActive": {
"type": "boolean",
"default": true
},
"tags": {
"type": "array",
"default": [],
"items": {
"type": "string"
}
},
"address": {
"type": "object",
"properties": {
"street": {
"type": "string"
},
"city": {
"type": "string"
}
}
}
}
}
*/Parameters
toJsonSchema(target: Function | Object)
target: ThePropertyManagerclass or instance for which to generate the JSON Schema.
Return Value
object- A JSON Schema object representing the properties defined in thePropertyManagerinstance.
The toUISchema helper function converts properties defined in a PropertyManager instance or class into a uiSchema object for React JSON Schema Form (RJSF). This is useful for controlling the UI appearance of form fields, such as making a field read-only or using a specific widget.
Usage
import { AdvancePropertyManager, defineProperties } from 'property-manager';
import { toUISchema } from 'property-manager/lib/to-ui-schema';
class MyFormModel extends AdvancePropertyManager { }
defineProperties(MyFormModel, {
id: { type: Number, writable: false }, // Read-only field
name: { type: String, value: '', 'ui:placeholder': 'Enter name' }, // Custom UI attribute
bio: { type: String, value: '', 'ui:widget': 'textarea' },
nested: {
type: Object,
properties: {
field1: { type: String, 'ui:title': 'Field One' }
}
}
});
const uiSchema = toUISchema(MyFormModel);
console.log(JSON.stringify(uiSchema, null, 2));
/*
Output:
{
"id": {
"ui:readonly": true
},
"name": {
"ui:placeholder": "Enter name"
},
"bio": {
"ui:widget": "textarea"
},
"nested": {
"field1": {
"ui:title": "Field One"
}
}
}
*/Parameters
toUISchema(target: Function | Object)target: ThePropertyManagerclass or instance for which to generate theuiSchema.
Return Value
object- An RJSFuiSchemaobject.
The toRjsf helper function is a convenient utility that converts a PropertyManager instance into both a JSON Schema and a UI Schema, which is the format required by React JSON Schema Form (RJSF).
Usage
import { AdvancePropertyManager, defineProperties } from 'property-manager';
import { toRjsf } from 'property-manager/lib/to-rjsf';
class MyDataModel extends AdvancePropertyManager { }
defineProperties(MyDataModel, {
name: { type: String, value: '' },
isActive: { type: Boolean, value: true, writable: false }
});
const { schema, uiSchema } = toRjsf(MyDataModel);
console.log('--- Schema ---');
console.log(JSON.stringify(schema, null, 2));
console.log('\n--- UI Schema ---');
console.log(JSON.stringify(uiSchema, null, 2));
/*
Output:
--- Schema ---
{
"type": "object",
"properties": {
"name": {
"type": "string",
"default": ""
},
"isActive": {
"type": "boolean",
"default": true
}
}
}
--- UI Schema ---
{
"isActive": {
"ui:readonly": true
}
}
*/Parameters
toRjsf(target: Function | Object)target: ThePropertyManagerclass or instance to convert.
Return Value
{schema: object, uiSchema: object}- An object containing both theschemaanduiSchema.
More recent changes see: CHANGELOG.md
- ES6 Class
- ESM support
- NodeJS >= 8
- feat: add the readonly to smart assigned property
@Properties
class Phone extends AdvancePropertyManager {
@Prop({
writable: false,
exported: true,
assigned: '',
}) id!: string;
}- BROKEN CHANGE: DO NOT EXPORT the readonly property by default unless exported is true.
@Properties
class Phone extends AdvancePropertyManager {
@Prop({
writable: false,
exported: true,
}) id!: string;
}- add the array with type supports.
import { arrayOf } from 'property-manager/lib/array';
import AdvancePropertyManager from 'property-manager/lib/advance';
import { PropertyManager as Properties, Property as Prop } from 'property-manager-decorator';
@Properties
class Phone extends AdvancePropertyManager {
@Prop() value!: string;
@Prop() codeNum!: string;
@Prop() kind!: string;
constructor(initValue?) {
super(initValue);
}
}
@Properties
class Contact extends AdvancePropertyManager {
@Prop({type: String}) name!: string;
@Prop({type: arrayOf(Phone)}) phones!: Phone[];
constructor(initValue?) {
super(initValue);
}
}- BROKEN change
toObjectmethod params to(options?: IMergeOptions) - BROKEN change
assignmethod params to(src, options?: IMergeOptions) - BROKEN change
assignTomethod params to(dest, options?: IMergeOptions) - BROKEN change
assignPropertyToandassignPropertymethod params to(dest, src, name: string, value, attrs?, options?: IMergeOptions) - BROKEN change
exportTomethod params to(dest, options?: IExportOptions) - BROKEN change
mergeTomethod params to(dest, options?: IMergeOptions)- add
skipNullandskipUndefinedoption toIExportOptionsandIMergeOptions
- add
- add the
extends(attrs: Object, nonExported1stChar)method to theProperties- return a new
Propertiesinstance to extends properties from current instance.
- return a new
- add the inherited properties supports for
AdvancePropertyManager.defineProperties
- change the
recreateargument default value ofdefinePropertiestofalseforAdvancePropertyManagerandNormalPropertyManager - set all methods and non-properties of
Propertiesto be non-enumerable.
- add typed property for
AdvancePropertyManagerandNormalPropertyManager
function CustomType(value) {
if (!(this instanceof CustomType)) return new CustomType(value)
try {
value = JSON.parse(value)
} catch(err) {
this.value = value
}
}
const attrs = {
prop1: {type: CustomType, value: 111}
}
class TypedPM extends AdvancePropertyManager {
constructor(opts) {
super(opts)
}
}
TypedPM.defineProperties(attrs)
const obj = new TypedPM()
console.log(obj.prop1 instanceof CustomType)- add the
skipExistsoption to theProperties.assignToandProperties.assignPropertyTo
- the options to the
Properties.assignTo(dest, src, options)exclude(String|Array)skipDefault(Boolean)skipExists(Boolean)skipReadOnly(Boolean)exported(Boolean)
- add the alias property descriptor(Normal&Advance):
- You can define one or more aliases to assign from other object(options)
alias(String|ArrayOf String)
- Smart assignment property supports(AdvancePropertyManager):
- broken: SMART_ASSIGN constant deprecated.
assigneddescriptor (Boolean|String):Stringmeans SMART_ASSIGN.- it's the internal property name of the smart assignment if it's string
- the internal property name is the property name with prefix(
nonExported1stChar) if it's an empty string
- broken: remove
attrsNameproperty(fixed to '$attributes')
- add the helper function: properties/define-properties.
- clone default property value if the value is an object when initializing
- the object instances will share the same one of property value if the default value of property is an object.
- howto create a new object instance when initializing default value.
- Solution 1: the
valuedescriptor could be a function to create new object instance:- Problem1: it will be only available for normal and advance property manager
value: function (){return Object.create()}
- Problem2: the value can not be a function now.
- Problem1: it will be only available for normal and advance property manager
- Solution 2: check the value whether is object. if so, clone it when initializing.
- use this solution. but if someone wish all instance share the same value.
- add a descriptor to control whethe enable this. but simple can not support the custom descriptor.
clone(Boolean): defaults to true.
- the object instances will share the same one of property value if the default value of property is an object.
- Smart assignment property supports:
- assign property descriptor (Function(value, dest, src, name)):
- It only used to assign the options from another object.
- It's no effect if the assign the property individually. should use the property descriptor
setto do so. - maybe I should wrap it:
- add a hidden internal property with prefix(
nonExported1stChar) - add descriptor
getfunction to read the property - add descriptor
setfunction to assign the property(call theassigndescriptor).
- add a hidden internal property with prefix(
- need a descriptor to control whethe enable this.
assigned: AdvancePropertyManager::SMART_ASSIGN = 2
- enabled:
!get and !set and assigned is AdvancePropertyManager::SMART_ASSIGN
- only available for advance property manager.
- note: only
valueargument is passed intoassigndescriptor when assignment the property individually.
- assign property descriptor (Function(value, dest, src, name)):
- add the property writable check: do not assign the readonly property.
- Normal, Advance
- add the
assigned,exported(Boolean) to property descriptor directly.assigned: enumerable isnt false and (writable isnt false or isFunction(set)).exported: enumerable isnt false and the first char isnt "$"
- add the
PropertyManager::nonExported1stChar(Char), defaults to '$'- note: the
exporteddescriptor is higher prior thannonExported1stChar.
- note: the
nonExported1stCharoption to the property manager ability.
- broken the arguments order of assign function in property descriptor are changed:
- attr.assign(value, dest, src, name, opts) instead of assign(dest, src, value, name)
MIT