Skip to content

Commit

Permalink
Support setting GKs in RecoilEnv
Browse files Browse the repository at this point in the history
This change adds a new property to RecoilEnv,
RECOIL_GKS_ENABLED_UNSTABLE, which can be used to enable certain GKs at
runtime. When the property is updated, its changes are proxied to the
underlying GK implementation.
  • Loading branch information
impl committed Oct 24, 2022
1 parent 4d7527c commit 791a32d
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 19 deletions.
77 changes: 59 additions & 18 deletions packages/recoil/core/Recoil_RecoilEnv.js
Expand Up @@ -12,14 +12,61 @@
'use strict';

const err = require('recoil-shared/util/Recoil_err');
const gkx = require('recoil-shared/util/Recoil_gkx');

export type RecoilEnv = {
RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED: boolean,
RECOIL_GKS_ENABLED_UNSTABLE: string[],
};

const env: RecoilEnv = {
RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED: true,
};
const env: RecoilEnv = new Proxy(
{
RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED: true,
RECOIL_GKS_ENABLED_UNSTABLE: [],
},
{
set(obj, prop, value) {
if (prop === 'RECOIL_GKS_ENABLED_UNSTABLE') {
// Remove old GKs set in the environment, filter out any GKS that are
// already set by default, and set new GKs.
obj[prop].forEach(gkx.setFail);
obj[prop] = value.filter(gk => !gkx(gk));
obj[prop].forEach(gkx.setPass);
} else {
obj[prop] = value;
}

return true;
},
},
);

function readProcessEnvBooleanFlag(name: string, set: boolean => void) {
const sanitizedValue = process.env[name]?.toLowerCase()?.trim();

if (sanitizedValue == null || sanitizedValue === '') {
return;
}

const allowedValues = ['true', 'false'];
if (!allowedValues.includes(sanitizedValue)) {
throw err(
`process.env.${name} value must be 'true', 'false', or empty: ${sanitizedValue}`,
);
}

set(sanitizedValue === 'true');
}

function readProcessEnvStringArrayFlag(name: string, set: (string[]) => void) {
const sanitizedValue = process.env[name]?.trim();

if (sanitizedValue == null || sanitizedValue === '') {
return;
}

set(sanitizedValue.split(/\s*,\s*/));
}

/**
* Allow NodeJS/NextJS/etc to set the initial state through process.env variable
Expand All @@ -38,21 +85,15 @@ function applyProcessEnvFlagOverrides() {
return;
}

const sanitizedValue =
process.env.RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED?.toLowerCase()?.trim();

if (sanitizedValue == null || sanitizedValue === '') {
return;
}

const allowedValues = ['true', 'false'];
if (!allowedValues.includes(sanitizedValue)) {
throw err(
`process.env.RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED value must be 'true', 'false', or empty: ${sanitizedValue}`,
);
}

env.RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED = sanitizedValue === 'true';
readProcessEnvBooleanFlag(
'RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED',
value => {
env.RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED = value;
},
);
readProcessEnvStringArrayFlag('RECOIL_GKS_ENABLED_UNSTABLE', value => {
env.RECOIL_GKS_ENABLED_UNSTABLE = value;
});
}

applyProcessEnvFlagOverrides();
Expand Down
33 changes: 32 additions & 1 deletion packages/recoil/core/__tests__/Recoil_core-test.js
Expand Up @@ -14,7 +14,7 @@ const {
getRecoilTestFn,
} = require('recoil-shared/__test_utils__/Recoil_TestingUtils');

let a, atom, store, nullthrows, getNodeLoadable, setNodeValue;
let a, atom, store, nullthrows, getNodeLoadable, setNodeValue, RecoilEnv, gkx;

const testRecoil = getRecoilTestFn(() => {
const {
Expand All @@ -28,6 +28,9 @@ const testRecoil = getRecoilTestFn(() => {
a = atom<number>({key: 'a', default: 0}).key;

store = makeStore();

RecoilEnv = require('../Recoil_RecoilEnv');
gkx = require('recoil-shared/util/Recoil_gkx');
});

testRecoil('read default value', () => {
Expand All @@ -43,3 +46,31 @@ testRecoil('setNodeValue returns written value when writing atom', () => {
const writes = setNodeValue(store, store.getState().currentTree, a, 1);
expect(nullthrows(writes.get(a)).contents).toBe(1);
});

describe('gatekeepers', () => {
testRecoil('environment propagates GKs', () => {
expect(gkx('recoil_test_gk')).toBe(false);
RecoilEnv.RECOIL_GKS_ENABLED_UNSTABLE = ['recoil_test_gk'];
expect(gkx('recoil_test_gk')).toBe(true);
RecoilEnv.RECOIL_GKS_ENABLED_UNSTABLE = [];
expect(gkx('recoil_test_gk')).toBe(false);
});

describe('support for process.env.RECOIL_GKS_ENABLED_UNSTABLE', () => {
const originalProcessEnv = process.env;
beforeEach(() => {
process.env = {...originalProcessEnv};
process.env.RECOIL_GKS_ENABLED_UNSTABLE =
'recoil_test_gk1,recoil_test_gk2';
});

afterEach(() => {
process.env = originalProcessEnv;
});

testRecoil('environment propagates GKs', () => {
expect(gkx('recoil_test_gk1')).toBe(true);
expect(gkx('recoil_test_gk2')).toBe(true);
});
});
});
1 change: 1 addition & 0 deletions typescript/recoil.d.ts
Expand Up @@ -38,6 +38,7 @@
// recoilEnv.d.ts
export interface RecoilEnv {
RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED: boolean;
RECOIL_GKS_ENABLED_UNSTABLE: string[];
}

export const RecoilEnv: RecoilEnv;
Expand Down

0 comments on commit 791a32d

Please sign in to comment.