cooky-cutter
Version:
Object factories for testing in TypeScript
72 lines (71 loc) • 2.95 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.compute = void 0;
const utils_1 = require("./utils");
const config_1 = require("./config");
// Given a key, the configuration object (with overrides already applied) and
// the end result object, compute the current value for the given key and write
// that value to the result object. Optionally track the path values are
// computed along in cases where it's possible to define circular dependencies.
function compute(key, values, result, invocations, path, override, computedKeys) {
// If this key was already computed (according to the passed array) then skip
// this computation. This likely was a result of a `derive` function requiring
// this key to be computed to invoke the derived function because it was a
// dependency. In these cases, avoid re-computing the value because often
// the factories are not idempotent (eg: each call the invocation is
// incremented) which can lead to unexpected inconsistencies.
if (computedKeys.indexOf(key) >= 0) {
return;
}
const value = values[key];
// In essence, this is "exhaustively" checking for each type of attribute that
// can be defined for a given key. Unfortunately it's not truly exhaustive,
// but would be great to update this to do true exhaustive type checking.
if (utils_1.isDerivedFunction(value)) {
result[key] = value(result, values, invocations, path, override, computedKeys);
}
else if (utils_1.isFactoryFunction(value)) {
result[key] = value();
}
else if (utils_1.isArrayFactoryFunction(value)) {
result[key] = value();
}
else if (utils_1.isAttributeFunction(value)) {
result[key] = value(invocations);
}
else {
if (!(key in override)) {
warnAboutHardCodedValues(key, value);
}
result[key] = value;
}
// Mark this key has having it's value computed.
computedKeys.push(key);
}
exports.compute = compute;
/**
* Explicitly setting an object or array as a value in a factory can lead to
* really challenging and subtle bugs since they will be shared across all
* instances of a factory. Check for objects and arrays and by default display
* a warning.
*/
const warnAboutHardCodedValues = (key, value) => {
let message;
if (Array.isArray(value)) {
message = `\`${key}\` contains a hard-coded array.`;
}
else if (typeof value === "object" && value !== null) {
message = `\`${key}\` contains a hard-coded object.`;
}
const { errorOnHardCodedValues } = config_1.getConfig();
if (message) {
message += ` It will be shared across all instances of this factory. Consider using a factory function.`;
if (errorOnHardCodedValues) {
console.trace();
throw message;
}
else {
console.warn(message);
}
}
};