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, which
can be used to enable certain GKs at runtime. We update the OSS gkx()
implementation to refer to this property directly, and as a result we
have to move the RecoilEnv to the shared package (which also
conveniently ensures that RecoilEnv properties and gkx() are initialized
together).
  • Loading branch information
impl committed Nov 2, 2022
1 parent 7681892 commit ab92f08
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 28 deletions.
2 changes: 1 addition & 1 deletion packages/recoil/Recoil_index.js
Expand Up @@ -44,7 +44,7 @@ export type {

const {RecoilLoadable} = require('./adt/Recoil_Loadable');
const {DefaultValue} = require('./core/Recoil_Node');
const RecoilEnv = require('./core/Recoil_RecoilEnv');
const RecoilEnv = require('recoil-shared/util/Recoil_RecoilEnv');
const {RecoilRoot, useRecoilStoreID} = require('./core/Recoil_RecoilRoot');
const {isRecoilValue} = require('./core/Recoil_RecoilValue');
const {retentionZone} = require('./core/Recoil_RetentionZone');
Expand Down
2 changes: 1 addition & 1 deletion packages/recoil/core/Recoil_Node.js
Expand Up @@ -17,7 +17,7 @@ import type {RetainedBy} from './Recoil_RetainedBy';
import type {AtomWrites, NodeKey, Store, TreeState} from './Recoil_State';

const {isFastRefreshEnabled} = require('./Recoil_ReactMode');
const RecoilEnv = require('./Recoil_RecoilEnv');
const RecoilEnv = require('recoil-shared/util/Recoil_RecoilEnv');
const RecoilValueClasses = require('./Recoil_RecoilValue');
const expectationViolation = require('recoil-shared/util/Recoil_expectationViolation');
const gkx = require('recoil-shared/util/Recoil_gkx');
Expand Down
Expand Up @@ -57,7 +57,7 @@ const testRecoil = getRecoilTestFn(() => {

({DEFAULT_VALUE, DefaultValue} = require('../../core/Recoil_Node'));
({RecoilRoot, useRecoilStoreID} = require('../../core/Recoil_RecoilRoot'));
RecoilEnv = require('../../core/Recoil_RecoilEnv');
RecoilEnv = require('recoil-shared/util/Recoil_RecoilEnv');
({isRecoilValue} = require('../../core/Recoil_RecoilValue'));
({RecoilLoadable, isLoadable} = require('../../adt/Recoil_Loadable'));
({
Expand Down
Expand Up @@ -11,16 +11,50 @@

'use strict';

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

export type RecoilEnv = {
RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED: boolean,
RECOIL_GKS_ENABLED: Set<string>,
};

const env: RecoilEnv = {
RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED: true,
RECOIL_GKS_ENABLED: new Set([
'recoil_hamt_2020',
'recoil_sync_external_store',
'recoil_suppress_rerender_in_callback',
'recoil_memory_managament_2020',
]),
};

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*|\s+/));
}

/**
* Allow NodeJS/NextJS/etc to set the initial state through process.env variable
* Note: we don't assume 'process' is available in all runtime environments
Expand All @@ -38,21 +72,17 @@ 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', value => {
value.forEach(gk => {
env.RECOIL_GKS_ENABLED.add(gk);
});
});
}

applyProcessEnvFlagOverrides();
Expand Down
14 changes: 5 additions & 9 deletions packages/shared/util/Recoil_gkx.js
Expand Up @@ -10,26 +10,22 @@
*/
'use strict';

const gks = new Map()
.set('recoil_hamt_2020', true)
.set('recoil_sync_external_store', true)
.set('recoil_suppress_rerender_in_callback', true)
.set('recoil_memory_managament_2020', true);
const RecoilEnv = require('./Recoil_RecoilEnv');

function Recoil_gkx_OSS(gk: string): boolean {
return gks.get(gk) ?? false;
return RecoilEnv.RECOIL_GKS_ENABLED.has(gk);
}

Recoil_gkx_OSS.setPass = (gk: string): void => {
gks.set(gk, true);
RecoilEnv.RECOIL_GKS_ENABLED.add(gk);
};

Recoil_gkx_OSS.setFail = (gk: string): void => {
gks.set(gk, false);
RecoilEnv.RECOIL_GKS_ENABLED.delete(gk);
};

Recoil_gkx_OSS.clear = (): void => {
gks.clear();
RecoilEnv.RECOIL_GKS_ENABLED.clear();
};

module.exports = Recoil_gkx_OSS; // @oss-only
Expand Down
44 changes: 44 additions & 0 deletions packages/shared/util/__tests__/Recoil_RecoilEnv-test.js
@@ -0,0 +1,44 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @oncall recoil
*/
'use strict';

describe('RecoilEnv', () => {
test('environment propagates GKs', () => {
const RecoilEnv = require('../Recoil_RecoilEnv');
const gkx = require('../Recoil_gkx');

expect(gkx('recoil_test_gk')).toBe(false);
RecoilEnv.RECOIL_GKS_ENABLED.add('recoil_test_gk');
expect(gkx('recoil_test_gk')).toBe(true);
});

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

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

test('environment propagates GKs', () => {
const gkx = require('../Recoil_gkx');

expect(gkx('recoil_test_gk1')).toBe(true);
expect(gkx('recoil_test_gk2')).toBe(true);
expect(gkx('recoil_test_gk3')).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: Set<string>;
}

export const RecoilEnv: RecoilEnv;
Expand Down

0 comments on commit ab92f08

Please sign in to comment.