1.1.1 • Published 4 years ago

json-file-handler v1.1.1

Weekly downloads
1
License
MIT
Repository
github
Last release
4 years ago

JSON File Handler

CI/CD workflow status codecov npm version Commitizen friendly

Create or manipulate JSON files with asynchronous read, write, merge (two files into a third) and join (an object into a file) operations.

Table of Contents

Installation

npm install --save json-file-handler

Usage

Import the functions that you need to use, you can do so using require:

const JSONFileHandler = require('json-file-handler');
const path = require('path');

const settingsFilePath = path.resolve(__dirname, '../config/settings.json');
JSONFileHandler.read(settingsFilePath)
  .then((settings) => {
    // settings processing...
  })
  .catch((error) => {
    // error handling...
  });

or ES6 import (if you are using TypeScript, you need to compile your project with --esModuleInterop flag for it to work):

import { join as joinJSON } from 'json-file-handler';
const path = require('path');

const updateSettingsFile = async (settingsFilePath, newSettings) => {
  try {
    const absoluteSettingsFilePath = path.resolve(__dirname, settingsFilePath);
    const fileIndentation = 4;
    await joinJSON(absoluteSettingsFilePath, newSettings, fileIndentation);
  } catch (error) {
    // error handling...
  }
};

Things to know

All the functions that this library makes available expect an absolute file path. You can use a relative file path, but it will be relative to the current working directory of the NodeJS process (process.cwd()). Instead, you need to create an absolute file path from a relative path using path.resolve() like this:

const path = require('path');

const relativeFilePath = '../config/settings.json';
const absoluteFilePath = path.resolve(__dirname, relativeFilePath);

Writing functions (overwrite, merge and join) asks for an optional indentationLevel parameter, whose value determines how much space is used for indentation when the file is formatted. JSON.stringify is responsible for the formatting, so a value less than 1 indicates that no formatting is applied, and a value greater than 10 is ignored.

Error Handling

When the functions fails they return a rejected promise with an error that can either be an instance of JSONFileHandlerError, if the error was caused by a misuse of the library, or of Error (actually is of SystemError, but Node doesn't exposes the class so it can't be checked using instanceof operator), if it was caused by violating an operating system constraint, like reading a file that doesn't exist, or trying to write to a read-only file.

Both types of errors contain the properties path (useful when you want to know which file caused the error when you are merging two files or iterating) and code, that can be used to handle them. Bellow are the error codes that should be checked for each function, classified by kind:

  • read
    • JSONFileHandlerError
      • 'EMPTY_FILE'
      • 'NOT_A_JSON'
    • SystemError
      • 'ENOENT'
      • 'EPERM'
      • 'EMFILE'
      • 'EISDIR'
  • overwrite
    • JSONFileHandlerError
      • 'NOT_A_VALID_OBJECT'
    • SystemError
      • 'EPERM'
      • 'EMFILE'
      • 'EISDIR'
  • join
    • JSONFileHandlerError
      • 'NOT_A_JSON'
      • 'NOT_A_VALID_OBJECT'
    • SystemError
      • 'EPERM'
      • 'EMFILE'
      • 'EISDIR'
  • merge
    • JSONFileHandlerError
      • 'EMPTY_FILE'
      • 'NOT_A_JSON'
    • SystemError
      • 'ENOENT'
      • 'EPERM'
      • 'EMFILE'
      • 'EISDIR'

The error codes of JSONFileHandlerError are self explanatory, a more detailed explanation of SystemError error codes can be found inside Node documentation. Also in the examples section.

Examples

Functions can be used with async/await or promises. read example uses promises while join and merge examples use async/await.

Read

import { read as readJSON } from 'json-file-handler';

const path = require('path');

