preface
Yeoman/ConfigStore is a very useful and powerful tool for configuring storage in Yeoman. The core idea is to create a file in the current system based on the established file naming rules to store user configuration data. The configuration can be modified and saved by reading and writing files.
use
-
Create a new Node project and install the dependencies.
npm install configstore Copy the code
-
Set type in package.json to module.
-
Create test_configstore.js and execute. Test_configstore.js looks like this:
import Configstore from "configstore"; import fs from "fs"; const packageJson = JSON.parse(fs.readFileSync("./package.json"."utf8")); // Create a Configstore instance. const config = new Configstore(packageJson.name, { foo: "bar" }); console.log(config.get("foo")); //=> 'bar' config.set("awesome".true); console.log(config.get("awesome")); //=> true // Use dot-notation to access nested properties. config.set("bar.baz".true); console.log(config.get("bar")); //=> {baz: true} config.delete("awesome"); console.log(config.get("awesome")); Copy the code
-
Run the test_configstore.js file.
Rely on the analysis of
Learn about the NPM package that ConfigStore relies on.
- path
Node has built-in modules for manipulating files and directories.
- os
Node has a built-in module that provides operating system-specific methods and properties.
- graceful-fs
An upgraded version of fs module, compatible with different platforms and environments. In the file read and write this piece, is superior to the native FS module.
- xdg-basedir
On Linux, obtain the user’s configuration file path. For example: ‘/usr/share’ – a directory for storing shared data, etc.
- write-file-atomic
Fs.writefile extension module for file writing and support for setting the UID/GID of a file.
Uid indicates the file operation permission of a user, GID indicates the file operation permission of the user group.
- dotProp
Supports multi-level nesting of objects, through ‘.’ access and manipulation of object properties.
- unique-string
Generates a random 32-bit length string.
Front variable
/** * 1. ConfigDirectory: stores temporary files for the current operating system. Linux Obtained from the xdgConfig package. * Other operating systems get os.tmpdir(), followed by a concatenated 32-bit string. * eg: 'C:\\Users\\userName\\AppData\\Local\\Tempb4de2a49c8ffa3fbee04446f045483b2' * 2. permissionError: MkdirOptions: Folder creation configuration, mode represents Linux directory permissions, and recursive means recursive creation * mode: 0O0700: indicates that the owner has read, write, and execute permissions * 4. WriteFileOptions: indicates write file configuration. * /
const configDirectory = xdgConfig || path.join(os.tmpdir(), uniqueString());
const permissionError = "You don't have access to this file.";
const mkdirOptions = { mode: 0o0700.recursive: true };
const writeFileOptions = { mode: 0o0600 };
Copy the code
The core code
/** * 5. Configstore class declaration, using ES modules syntax to export */
export default class Configstore {
/** * 6. Constructor, used to create Configstore instance *@param {*} The id is used to name the configStore storage file *@param {*} Defaults stores data by default, such as an object *@param {*} Options Stores configuration */
constructor(id, defaults, options = {}) {
/** * 7. PathPrefix: the path name of the stored file. * If globalConfigPath is set, the name is id/config.json. * Otherwise: configStore /id.json */
const pathPrefix = options.globalConfigPath
? path.join(id, "config.json")
: path.join("configstore".`${id}.json`);
/** * 8._path: indicates the full path for storing files in the operating system. * options.configPath: indicates the full path to be defined by the user. * Or the system temporary storage path/storage file path. * /
this._path = options.configPath || path.join(configDirectory, pathPrefix);
/** * 9._all: Stores the storage data of the current ConfigStore instance in object format. * /
if (defaults) {
this.all = { ... defaults, ... this.all, }; }}/** * 10. Read the file storing the object in UTF-8 encoding */
get all() {
try {
return JSON.parse(fs.readFileSync(this._path, "utf8"));
} catch (error) {
// Create directory if it doesn't exist
// File does not exist, return empty object
if (error.code === "ENOENT") {
return {};
}
// Improve the message of permission errors
// File permissions are limited
if (error.code === "EACCES") {
error.message = `${error.message}\n${permissionError}\n`;
}
// Empty the file if it encounters invalid JSON
if (error.name === "SyntaxError") {
writeFileAtomic.sync(this._path, "", writeFileOptions);
return {};
}
throwerror; }}/** * 11. Storage data is written, which is equivalent to overwriting */
set all(value) {
try {
// Make sure the folder exists as it could have been deleted in the meantime
fs.mkdirSync(path.dirname(this._path), mkdirOptions);
writeFileAtomic.sync(
this._path,
JSON.stringify(value, undefined."\t"),
writeFileOptions
);
} catch (error) {
// Improve the message of permission errors
if (error.code === "EACCES") {
error.message = `${error.message}\n${permissionError}\n`;
}
throwerror; }}/** * 12. Get the number of stored data (JSON object) attributes */
get size() {
return Object.keys(this.all || {}).length;
}
/** * 13. Retrieve stored data by key name (essentially object property access, additional support for nested object property access) *@param {*} key
* @returns* /
get(key) {
return dotProp.get(this.all, key);
}
/** * 14. Assign a key-value to the data object attribute *@param {*} key
* @param {*} value* /
set(key, value) {
const config = this.all;
if (arguments.length === 1) {
for (const k of Object.keys(key)) { dotProp.set(config, k, key[k]); }}else {
dotProp.set(config, key, value);
}
this.all = config;
}
/** * 15. Check whether an attribute * exists in the data@param {*} key
* @returns* /
has(key) {
return dotProp.has(this.all, key);
}
/** * 16. Delete the attribute * of the specified key@param {*} key* /
delete(key) {
const config = this.all;
dotProp.delete(config, key);
this.all = config;
}
/** * 17. Clear the current stored data */
clear() {
this.all = {};
}
/** * 18. Obtain the full path of the current data store file */
get path() {
return this._path;
}
Copy the code
conclusion
When developing JS library, the part involving file operation needs to take into account the circumstances of different systems and platforms. Configstore is a good idea to follow.