Skip to content

Commit

Permalink
flag script
Browse files Browse the repository at this point in the history
  • Loading branch information
rickhanlonii committed Jan 26, 2024
1 parent 76f14eb commit c880229
Show file tree
Hide file tree
Showing 2 changed files with 308 additions and 1 deletion.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@
"download-build-for-head": "node ./scripts/release/download-experimental-build.js --commit=$(git rev-parse HEAD)",
"download-build-in-codesandbox-ci": "cd scripts/release && yarn install && cd ../../ && yarn download-build-for-head || yarn build --type=node react/index react-dom/index react-dom/src/server react-dom/test-utils scheduler/index react/jsx-runtime react/jsx-dev-runtime",
"check-release-dependencies": "node ./scripts/release/check-release-dependencies",
"generate-inline-fizz-runtime": "node ./scripts/rollup/generate-inline-fizz-runtime.js"
"generate-inline-fizz-runtime": "node ./scripts/rollup/generate-inline-fizz-runtime.js",
"flags": "node ./scripts/flags/flags.js"
},
"resolutions": {
"react-is": "npm:react-is"
Expand Down
306 changes: 306 additions & 0 deletions scripts/flags/flags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
'use strict';

const babel = require('@babel/register');

babel({
plugins: ['@babel/plugin-transform-modules-commonjs'],
});

// Set the globals to string values to output them to the table.
global.__VARIANT__ = 'gk';
global.__EXPERIMENTAL__ = 'experimental';
global.__NEXT_MAJOR__ = 'next';
global.__PROFILE__ = 'profile';
global.__DEV__ = 'dev';

// Mock the ReactNativeInternalFeatureFlags and ReactFeatureFlags modules
const Module = require('module');
const DynamicFeatureFlagsWWW = require('../../packages/shared/forks/ReactFeatureFlags.www-dynamic.js');
const DynamicFeatureFlagsNative = require('../../packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js');

const originalLoad = Module._load;

Module._load = function (request, parent) {
if (request === 'ReactNativeInternalFeatureFlags') {
return DynamicFeatureFlagsNative;
} else if (request === 'ReactFeatureFlags') {
return DynamicFeatureFlagsWWW;
}

return originalLoad.apply(this, arguments);
};

const yargs = require('yargs');
const argv = yargs
.parserConfiguration({
// Important: This option tells yargs to move all other options not
// specified here into the `_` key. We use this to send all of the
// Jest options that we don't use through to Jest (like --watch).
'unknown-options-as-args': true,
})
.wrap(yargs.terminalWidth())
.options({
csv: {
alias: 'c',
describe: 'output cvs.',
requiresArg: false,
type: 'boolean',
default: false,
},
diff: {
alias: 'd',
describe: 'output diff of two or more flags.',
requiresArg: false,
type: 'array',
choices: [
'www',
'www-modern',
'rn',
'rn-fb',
'canary',
'next',
'experimental',
null,
],
default: null,
},
sort: {
alias: 's',
describe: 'sort diff by one or more flags.',
requiresArg: false,
type: 'array',
default: 'next',
choices: [
'www',
'www-modern',
'rn',
'rn-fb',
'canary',
'next',
'experimental',
],
},
}).argv;

const ReactFeatureFlags = require('../../packages/shared/ReactFeatureFlags.js');
const ReactFeatureFlagsWWW = require('../../packages/shared/forks/ReactFeatureFlags.www.js');
const ReactFeatureFlagsNativeFB = require('../../packages/shared/forks/ReactFeatureFlags.native-fb.js');
const ReactFeatureFlagsNativeOSS = require('../../packages/shared/forks/ReactFeatureFlags.native-oss.js');

const allFlagsUniqueFlags = new Set([
...Object.keys(ReactFeatureFlags),
...Object.keys(ReactFeatureFlagsWWW),
...Object.keys(ReactFeatureFlagsNativeFB),
...Object.keys(ReactFeatureFlagsNativeOSS),
]);

function getNextMajorFlagValue(flag) {
const value = ReactFeatureFlags[flag];
if (value === true || value === 'next') {
return '✅';
} else if (value === false || value === 'experimental') {
return '❌';
} else if (value === 'profile') {
return '⏱️';
} else if (value === 'dev') {
return '💻';
} else if (typeof value === 'number') {
return value;
} else {
throw new Error(`Unexpected OSS Stable value ${value} for flag ${flag}`);
}
}

function getOSSCanaryFlagValue(flag) {
const value = ReactFeatureFlags[flag];
if (value === true) {
return '✅';
} else if (value === false || value === 'experimental' || value === 'next') {
return '❌';
} else if (value === 'profile') {
return '⏱️';
} else if (value === 'dev') {
return '💻';
} else if (typeof value === 'number') {
return value;
} else {
throw new Error(`Unexpected OSS Canary value ${value} for flag ${flag}`);
}
}

function getOSSExperimentalFlagValue(flag) {
const value = ReactFeatureFlags[flag];
if (value === true || value === 'experimental') {
return '✅';
} else if (value === false || value === 'next') {
return '❌';
} else if (value === 'profile') {
return '⏱️';
} else if (value === 'dev') {
return '💻';
} else if (typeof value === 'number') {
return value;
} else {
throw new Error(
`Unexpected OSS Experimental value ${value} for flag ${flag}`
);
}
}

function getWWWModernFlagValue(flag) {
const value = ReactFeatureFlagsWWW[flag];
if (value === true || value === 'experimental') {
return '✅';
} else if (value === false || value === 'next') {
return '❌';
} else if (value === 'profile') {
return '⏱️';
} else if (value === 'dev') {
return '💻';
} else if (value === 'gk') {
return '🧪';
} else if (typeof value === 'number') {
return value;
} else {
throw new Error(`Unexpected WWW Modern value ${value} for flag ${flag}`);
}
}

function getWWWClassicFlagValue(flag) {
const value = ReactFeatureFlagsWWW[flag];
if (value === true) {
return '✅';
} else if (value === false || value === 'experimental' || value === 'next') {
return '❌';
} else if (value === 'profile') {
return '⏱️';
} else if (value === 'dev') {
return '💻';
} else if (value === 'gk') {
return '🧪';
} else if (typeof value === 'number') {
return value;
} else {
throw new Error(`Unexpected WWW Classic value ${value} for flag ${flag}`);
}
}

function getRNOSSFlagValue(flag) {
const value = ReactFeatureFlagsNativeOSS[flag];
if (value === true) {
return '✅';
} else if (value === false || value === 'experimental' || value === 'next') {
return '❌';
} else if (value === 'profile') {
return '⏱️';
} else if (value === 'dev') {
return '💻';
} else if (value === 'gk') {
return '🧪';
} else if (typeof value === 'number') {
return value;
} else {
throw new Error(`Unexpected RN OSS value ${value} for flag ${flag}`);
}
}

function getRNFBFlagValue(flag) {
const value = ReactFeatureFlagsNativeFB[flag];
if (value === true) {
return '✅';
} else if (value === false || value === 'experimental' || value === 'next') {
return '❌';
} else if (value === 'profile') {
return '⏱️';
} else if (value === 'dev') {
return '💻';
} else if (value === 'gk') {
return '🧪';
} else if (typeof value === 'number') {
return value;
} else {
throw new Error(`Unexpected RN FB value ${value} for flag ${flag}`);
}
}

function argToHeader(arg) {
switch (arg) {
case 'www':
return 'WWW Classic';
case 'www-modern':
return 'WWW Modern';
case 'rn':
return 'RN OSS';
case 'rn-fb':
return 'RN FB';
case 'canary':
return 'OSS Canary';
case 'next':
return 'OSS Next Major';
case 'experimental':
return 'OSS Experimental';
default:
return arg;
}
}
const isDiff = argv.diff != null && argv.diff.length > 1;

const table = {};
// eslint-disable-next-line no-for-of-loops/no-for-of-loops
for (const flag of allFlagsUniqueFlags) {
const values = {
'OSS Next Major': getNextMajorFlagValue(flag),
'OSS Canary': getOSSCanaryFlagValue(flag),
'OSS Experimental': getOSSExperimentalFlagValue(flag),
'WWW Classic': getWWWClassicFlagValue(flag),
'WWW Modern': getWWWModernFlagValue(flag),
'RN FB': getRNFBFlagValue(flag),
'RN OSS': getRNOSSFlagValue(flag),
};

if (!isDiff) {
table[flag] = values;
continue;
}

const subset = argv.diff.map(argToHeader).reduce((acc, key) => {
if (key in values) {
acc[key] = values[key];
}
return acc;
}, {});

if (new Set(Object.values(subset)).size !== 1) {
table[flag] = subset;
}
}

// Sort the table
const sortBy = isDiff ? argv.diff.map(argToHeader) : argv.sort.map(argToHeader);
let sorted;
sortBy.forEach(sort => {
sorted = Object.fromEntries(
Object.entries(table).sort(([, rowA], [, rowB]) =>
rowB[sort].toString().localeCompare(rowA[sort])
)
);
});

if (argv.csv) {
const fs = require('fs');
const csvHeader =
'Flag name, WWW Classic, RN FB, OSS Canary, OSS Experimental, WWW Modern, RN OSS\n';
const csvRows = Object.keys(sorted).map(flag => {
const row = sorted[flag];
return `${flag}, ${row['WWW Classic']}, ${row['RN FB']}, ${row['OSS Canary']}, ${row['OSS Experimental']}, ${row['WWW Modern']}, ${row['RN OSS']}`;
});
fs.writeFile('./flags.csv', csvHeader + csvRows.join('\n'), function (err) {
if (err) {
return console.log(err);
}
console.log('The file was saved!');
});
}

// print table with formatting
console.table(sorted);

0 comments on commit c880229

Please sign in to comment.