{"version":3,"names":["isJest","runOnUI","isSharedValue","IS_JEST","createMapperRegistry","mappers","Map","sortedMappers","runRequested","processingMappers","updateMappersOrder","pre","forEach","mapper","outputs","output","preMappers","get","undefined","set","push","visited","Set","newOrder","dfs","add","input","inputs","preMapper","has","mapperRun","size","length","dirty","worklet","maybeRequestUpdates","requestAnimationFrame","queueMicrotask","extractInputs","resultArray","Array","isArray","Object","getPrototypeOf","prototype","element","values","start","mapperID","id","sv","addListener","stop","delete","removeListener","MAPPER_ID","startMapper","arguments","mapperRegistry","global","__mapperRegistry","stopMapper"],"sources":["mappers.ts"],"sourcesContent":["'use strict';\nimport type {\n MapperRawInputs,\n MapperOutputs,\n SharedValue,\n} from './commonTypes';\nimport { isJest } from './PlatformChecker';\nimport { runOnUI } from './threads';\nimport { isSharedValue } from './isSharedValue';\n\nconst IS_JEST = isJest();\n\ntype MapperExtractedInputs = SharedValue[];\n\ntype Mapper = {\n id: number;\n dirty: boolean;\n worklet: () => void;\n inputs: MapperExtractedInputs;\n outputs?: MapperOutputs;\n};\n\nfunction createMapperRegistry() {\n 'worklet';\n const mappers = new Map();\n let sortedMappers: Mapper[] = [];\n\n let runRequested = false;\n let processingMappers = false;\n\n function updateMappersOrder() {\n // sort mappers topologically\n // the algorithm here takes adventage of a fact that the topological order\n // of a transposed graph is a reverse topological order of the original graph\n // The graph in our case consists of mappers and an edge between two mappers\n // A and B exists if there is a shared value that's on A's output lists and on\n // B's input list.\n //\n // We don't need however to calculate that graph as it is easier to work with\n // the transposed version of it that can be calculated ad-hoc. For the transposed\n // version to be traversed we use \"pre\" map that maps share value to mappers that\n // output that shared value. Then we can infer all the outgoing edges for a given\n // mapper simply by scanning it's input list and checking if any of the shared values\n // from that list exists in the \"pre\" map. If they do, then we have an edge between\n // that mapper and the mappers from the \"pre\" list for the given shared value.\n //\n // For topological sorting we use a dfs-based approach that requires the graph to\n // be traversed in dfs order and each node after being processed lands at the\n // beginning of the topological order list. Since we traverse a transposed graph,\n // instead of reversing that order we can use a normal array and push processed\n // mappers to the end. There is no need to reverse that array after we are done.\n const pre = new Map(); // map from sv -> mapper that outputs that sv\n mappers.forEach((mapper) => {\n if (mapper.outputs) {\n for (const output of mapper.outputs) {\n const preMappers = pre.get(output);\n if (preMappers === undefined) {\n pre.set(output, [mapper]);\n } else {\n preMappers.push(mapper);\n }\n }\n }\n });\n const visited = new Set();\n const newOrder: Mapper[] = [];\n function dfs(mapper: Mapper) {\n visited.add(mapper);\n for (const input of mapper.inputs) {\n const preMappers = pre.get(input);\n if (preMappers) {\n for (const preMapper of preMappers) {\n if (!visited.has(preMapper)) {\n dfs(preMapper);\n }\n }\n }\n }\n newOrder.push(mapper);\n }\n mappers.forEach((mapper) => {\n if (!visited.has(mapper)) {\n dfs(mapper);\n }\n });\n sortedMappers = newOrder;\n }\n\n function mapperRun() {\n runRequested = false;\n if (processingMappers) {\n return;\n }\n try {\n processingMappers = true;\n if (mappers.size !== sortedMappers.length) {\n updateMappersOrder();\n }\n for (const mapper of sortedMappers) {\n if (mapper.dirty) {\n mapper.dirty = false;\n mapper.worklet();\n }\n }\n } finally {\n processingMappers = false;\n }\n }\n\n function maybeRequestUpdates() {\n if (IS_JEST) {\n // On Jest environment we avoid using queueMicrotask as that'd require test\n // to advance the clock manually. This on other hand would require tests\n // to know how many times mappers need to run. As we don't want tests to\n // make any assumptions on that number it is easier to execute mappers\n // immediately for testing purposes and only expect test to advance timers\n // if they want to make any assertions on the effects of animations being run.\n mapperRun();\n } else if (!runRequested) {\n if (processingMappers) {\n // In general, we should avoid having mappers trigger updates as this may\n // result in unpredictable behavior. Specifically, the updated value can\n // be read by mappers that run later in the same frame but previous mappers\n // would access the old value. Updating mappers during the mapper-run phase\n // breaks the order in which we should execute the mappers. However, doing\n // that is still a possibility and there are some instances where people use\n // the API in that way, hence we need to prevent mapper-run phase falling into\n // an infinite loop. We do that by detecting when mapper-run is requested while\n // we are already in mapper-run phase, and in that case we use `requestAnimationFrame`\n // instead of `queueMicrotask` which will schedule mapper run for the next\n // frame instead of queuing another set of updates in the same frame.\n requestAnimationFrame(mapperRun);\n } else {\n queueMicrotask(mapperRun);\n }\n runRequested = true;\n }\n }\n\n function extractInputs(\n inputs: unknown,\n resultArray: MapperExtractedInputs\n ): MapperExtractedInputs {\n if (Array.isArray(inputs)) {\n for (const input of inputs) {\n input && extractInputs(input, resultArray);\n }\n } else if (isSharedValue(inputs)) {\n resultArray.push(inputs);\n } else if (Object.getPrototypeOf(inputs) === Object.prototype) {\n // we only extract inputs recursively from \"plain\" objects here, if object\n // is of a derivative class (e.g. HostObject on web, or Map) we don't scan\n // it recursively\n for (const element of Object.values(inputs as Record)) {\n element && extractInputs(element, resultArray);\n }\n }\n return resultArray;\n }\n\n return {\n start: (\n mapperID: number,\n worklet: () => void,\n inputs: MapperRawInputs,\n outputs?: MapperOutputs\n ) => {\n const mapper: Mapper = {\n id: mapperID,\n dirty: true,\n worklet,\n inputs: extractInputs(inputs, []),\n outputs,\n };\n mappers.set(mapper.id, mapper);\n sortedMappers = [];\n for (const sv of mapper.inputs) {\n sv.addListener(mapper.id, () => {\n mapper.dirty = true;\n maybeRequestUpdates();\n });\n }\n maybeRequestUpdates();\n },\n stop: (mapperID: number) => {\n const mapper = mappers.get(mapperID);\n if (mapper) {\n mappers.delete(mapper.id);\n sortedMappers = [];\n for (const sv of mapper.inputs) {\n sv.removeListener(mapper.id);\n }\n }\n },\n };\n}\n\nlet MAPPER_ID = 9999;\n\nexport function startMapper(\n worklet: () => void,\n inputs: MapperRawInputs = [],\n outputs: MapperOutputs = []\n): number {\n const mapperID = (MAPPER_ID += 1);\n\n runOnUI(() => {\n let mapperRegistry = global.__mapperRegistry;\n if (mapperRegistry === undefined) {\n mapperRegistry = global.__mapperRegistry = createMapperRegistry();\n }\n mapperRegistry.start(mapperID, worklet, inputs, outputs);\n })();\n\n return mapperID;\n}\n\nexport function stopMapper(mapperID: number): void {\n runOnUI(() => {\n const mapperRegistry = global.__mapperRegistry;\n mapperRegistry?.stop(mapperID);\n })();\n}\n"],"mappings":"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"}