The base class of a configuration class for a interfacial class.
Install
npm install class-config-base --save
Usage
-
Load this module.
const ClassConfigBase = require('class-config-base')
-
Define default config object. This object determines the property default values, the property structure and the property data types of the class config class.
const defaultConfig = { a: '', b: { c: 0, d: false } }
-
Define the class config class. defineAccessors
method is optional and creates descriptors to override property accessors. defineInterfaces
method creates descriptors to define properties and methods of the target interfacial class.
class MyClassConfig extends ClassConfigBase {
constructor (initConfig) {
super(initConfig, defaultConfig)
}
defineAccessors () {
return {
'b.c': (parent, key) => ({
enumerable: true,
get () { return parent[key] },
set (v) { parent[key] = Math.max(0, v) },
})
}
}
defineInterfaces () {
return {
myA: (config, myA) => ({
enumerable: true,
set () {},
get () { return config.a },
}),
myC: (config, myC) => ({
enumerable: true,
set (v) { config.b.c = Math.max(v, 0) },
get () { return config.b.c },
}),
myD: (config, myD) => ({
enumerable: true,
configurable: true,
set (value) { Object.defineProperty(this, myD, {
enumerable: true,
configuable: true,
writable: true,
value,
}) },
get () { return config.b.d },
}),
}
}
}
This module prepares some useful functions to define accessors/interfaces simply.
By using these functions, the above example can be rewritten as follows:
const { readonly, writable, replaceable } = ClassConfigBase
class MyClassConfig extends ClassConfigBase {
constructor (initConfig) {
super(initConfig, defaultConfig)
}
defineAccessors () {
return {
'b.c': (parent, key) => writable({
get: () => parent[key],
set: v => { parent[key] = Math.max(0, v) },
})
}
}
defineInterfaces () {
return {
myA: config => readonly({
get: () => config.a,
},
myC: config => writable({
set (v) { config.b.c = Math.max(v, 0) },
get () { return config.b.c },
},
myD: config => replaceable({
get: () => config.b.d,
}
}
}
}
-
Define the interfacial class with the class config.
class MyClass {
constructor (config) {
config.configure(this)
}
}
-
Instantiate and use the interfacial class.
const myCfg = new MyClassConfig({ a: 'Foo', b: { c: 123, d: true } })
const myObj = new MyClass(myCfg)
console.log(myObj.toString())
console.log(Object.prototype.toString.call(myObj))
console.log(myObj.myA)
console.log(myObj.myC)
console.log(myObj.myD)
myObj.myA = 'Bar'
console.log(myObj.myA)
myObj.myC = 999
console.log(myObj.myC)
myObj.myC = -888
console.log(myObj.myC)
myObj.myD = false
console.log(myObj.myD)
myObj.myD = 123
console.log(myObj.myD)
-
A property value, even if it is read-only, can be updated with the class config object.
myCfg.a = 'Buz'
myCfg.b.c = 666
console.log(myObj.myA)
console.log(myObj.myC)
API
constructor(initConfig, defaultConfig)
Constructs a configuration class instance.
initConfig and defaultConfig are plain objects and can be nested objects.
defaultConfig is to specify the default values and the types of the properties.
So if a property in initConfig is different from a corresponding property in defaultConfig, the property value in initConfig is ignored.
Parameters:
- initConfig (object) : a configuration object which has initial property values.
- defaultConfig (object) : a configuration object which has default property values.
defineAccessors() => object
Returns an object which maps between property key chains and functions which return property descriptors.
A key chain concatenates all keys in a key path with dots. A descriptor is a thing used by Object.defineProperty
.
This method is used to override configure accessors of the config class.
Returns:
- (object) An object which maps between property key chains and functions to get property descriptors of the config class.
The format of an entry in the returned object is as follows:
defineAccessors () {
return {
'a.b.c' : function (parent, key) {
return {
enumerable: true,
get () { return parent[key] },
set (v) { parent[key] = v },
}
},
...
}
}
This entry is a function of which the arguments are parent and key.
In the above example, parent equals to .a.b
, and key equals to 'c'
.
defineInterfaces() => object
Returns an object which maps between property names and functions which return property descriptors. A descriptor is a thing used by Object.defineProperty
.
This method defines the interfaces of the target class.
Returns:
- (object) An object which maps between property name and functions to get property descriptors of the target class.
The format of an entry in the returned object is as follows:
defineInterfaces () {
return {
'ccc' : function (config, interfaceName) {
return {
enumerable: true,
get () { return config.a.b.c },
set (v) { config.a.b.c = v },
}
},
...
}
}
This entry is a function of which the arguments are config and interfaceName.
In the above example, interfaceName equals to 'ccc'
.
configure(instance)
Configures the interfaces of the target class instance in its constructor.
Parameters:
- instance (object) : A class instance to be configured.
static readonly({ get, enumerable = true }) => object
Returns a readonly property descriptors.
Parameters:
- get : A getter of this property.
- enumerable: A flag to show this property during enumeration of the properties.
static writable({ get, set, enumerable = true, configurable = false }) => object
Returns a writable property descriptors.
- get : A getter of this property.
- set : A setter of this property.
- enumerable: A flag to show this property during enumeration of the properties.
- configurable: A flag to change or delete this property.
static replaceable({ get, enumerable = true }) => object
Returns a replaceable property descriptors.
Parameters:
- get : A getter of this property.
- enumerable: A flag to show this property during enumeration of the properties.
License
Copyright (C) 2017 Takayuki Sato
This program is free software under MIT License.
See the file LICENSE in this distribution for more details.