@fast-check/poisoning
Version:
Set of utilities to ease detection and revert of poisoning
88 lines (87 loc) • 4.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.captureAllGlobals = captureAllGlobals;
const PoisoningFreeArray_js_1 = require("./PoisoningFreeArray.js");
const PoisoningFreeMap_js_1 = require("./PoisoningFreeMap.js");
const PoisoningFreeSet_js_1 = require("./PoisoningFreeSet.js");
const SString = String;
const safeObjectGetOwnPropertyDescriptors = Object.getOwnPropertyDescriptors;
const safeObjectGetOwnPropertyNames = Object.getOwnPropertyNames;
const safeObjectGetOwnPropertySymbols = Object.getOwnPropertySymbols;
function compareKeys(keyA, keyB) {
const sA = SString(keyA[0]);
const sB = SString(keyB[0]);
return sA < sB ? -1 : sA > sB ? 1 : 0;
}
function extractAllDescriptorsDetails(instance) {
const descriptors = safeObjectGetOwnPropertyDescriptors(instance);
const allDescriptors = PoisoningFreeArray_js_1.PoisoningFreeArray.from([
...safeObjectGetOwnPropertyNames(descriptors),
...safeObjectGetOwnPropertySymbols(descriptors),
]);
const allDescriptorsDetails = PoisoningFreeArray_js_1.PoisoningFreeArray.from(allDescriptors[PoisoningFreeArray_js_1.MapSymbol]((name) => [
name,
descriptors[name],
]));
return allDescriptorsDetails[PoisoningFreeArray_js_1.SortSymbol](compareKeys);
}
function flagRootRecursively(knownGlobals, instance, currentRoot) {
const storedGlobal = knownGlobals[PoisoningFreeMap_js_1.GetSymbol](instance);
if (storedGlobal === undefined) {
return;
}
if (storedGlobal.rootAncestors[PoisoningFreeSet_js_1.HasSymbol](currentRoot)) {
return;
}
storedGlobal.rootAncestors[PoisoningFreeSet_js_1.AddSymbol](currentRoot);
if (storedGlobal.depth <= 1) {
return;
}
for (const [, descriptor] of storedGlobal.properties) {
flagRootRecursively(knownGlobals, descriptor.value, currentRoot);
}
}
function captureAllGlobals() {
const knownGlobals = PoisoningFreeMap_js_1.PoisoningFreeMap.from();
const nextCaptures = PoisoningFreeArray_js_1.PoisoningFreeArray.from([
{ instance: globalThis, name: 'globalThis', currentDepth: 0, lastRootInPath: 'globalThis' },
]);
while (nextCaptures.length !== 0) {
const { instance, name, currentDepth, lastRootInPath } = nextCaptures[PoisoningFreeArray_js_1.ShiftSymbol]();
if (typeof instance !== 'function' && typeof instance !== 'object') {
continue;
}
if (instance === null || instance === undefined) {
continue;
}
if (knownGlobals[PoisoningFreeMap_js_1.HasSymbol](instance)) {
flagRootRecursively(knownGlobals, instance, lastRootInPath);
continue;
}
const allDescriptorsDetails = extractAllDescriptorsDetails(instance);
const localGlobal = {
name,
depth: currentDepth,
properties: PoisoningFreeMap_js_1.PoisoningFreeMap.from(),
rootAncestors: PoisoningFreeSet_js_1.PoisoningFreeSet.from([lastRootInPath]),
};
knownGlobals[PoisoningFreeMap_js_1.SetSymbol](instance, localGlobal);
for (let index = 0; index !== allDescriptorsDetails.length; ++index) {
const descriptorName = allDescriptorsDetails[index][0];
const descriptor = allDescriptorsDetails[index][1];
localGlobal.properties[PoisoningFreeMap_js_1.SetSymbol](descriptorName, descriptor);
if (typeof descriptorName === 'symbol') {
continue;
}
const subGlobalName = currentDepth !== 0 ? name + '.' + SString(descriptorName) : SString(descriptorName);
const newLastRootInPath = currentDepth <= 1 ? name : lastRootInPath;
nextCaptures[PoisoningFreeArray_js_1.PushSymbol]({
instance: descriptor.value,
name: subGlobalName,
currentDepth: currentDepth + 1,
lastRootInPath: newLastRootInPath,
});
}
}
return knownGlobals;
}