configuration
v4.1.5
Published
Performant and feature rich library for managing configurations/settings.
Downloads
633
Maintainers
Readme
Configuration
Performant and feature rich library for managing configurations/settings.
Features
This library has been modeled after VSCode's settings system, and it can be used for implementing a similarly powerful system in your app.
- Performant: it's designed to be extremely fast.
- Providers: a provider reads and writes the actual data, many are built-in (memory, json, local storage etc.) and others can be written easily.
- Universal: it works in the browser too, just use a suitable provider.
- Scopes: a single configuration instance can have multiple providers, so for example a
global + local
setup can be implemented easily. - Filtering: an arbitrary filter function can be provided, for example to make sure the settings are filtered by a schema.
- Path props: path props (e.g.
foo.bar
) are supported for retrieving/setting/deleting entries. - Flat objects: flat objects (e.g.
{ 'foo.bar': true, 'foo.baz': false }
) are supported transparently too.
Install
npm install --save configuration
Usage
The following providers are built-in:
import ProviderAbstract from 'configuration/abstract'; // The most basic abstract provider
import ProviderAbstractFile from 'configuration/abstract-file'; // The most basic abstract file provider
import ProviderAbstractJSON from 'configuration/abstract-json'; // The most basic abstract JSON-backed file provider
import ProviderFile from 'configuration/file'; // A provider that reads/writes to a file
import ProviderJSON from 'configuration/json'; // A provider that reads/writes to a JSON file
import ProviderMemory from 'configuration/memory'; // A provider that reads/writes to memory
import ProviderStorage from 'configuration/storage'; // A provider that reads/writes to a general web storage object
import ProviderLocalStorage from 'configuration/local-storage'; // A provider that reads/writes to localStorage
import ProviderSessionStorage from 'configuration/session-storage'; // A provider that reads/writes to sessionStorage
This is how you'd create a multi-tier settings sytem:
import Configuration from 'configuration';
import ProviderMemory from 'configuration/memory';
import ProviderJSON from 'configuration/json';
// Let's initiate the configuration instance
const Window = new ProviderMemory ({ // A window-level tier, that overrides every other tier
scope: 'window', // The name of the scope for this provider
defaults: {}, // The default settings object for this provider
defaultsRaw: '{\n\t// Write window-level settings here\n}' // The default settings object for this provider as a string
});
const Local = new ProviderJSON ({ // A local-level tier, that overrides every other tier except for "window"
scope: 'local', // The name of the scope for this provider
path: './myapp/local.json', // Path where to persist data
watching: true, // Whether to watch the file for changes too or not
defaults: {}, // The default settings object for this provider
defaultsRaw: '{\n\t// Write local-level settings here\n}' // The default settings object for this provider as a string
});
const Global = new ProviderJSON ({ // A global-level tier, that overrides only the "defaults" tier
scope: 'global', // The name of the scope for this provider
path: '/Users/fabio/.config/myapp/global.json', // Path where to persist data
watching: true, // Whether to watch the file for changes too or not
defaults: {}, // The default settings object for this provider
defaultsRaw: '{\n\t// Write global-level settings here\n}' // The default settings object for this provider as a string
});
const configuration = new Configuration ({
providers: [Window, Local, Global], // List of custom providers used, ordered by priority
defaults: { // The default settings object for the implicit "defaults" scope
some: {
default: {
settings: true
}
}
},
filter: settings => { // Custom optional function for manipulating the raw settings object
// Optionally filter down the passed "settings" object...
return settings;
}
});
// Using the #get method
configuration.get (); // Get the entire merged object
configuration.get ( '*' ); // Get the entire object for each scope
configuration.get ( '*', 'some.path' ); // Get the value at "some.path" for all scopes
configuration.get ( 'local', 'some.path' ); // Get the value at "some.path" from the "local" scope
configuration.get ( 'some.path' ); // Get the value at "some.path" from the first scope that has a value for it
// Using the #has method
configuration.has ( '*', 'some.path' ); // Check if a value exists at "some.path" in all scopes
configuration.has ( 'local', 'some.path' ); // Check if a value exists at "some.path" in the "local" scope
configuration.has ( 'some.path' ); // Check if a value exists at "some.path" in at least one scope
// Using the #remove method
configuration.remove ( '*', 'some.path' ); // Remove the "some.path" key from all scopes
configuration.remove ( 'local', 'some.path' ); // Remove the "some.path" key from the "local" scope
configuration.remove ( 'some.path' ); // Remove the "some.path" key from any scope that has a value for it
// Using the #reset method
configuration.reset (); // Reset the value of every scope to its default one
configuration.reset ( 'local' ); // Reset the value of the "local" scope
// Using the #set method
configuration.set ( '*', 'some.path', 123 ); // Set "123" as the value at "some.path" for every scope
configuration.set ( 'local', 'some.path', 123 ); // Set "123" as the value at "some.path" for the "local" scope
configuration.set ( 'some.path', 123 ); // Set "123" as the value at "some.path" in the first scope that has a value for that key
// Using the #update method
configuration.update ( '*', { something: {} } ); // Replacing the entire settings object for every scope
configuration.update ( 'local', { something: {} } ); // Replacing the entire settings object for the "local" scope
// Listening for changes
configuration.onChange ( () => {
// Something changed anywhere in the object, but we don't know exactly where, but this makes this callback the cheapest
});
configuration.onChange ( 'local', 'some.path', ( value, valuePrev ) => {
// The value of "some.path" in the "local" scope changed
});
configuration.onChange ( 'some.path', ( value, valuePrev ) => {
// The value of "some.path" in the first scope that provides a value for it changed
});
// Let's dispose of the configuration object, stopping filesystem watching for example
configuration.dispose ();
License
MIT © Fabio Spampinato