<NME> index.ts
<BEF> import { isImmutable, List } from "immutable";
import isEqual from "lodash/isEqual";
import result from "lodash/result";
import set from "lodash/set";
import unset from "lodash/unset";
import { setConfigAtKey } from "./myths/set-config-at-key";
import { configuration } from "./package";
import { ConfigurationOption, ConfigurationOptionDefinition, ConfigurationOptionDeprecatedDefinition, HasPrivateConfigurationState } from "./types";

export { configuration } from "./package";
export { setConfigAtKey } from "./myths/set-config-at-key"
export { toggleConfigAtKey } from "./myths/toggle-config-at-key"
export * from "./types";

const options: {[key: string]: ConfigurationOption} = {};
const deprecated: {[key: string]: <T>(value: T) => { [key: string]: T }} = {};

const strippedToDefinition = <T>(option: ConfigurationOptionDefinition<T>) => {
  // Make a copy and trim everything down to just the spec
  const definition: ConfigurationOptionDefinition<T> = {...option};

  unset(definition, "value");
  unset(definition, "selector");
  unset(definition, "action");

  return definition;
}

export const defineConfigOption = <TYPE>(
  props: ConfigurationOptionDefinition<TYPE>,
) => {
  if (props.key in deprecated) {
    throw new Error(`Duplicate deprecated configuration option "${props.key}"`);
  }

  if (props.key in options) {
    const oldSpec = strippedToDefinition(options[props.key]);
    const newSpec = strippedToDefinition(props);

    if (!isEqual(oldSpec, newSpec)) {
      console.group(`Duplicate configuration option "${props.key}"`)
      console.log("old config option spec:", oldSpec);
      console.log("new config option spec:", newSpec);
      console.groupEnd()

      throw new Error(`Duplicate configuration option "${props.key}"`);
    }
  }

  options[props.key] = {
    ...props,
    value: props.defaultValue,
    selector: configuration.createSelector(
      state => {
        const value =
          state?.current?.getIn(props.key.split(".")) ?? props.defaultValue;

        return isImmutable(value)
          ? value.toJS()
          : value;
      }
    ),
    action: (value: TYPE) => setConfigAtKey.create({ key: props.key, value }),
  };

  return options[props.key];
};

export const createDeprecatedConfigOption = <TYPE>(
  props: ConfigurationOptionDeprecatedDefinition,
) => {
  if (props.key in options) {
    throw new Error(`Duplicate deprecated configuration option "${props.key}"`);
  }

  if (props.key in deprecated && props.changeTo !== deprecated[props.key]) {
    throw new Error(`Duplicate deprecated configuration option "${props.key}"`);
  }

  deprecated[props.key] = props.changeTo;
}

export const createConfigCollection = <TYPE>(
  { key }: { key: string },
) => configuration.createSelector(
  state => {
    const actual = {
      [key]: state?.current?.get(key)?.toJS() ?? {}
    };

    Object
      .entries(options)
      .filter(([optionKey, _]) => optionKey.startsWith(`${key}.`))
      .filter(([optionKey, _]) => result(actual, optionKey) === undefined)
      .forEach(([optionKey, option]) =>
        set(actual, optionKey, option.defaultValue),
      );

    return actual[key];
  },
);

export const allConfigOptionDefinitions = () =>
  Object.values(options).map(strippedToDefinition);

export const allConfigOptions = (state?: HasPrivateConfigurationState) => {
  const all = Object.values(options);

  if (state !== undefined) {
    return all.map(x => ({
      ...x,
      value: x.selector(state),
    }));
  }
  else {
    return all;
  }
};

export const configOption = (key: string) => {
  return options[key];
};

