Skip to content

Instantly share code, notes, and snippets.

@Silverwolf90
Created June 16, 2021 19:20
Show Gist options
  • Save Silverwolf90/bd769950f074a214289975566fd61c3d to your computer and use it in GitHub Desktop.
Save Silverwolf90/bd769950f074a214289975566fd61c3d to your computer and use it in GitHub Desktop.
guardAccessOfEmptyValues
const DeepProxy = require('proxy-deep');
const { isSymbol, isPlainObject } = require('lodash');
// Empty values trigger access errors
const isEmptyValue = (value) => (
value === undefined ||
value === ''
);
// Check whether the value should be returned
const shouldReturnRawValue = (key, value) => (
(!isPlainObject(value) && !isEmptyValue(value)) ||
isSymbol(key) ||
// The following keys are allowed to be empty
key === 'then' || // Avoids error with promises
key === 'inspect' || // Avoids error with console.log in node.js
key === 'length' // Avoids error with lodash checking if an object is array-like
);
// Helper to get current path
const getPath = (config, key) =>
config.path.length
? config.path.concat(key).join('.')
: key;
// Wraps a config object with a proxy that throws an error if accessing an empty
// or non-existent value (ie: undefined or empty string). External things may test
// for the existence of keys--for example, Promise.resolve will check `then`
// key to see if it's a thenable--so if the list of keys that can be empty grows
// more we should consider something a bit less experimental. For now this is kind
// of fun...
const guardAccessOfEmptyValues = (config) =>
new DeepProxy(config, {
get(target, key, receiver) {
const value = Reflect.get(target, key, receiver);
if (isPlainObject(value)) {
return this.nest(value);
} else if (shouldReturnRawValue(key, value)) {
return value;
} else if (isEmptyValue(value)) {
throw new Error(`Config error: config.${getPath(this, key)} is empty`)
}
},
});
module.exports = guardAccessOfEmptyValues;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment