Skip to content

Commit

Permalink
MF-87 Config library should support nested config properties (openmrs#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
brandones authored and joeldenning committed Oct 19, 2019
1 parent d11199d commit 5f30cb7
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 15 deletions.
41 changes: 41 additions & 0 deletions packages/esm-config/src/module-config/module-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,50 @@ describe("getConfig", () => {
expect(() => Config.getConfig("foo-module")).toThrowError(/schema/);
});

it("requires nested config values to have been defined in the schema", () => {
Config.defineConfigSchema("foo-module", {
foo: { bar: { default: "qux" } }
});
Config.provide({ "foo-module": { foo: { doof: "nope" } } });
expect(() => Config.getConfig("foo-module")).toThrowError(/schema/);
});

it("throws if looking up module with no schema", () => {
expect(() => Config.getConfig("fake-module")).toThrowError(
/schema.*defined/
);
});

it("returns a nested configuration", () => {
Config.defineConfigSchema("foo-module", {
foo: {
bar: {
default: -1
},
baz: {
qux: {
default: "N/A"
},
quy: {
default: ""
}
}
}
});
const testConfig = {
"foo-module": {
foo: {
bar: 0,
baz: {
quy: "xyz"
}
}
}
};
Config.provide(testConfig);
const config = Config.getConfig("foo-module");
expect(config.foo.bar).toBe(0);
expect(config.foo.baz.qux).toBe("N/A");
expect(config.foo.baz.quy).toBe("xyz");
});
});
55 changes: 40 additions & 15 deletions packages/esm-config/src/module-config/module-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,52 @@ export function getConfig(moduleName) {
}
const schema = schemas[moduleName];

// Create a config object composed of all the defaults
const defaultConfig = R.map(R.prop("default"), schema);

// Merge all of the configs provided for moduleName
const mergeDeepAll = R.reduce(R.mergeDeepRight, {});
const allConfigsForModule = R.map(R.prop(moduleName), configs);
const providedConfig = R.mergeAll(allConfigsForModule);
const providedConfig = mergeDeepAll(allConfigsForModule);

for (let [key, value] of Object.entries(providedConfig)) {
if (!schema.hasOwnProperty(key)) {
throw Error(
`Unknown config key ${key} provided for module ${moduleName}. Please see the config schema for ${moduleName}.`
);
// Recursively check the provided config tree to make sure that all
// of the provided properties exist in the schema.
const checkForUnknownConfigProperties = (schema, config, keyPath = "") => {
for (let [key, value] of Object.entries(config)) {
keyPath += key;
if (!schema.hasOwnProperty(key)) {
throw Error(
`Unknown config key ${keyPath} provided for module ${moduleName}. Please see the config schema for ${moduleName}.`
);
} else if (typeof value === "object" && value !== null) {
// Recurse to config[key] and schema[key].
const schemaPart = schema[key];
checkForUnknownConfigProperties(schemaPart, value, keyPath + ".");
}
}
}
for (let key of Object.keys(schema)) {
if (!providedConfig.hasOwnProperty(key)) {
providedConfig[key] = schema[key]["default"];
};
checkForUnknownConfigProperties(schema, providedConfig);

// Recursively fill in the config with values from the schema.
const setDefaults = (schema, config) => {
for (let key of Object.keys(schema)) {
if (schema[key].hasOwnProperty("default")) {
// We assume that schema[key] defines a config value, since it has
// a property "default."
if (!config.hasOwnProperty(key)) {
config[key] = schema[key]["default"];
}
} else {
// Since schema[key] has no property "default", we assume it is a
// parent config property. We recurse to config[key] and schema[key].
// Default config[key] to {}.
const schemaPart = schema[key];
const configPart = config.hasOwnProperty(key) ? config[key] : {};
config[key] = setDefaults(schemaPart, configPart);
}
}
}
return config;
};
const config = setDefaults(schema, providedConfig);

return providedConfig;
return config;
}

export function clearAll() {
Expand Down

0 comments on commit 5f30cb7

Please sign in to comment.