const settingsFilePath = path.resolve(__dirname, '../config/settings.json');
readJSON(settingsFilePath)
  .then((settings) => {
    // settings processing...
  })
  .catch((error) => {
    switch (error.code) {
      case 'EMPTY_FILE':
        // The file is empty
        break;
      case 'NOT_A_JSON':
        // The content of the file can't be read as JSON
        break;
      case 'ENOENT':
        // The file you are trying to read doesn't exist
        break;
      case 'EPERM':
        // The file requires elevated privileges to be read
        break;
      case 'EMFILE':
        // There are too many open file descriptors, so the file can't be read
        // at this time
        break;
      case 'EISDIR':
        // The given path is the path of an existing directory
        break;
    }
  });

Overwrite

import { overwrite as overwriteJSON } from 'json-file-handler';
import { defaultSettings, settingsFilePath } from '@constants/settings';

const resetSettingsFile = async (settingsFilePath) => {
  try {
    await overwriteJSON(settingsFilePath, defaultSettings);
  } catch (error) {
    switch (error.code) {
      case 'NOT_A_VALID_OBJECT':
        // The object to be joined is not an object (it's a function, an array,
        // null or undefined)
        break;
      case 'EPERM':
        // The file requires elevated privileges to be written
        break;
      case 'EMFILE':
        // There are too many open file descriptors, so the file can't be
        // written at this time
        break;
      case 'EISDIR':
        // The given path is the path of an existing directory
        break;
    }
  }
};

resetSettingsFile(settingsFilePath);

Join

import { join as joinJSON } from 'json-file-handler';

const path = require('path');

const updateSettingsFile = async (settingsFilePath, newSettings) => {
  try {
    const fileIndentation = 4;
    await joinJSON(settingsFilePath, newSettings, fileIndentation);
  } catch (error) {
    switch (error.code) {
      case 'NOT_A_JSON':
        // The content of the file can't be read as JSON
        break;
      case 'NOT_A_VALID_OBJECT':
        // The object to be joined is not an object (it's a function, an array,
        // null or undefined)
        break;
      case 'EPERM':
        // The file requires elevated privileges to be written
        break;
      case 'EMFILE':
        // There are too many open file descriptors, so the file can't be
        // written at this time
        break;
      case 'EISDIR':
        // The given path is the path of an existing directory
        break;
    }
  }
};

const settingsFilePath = path.resolve(__dirname, '../config/settings.json');
const newSettings = {
  resX: 1920,
  rexY: 1080,
  theme: 'light',
  preferredView: 'list',
};
updateSettingsFile(settingsFilePath, newSettings);

Merge

import { merge as mergeJSON } from 'json-file-handler';

const path = require('path');

const mergeCustomSettingsFileIntoSettingsFile = async (
  settingsFilePath,
  customSettingsFilePath
) => {
  try {
    await mergeJSON(
      absoluteSettingsFilePath,
      absoluteCustomSettingsFilePath,
      absoluteSettingsFilePath
    );
  } catch (error) {
    switch (error.code) {
      case 'EMPTY_FILE':
        // Both files are empty
        break;
      case 'NOT_A_JSON':
        // The content of at least one of the two files can't be read as JSON
        break;
      case 'ENOENT':
        // At least one of the two files doesn't exist
        break;
      case 'EPERM':
        // At least one of the files requires elevated privileges to be read or
        // written
        break;
      case 'EMFILE':
        // There are too many open file descriptors, so the file can't be
        // written at this time
        break;
      case 'EISDIR':
        // At least one of the paths is the path of an existing directory
        break;
    }
  }
};

const settingsFilePath = path.resolve(__dirname, '../config/settings.json');
const customSettingsFilePath = path.resolve(
  __dirname,
  '../../custom-settings.json'
);
mergeCustomSettingsFileIntoSettingsFile(
  settingsFilePath,
  customSettingsFilePath
);

API Documentation

API documentation can be read at https://sebastian-altamirano.github.io/json-file-handler/.

FAQ

  • Why can i create and read files with a extension other than .json?

Some configuration files support JSON format without the .json extension, like .prettierrc and .eslintrc, which supports both YAML and JSON format.