export const allDeprecations = () => {
  return List(Object.entries(deprecated).map(([key, changeTo]) => ({
    key,
    changeTo,
  })));
}export const setConfigFile = (function () {
  // Try to return the actually requested function (works on node & electron)
  try {
    // This line fails in the browser due to fs-observable dependencies
    const fsBackend = require("./backends/filesystem");
    
    // Some browsers define 'require', and maybe they will return something
    // falsy instead of throwing so let's make sure that's not happening.
    if (fsBackend === undefined || fsBackend.setConfigFile === undefined) {

    return fsBackend.setConfigFile;
  } catch (requireErr) {
    // Ono the import failed. Not a showstopper for browser users. Return a
    // version of the function that yells if you use it.
    return (filename: string) => {
      const err = Error("Failed to load mythic-configuration's filesystem backend. You're probably running in a browser, but this only works in a node runtime!");

<MSG> Disable webpack processing of this node-only import

<DFF> @@ -131,9 +131,13 @@ export const allDeprecations = () => {
 export const setConfigFile = (function () {
   // Try to return the actually requested function (works on node & electron)
   try {
-    // This line fails in the browser due to fs-observable dependencies
-    const fsBackend = require("./backends/filesystem");
-    
+    // This import fails in the browser due to fs-observable dependencies.
+    // Attempt the import using a non-literal string to gently dissuade webpack
+    // and similar creatures from pre-processing the `require` (which fails in a
+    // non-catchable way).
+    const fsBackendPath = "./backends/filesystem";
+    const fsBackend = require(fsBackendPath);
+
     // Some browsers define 'require', and maybe they will return something
     // falsy instead of throwing so let's make sure that's not happening.
     if (fsBackend === undefined || fsBackend.setConfigFile === undefined) {
@@ -142,7 +146,7 @@ export const setConfigFile = (function () {
 
     return fsBackend.setConfigFile;
   } catch (requireErr) {
-    // Ono the import failed. Not a showstopper for browser users. Return a
+    // Ono the import failed! Not a showstopper for browser users. Return a
     // version of the function that yells if you use it.
     return (filename: string) => {
       const err = Error("Failed to load mythic-configuration's filesystem backend. You're probably running in a browser, but this only works in a node runtime!");

{'commit': 'diff --git a/packages/mythic-configuration/__tests__/configuration.spec.ts b/packages/mythic-configuration/__tests__/configuration.spec.ts\nindex b405b4788..6ea650da9 100644\n--- a/packages/mythic-configuration/__tests__/configuration.spec.ts\n+++ b/packages/mythic-configuration/__tests__/configuration.spec.ts\n@@ -120,7 +120,7 @@ describe("configuration", () => {\n     });\n \n     test("in non-node environment index.ts exports an implementation that throws exceptions [https://github.com/nteract/nteract/issues/5445]", () => {\n-      jest.resetModules();  \n+      jest.resetModules();\n       jest.mock("../src/backends/filesystem", () => {\n         throw new Error("Can\'t resolve \'fs\' in \'.../node_modules/mkdirp\'");\n       });\ndiff --git a/packages/mythic-configuration/src/index.ts b/packages/mythic-configuration/src/index.ts\nindex 0544d32c8..c671aa7a2 100644\n--- a/packages/mythic-configuration/src/index.ts\n+++ b/packages/mythic-configuration/src/index.ts\n@@ -131,9 +131,13 @@ export const allDeprecations = () => {\n export const setConfigFile = (function () {\n   // Try to return the actually requested function (works on node & electron)\n   try {\n-    // This line fails in the browser due to fs-observable dependencies\n-    const fsBackend = require("./backends/filesystem");\n-    \n+    // This import fails in the browser due to fs-observable dependencies.\n+    // Attempt the import using a non-literal string to gently dissuade webpack\n+    // and similar creatures from pre-processing the `require` (which fails in a\n+    // non-catchable way).\n+    const fsBackendPath = "./backends/filesystem";\n+    const fsBackend = require(fsBackendPath);\n+\n     // Some browsers define \'require\', and maybe they will return something\n     // falsy instead of throwing so let\'s make sure that\'s not happening.\n     if (fsBackend === undefined || fsBackend.setConfigFile === undefined) {\n@@ -142,7 +146,7 @@ export const setConfigFile = (function () {\n \n     return fsBackend.setConfigFile;\n   } catch (requireErr) {\n-    // Ono the import failed. Not a showstopper for browser users. Return a\n+    // Ono the import failed! Not a showstopper for browser users. Return a\n     // version of the function that yells if you use it.\n     return (filename: string) => {\n       const err = Error("Failed to load mythic-configuration\'s filesystem backend. You\'re probably running in a browser, but this only works in a node runtime!");\n', 'commit_subject': 'Disable webpack processing of this node-only import', 'repo_name': 'nteract/nteract', 'committer': {'name': 'Erem Boto', 'email': '2b81d3d15d09f32e9d4098e69e7a6c7d5e9b1134@stripe.com', 'time_sec': '1613242525', 'tz_offset': '-480', 'date': {'seconds': '1613242525'}}, 'commit_tree': '921b700f31279ce3dc09662c2aa63a3098be1e7e', 'commit_message': 'Disable webpack processing of this node-only import\n', 'language_name': 'Shell', 'license': 'bsd-3-clause', 'hunks': '@@ -131,9 +131,13 @@ export const allDeprecations = () => {\n export const setConfigFile = (function () {\n   // Try to return the actually requested function (works on node & electron)\n   try {\n-    // This line fails in the browser due to fs-observable dependencies\n-    const fsBackend = require("./backends/filesystem");\n-    \n+    // This import fails in the browser due to fs-observable dependencies.\n+    // Attempt the import using a non-literal string to gently dissuade webpack\n+    // and similar creatures from pre-processing the `require` (which fails in a\n+    // non-catchable way).\n+    const fsBackendPath = "./backends/filesystem";\n+    const fsBackend = require(fsBackendPath);\n+\n     // Some browsers define \'require\', and maybe they will return something\n     // falsy instead of throwing so let\'s make sure that\'s not happening.\n     if (fsBackend === undefined || fsBackend.setConfigFile === undefined) {\n@@ -142,7 +146,7 @@ export const setConfigFile = (function () {\n \n     return fsBackend.setConfigFile;\n   } catch (requireErr) {\n-    // Ono the import failed. Not a showstopper for browser users. Return a\n+    // Ono the import failed! Not a showstopper for browser users. Return a\n     // version of the function that yells if you use it.\n     return (filename: string) => {\n       const err = Error("Failed to load mythic-configuration\'s filesystem backend. You\'re probably running in a browser, but this only works in a node runtime!");\n', 'addition_count': 8, 'deletion_count': 4, 'src_file': 'a/packages/mythic-configuration/src/index.ts', 'tgt_file': 'b/packages/mythic-configuration/src/index.ts', 'file_extension': '.ts', 'before_file': 'import { isImmutable, List } from "immutable";\nimport isEqual from "lodash/isEqual";\nimport result from "lodash/result";\nimport set from "lodash/set";\nimport unset from "lodash/unset";\nimport { setConfigAtKey } from "./myths/set-config-at-key";\nimport { configuration } from "./package";\nimport { ConfigurationOption, ConfigurationOptionDefinition, ConfigurationOptionDeprecatedDefinition, HasPrivateConfigurationState } from "./types";\n\nexport { configuration } from "./package";\nexport { setConfigAtKey } from "./myths/set-config-at-key"\nexport { toggleConfigAtKey } from "./myths/toggle-config-at-key"\nexport * from "./types";\n\nconst options: {[key: string]: ConfigurationOption} = {};\nconst deprecated: {[key: string]: <T>(value: T) => { [key: string]: T }} = {};\n\nconst strippedToDefinition = <T>(option: ConfigurationOptionDefinition<T>) => {\n  // Make a copy and trim everything down to just the spec\n  const definition: ConfigurationOptionDefinition<T> = {...option};\n\n  unset(definition, "value");\n  unset(definition, "selector");\n  unset(definition, "action");\n\n  return definition;\n}\n\nexport const defineConfigOption = <TYPE>(\n  props: ConfigurationOptionDefinition<TYPE>,\n) => {\n  if (props.key in deprecated) {\n    throw new Error(`Duplicate deprecated configuration option "${props.key}"`);\n  }\n\n  if (props.key in options) {\n    const oldSpec = strippedToDefinition(options[props.key]);\n    const newSpec = strippedToDefinition(props);\n\n    if (!isEqual(oldSpec, newSpec)) {\n      console.group(`Duplicate configuration option "${props.key}"`)\n      console.log("old config option spec:", oldSpec);\n      console.log("new config option spec:", newSpec);\n      console.groupEnd()\n\n      throw new Error(`Duplicate configuration option "${props.key}"`);\n    }\n  }\n\n  options[props.key] = {\n    ...props,\n    value: props.defaultValue,\n    selector: configuration.createSelector(\n      state => {\n        const value =\n          state?.current?.getIn(props.key.split(".")) ?? props.defaultValue;\n\n        return isImmutable(value)\n          ? value.toJS()\n          : value;\n      }\n    ),\n    action: (value: TYPE) => setConfigAtKey.create({ key: props.key, value }),\n  };\n\n  return options[props.key];\n};\n\nexport const createDeprecatedConfigOption = <TYPE>(\n  props: ConfigurationOptionDeprecatedDefinition,\n) => {\n  if (props.key in options) {\n    throw new Error(`Duplicate deprecated configuration option "${props.key}"`);\n  }\n\n  if (props.key in deprecated && props.changeTo !== deprecated[props.key]) {\n    throw new Error(`Duplicate deprecated configuration option "${props.key}"`);\n  }\n\n  deprecated[props.key] = props.changeTo;\n}\n\nexport const createConfigCollection = <TYPE>(\n  { key }: { key: string },\n) => configuration.createSelector(\n  state => {\n    const actual = {\n      [key]: state?.current?.get(key)?.toJS() ?? {}\n    };\n\n    Object\n      .entries(options)\n      .filter(([optionKey, _]) => optionKey.startsWith(`${key}.`))\n      .filter(([optionKey, _]) => result(actual, optionKey) === undefined)\n      .forEach(([optionKey, option]) =>\n        set(actual, optionKey, option.defaultValue),\n      );\n\n    return actual[key];\n  },\n);\n\nexport const allConfigOptionDefinitions = () =>\n  Object.values(options).map(strippedToDefinition);\n\nexport const allConfigOptions = (state?: HasPrivateConfigurationState) => {\n  const all = Object.values(options);\n\n  if (state !== undefined) {\n    return all.map(x => ({\n      ...x,\n      value: x.selector(state),\n    }));\n  }\n  else {\n    return all;\n  }\n};\n\nexport const configOption = (key: string) => {\n  return options[key];\n};\n\nexport const allDeprecations = () => {\n  return List(Object.entries(deprecated).map(([key, changeTo]) => ({\n    key,\n    changeTo,\n  })));\n}export const setConfigFile = (function () {\n  // Try to return the actually requested function (works on node & electron)\n  try {\n    // This line fails in the browser due to fs-observable dependencies\n    const fsBackend = require("./backends/filesystem");\n    \n    // Some browsers define \'require\', and maybe they will return something\n    // falsy instead of throwing so let\'s make sure that\'s not happening.\n    if (fsBackend === undefined || fsBackend.setConfigFile === undefined) {\n\n    return fsBackend.setConfigFile;\n  } catch (requireErr) {\n    // Ono the import failed. Not a showstopper for browser users. Return a\n    // version of the function that yells if you use it.\n    return (filename: string) => {\n      const err = Error("Failed to load mythic-configuration\'s filesystem backend. You\'re probably running in a browser, but this only works in a node runtime!");\n', 'message': 'Disable webpack processing of this node-only import\n', 'author_name': 'Erem Boto', 'lang': 'ts'}