grafast
Version:
Cutting edge GraphQL planning and execution engine
685 lines • 30.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StepTracker = void 0;
const constants_ts_1 = require("../constants.js");
const dev_ts_1 = require("../dev.js");
const inspect_ts_1 = require("../inspect.js");
const step_ts_1 = require("../step.js");
const utils_ts_1 = require("../utils.js");
const lock_ts_1 = require("./lock.js");
/**
* This class keeps track of all of our steps, and the dependencies between
* steps and other steps, layer plans and steps, and output plans and steps.
*
* When a step is replaced by another step, all the dependencies are updated
* such that the replaced step simply evaporates.
*
* @internal
*/
class StepTracker {
constructor(operationPlan) {
/** @internal */
this.stepCount = 0;
/** @internal */
this.lockedStepCount = 0;
/** @internal */
this.activeSteps = new Set();
/** @internal */
this.stepById = [];
/** @internal */
this.aliasesById = [];
/** @internal */
this.stepsWithNoDependenciesByConstructor = new Map();
/** @internal */
this.internalDependencies = new Set();
/** @internal */
this.outputPlansByRootStep = new Map();
/** @internal */
this.layerPlansByRootStep = new Map();
/** @internal */
this.layerPlansByParentStep = new Map();
/** @internal */
this.layerPlansByDependentStep = new Map();
/** @internal */
this.layerPlans = [];
/**
* All the OutputPlans that were created to allow a more efficient
* walkOutputPlans implementation.
*
* @internal
*/
this.allOutputPlans = [];
this.nextStepIdToDeduplicate = 0;
this.operationPlan = operationPlan;
}
newStepsSince(oldStepCount) {
return this.stepById.slice(oldStepCount);
}
forbid(key) {
this[key] = () => {
throw new Error(`StepTracker.${key}(...) is forbidden after 'finalize' phase`);
};
}
/** Called when OperationPlan enters finalize phase. */
finalizeSteps() {
this.forbid("addStep");
this.forbid("addLayerPlan");
this.forbid("addOutputPlan");
this.forbid("deleteLayerPlan");
this.forbid("addStepDependency");
this.forbid("setLayerPlanRootStep");
this.forbid("replaceStep");
}
/** Called when OperationPlan is about to finalize the output plans. */
finalizeOutputPlans() {
this.forbid("setOutputPlanRootStep");
}
addStep($step) {
const stepId = this.stepCount++;
this.activeSteps.add($step);
const ctor = $step.constructor;
let stepsWithNoDependencies = this.stepsWithNoDependenciesByConstructor.get(ctor);
if (!stepsWithNoDependencies) {
stepsWithNoDependencies ??= new Set();
this.stepsWithNoDependenciesByConstructor.set(ctor, stepsWithNoDependencies);
}
stepsWithNoDependencies.add($step);
this.stepById[stepId] = $step;
this.aliasesById[stepId] = undefined;
this.addStepToItsLayerPlan($step);
return stepId;
}
/**
* @internal
*/
addLayerPlan(layerPlan) {
const id = this.layerPlans.push(layerPlan) - 1;
switch (layerPlan.reason.type) {
case "root":
case "subscription":
case "mutationField":
case "polymorphicPartition":
case "defer": {
break;
}
case "nullableBoundary":
case "listItem":
case "polymorphic": {
const store = this.layerPlansByParentStep.get(layerPlan.reason.parentStep);
if (store !== undefined) {
store.add(layerPlan);
}
else {
const layerPlans = new Set();
layerPlans.add(layerPlan);
this.layerPlansByParentStep.set(layerPlan.reason.parentStep, layerPlans);
}
break;
}
case "subroutine": {
const parent = layerPlan.reason.parentStep;
if (parent[constants_ts_1.$$subroutine] !== null) {
throw new Error(`Steps may currently only have one subroutine. If you have need for a step with multiple subroutines, please get in touch.`);
}
parent[constants_ts_1.$$subroutine] =
layerPlan;
break;
}
case "combined": {
break;
}
default: {
const never = layerPlan.reason;
throw new Error(`Unexpected layerPlan reason ${never.type}`);
}
}
return id;
}
/**
* @internal
*/
addOutputPlan(outputPlan) {
if (dev_ts_1.isDev && !this.activeSteps.has(outputPlan.rootStep)) {
throw new Error(`GrafastInternalError<84485250-c4f3-4175-ab0c-360e073fa69f>: Root step '${outputPlan.rootStep}' is not active; perhaps it was replaced (replacement: ${this.getStepById(outputPlan.rootStep.id)})`);
}
this.allOutputPlans.push(outputPlan);
const store = this.outputPlansByRootStep.get(outputPlan.rootStep);
if (store !== undefined) {
store.add(outputPlan);
}
else {
const outputPlans = new Set();
outputPlans.add(outputPlan);
this.outputPlansByRootStep.set(outputPlan.rootStep, outputPlans);
}
}
/**
* HIGHLY EXPERIMENTAL!
*
* @internal
*/
deleteLayerPlan(layerPlan) {
if (dev_ts_1.isDev) {
if (layerPlan.children.length > 0) {
throw new Error("This layer plan has children... should we really be deleting it?!");
}
this.allOutputPlans.forEach((o) => {
if (o.layerPlan === layerPlan) {
throw new Error("An output plan depends on this layer plan... should we really be deleting it?!");
}
});
}
this.layerPlans[layerPlan.id] = null;
// Remove layerPlan from its parent
if (layerPlan.reason.type === "root") {
// no action
}
else if (layerPlan.reason.type === "combined") {
for (const parentLayerPlan of layerPlan.reason.parentLayerPlans) {
const idx = parentLayerPlan.children.indexOf(layerPlan);
if (idx >= 0) {
parentLayerPlan.children.splice(idx, 1);
}
}
}
else {
const parentLayerPlan = layerPlan.reason.parentLayerPlan;
const idx = parentLayerPlan.children.indexOf(layerPlan);
if (idx >= 0) {
parentLayerPlan.children.splice(idx, 1);
}
}
// Remove references
const $root = layerPlan.rootStep;
if ($root) {
this.layerPlansByRootStep.get($root).delete(layerPlan);
}
if (layerPlan.reason.type !== "subroutine") {
const $parent = "parentStep" in layerPlan.reason ? layerPlan.reason.parentStep : null;
if ($parent) {
this.layerPlansByParentStep
.get($parent)
.delete(layerPlan);
}
}
if (layerPlan.reason.type === "combined") {
for (const combo of layerPlan.combinations) {
for (const source of combo.sources) {
const step = this.getStepById(source.stepId);
this.layerPlansByDependentStep
.get(step)
.delete(layerPlan);
}
}
}
// Remove all plans in this layer
const handled = new Set();
const handle = (step) => {
if (handled.has(step))
return;
handled.add(step);
// Handle dependents first
for (const dependent of step.dependents) {
if (dependent.step.layerPlan === layerPlan) {
handle(dependent.step);
}
}
this.eradicate(step);
};
for (const step of this.activeSteps) {
if (step.layerPlan === layerPlan) {
handle(step);
}
}
}
getStepById(id, allowUnset = false) {
const step = this.stepById[id];
if (!step && !allowUnset) {
throw new Error(`Illegal step access? Step with id ${id} doesn't exist`);
}
if (dev_ts_1.isDev) {
if (step && !this.activeSteps.has(step)) {
throw new Error(`${step} is not active, but we retrieved it from stepTracker.getStepById(${id}, ${allowUnset})`);
}
}
return step;
}
addStepDependency(raw$dependent, options) {
const $dependent = (0, utils_ts_1.sudo)(raw$dependent);
const $dependency = (0, utils_ts_1.sudo)(options.step);
if ($dependent === $dependency) {
throw new Error(`Step ${$dependent} cannot depend on itself!`);
}
if (!this.activeSteps.has($dependent)) {
throw new Error(`Cannot add ${$dependency} as a dependency of ${$dependent}; the latter is deleted! Explanation: https://err.red/gasdd#phase=${this.operationPlan.phase}&dependency=${encodeURIComponent(String($dependency))}&dependent=${encodeURIComponent(String($dependent))}&deleted=dependent`);
}
if (!this.activeSteps.has($dependency)) {
throw new Error(`Cannot add ${$dependency} as a dependency of ${$dependent}; the former is deleted! Explanation: https://err.red/gasdd#phase=${this.operationPlan.phase}&dependency=${encodeURIComponent(String($dependency))}&dependent=${encodeURIComponent(String($dependent))}&deleted=dependency`);
}
if ($dependent.isFinalized) {
throw new Error("You cannot add a dependency after the step is finalized.");
}
if (!($dependency instanceof step_ts_1.Step)) {
throw new Error(`Error occurred when adding dependency for '${$dependent}', value passed was not a step, it was '${(0, inspect_ts_1.inspect)($dependency)}' (phase = ${this.operationPlan.phase})`);
}
if (dev_ts_1.isDev) {
// Check that we can actually add this as a dependency
if (!$dependent.layerPlan.ancestry.includes($dependency.layerPlan)) {
throw new Error(
//console.error(
// This is not a GrafastInternalError
`Attempted to add '${$dependency}' (${$dependency.layerPlan}) as a dependency of '${$dependent}' (${$dependent.layerPlan}), but we cannot because that LayerPlan isn't an ancestor. (phase = ${this.operationPlan.phase})`);
}
}
if (!(0, utils_ts_1.stepAMayDependOnStepB)($dependent, $dependency)) {
if (dev_ts_1.isDev) {
if ($dependent.isFinalized) {
throw new Error(`${$dependent} is finalized and thus may not add a dependency on ${$dependency}.`);
}
if (!$dependency._isUnary &&
$dependent._isUnary &&
$dependent._isUnaryLocked) {
throw new Error(`Unary step ${$dependent} may not depend on non-unary step ${$dependency}.`);
}
if ((0, utils_ts_1.stepADependsOnStepB)($dependency, $dependent)) {
if ($dependency.implicitSideEffectStep) {
const reason = `This is likely an ordering issue in your plan resolver's code; be sure to create all steps that will be dependencies of a side effect step before creating the side effect step itself.`;
if ($dependent === $dependency.implicitSideEffectStep) {
throw new Error(`${$dependent} has side effects, so it may not depend on step ${$dependency} which was created afterwards and thus is implicitly dependent on it - this would form a cycle. ${reason}`);
}
if ((0, utils_ts_1.stepADependsOnStepB)($dependency.implicitSideEffectStep, $dependent)) {
throw new Error(`${$dependent} may not depend on ${$dependency} as the latter was created after ${$dependency.implicitSideEffectStep} (has side effects) which already depends on ${$dependent}; this would form a cycle. ${reason}`);
}
}
throw new Error(`${$dependent} may not depend on ${$dependency}, as doing so would form a dependency cycle.`);
}
}
throw new Error(`${$dependent} may not depend on ${$dependency} as it would create an invalid heirarchy (for example a cycle or an unreachable path through the graph).`);
}
const dependentDependencies = (0, utils_ts_1.writeableArray)($dependent.dependencies);
const dependentDependencyForbiddenFlags = (0, utils_ts_1.writeableArray)($dependent.dependencyForbiddenFlags);
const dependentDependencyOnReject = (0, utils_ts_1.writeableArray)($dependent.dependencyOnReject);
const dependentDependencyDataOnly = (0, utils_ts_1.writeableArray)($dependent.dependencyDataOnly);
const { skipDeduplication, acceptFlags = constants_ts_1.ALL_FLAGS & ~$dependent.defaultForbiddenFlags, onReject, dataOnly = false, } = options;
// When copying dependencies between classes, we might not want to
// deduplicate because we might refer to the dependency by its index. As
// such, we should only dedupe by default but allow opting out.
// TODO: change this to `!skipDeduplication`
if (skipDeduplication === false) {
const $searchForMe = options.step;
const existingIndex = dependentDependencies.indexOf($searchForMe);
if (existingIndex >= 0) {
return existingIndex;
}
}
if (!$dependency._isUnary && $dependent._isUnary) {
if ($dependent._isUnaryLocked) {
throw new Error(`Attempted to add non-unary step ${$dependency} as a dependency of ${$dependent}; but the latter is unary, so it cannot depend on batch steps`);
}
$dependent._isUnary = false;
}
const forbiddenFlags = constants_ts_1.ALL_FLAGS & ~(acceptFlags & $dependent.__trappableFlags);
this.stepsWithNoDependenciesByConstructor
.get($dependent.constructor)
?.delete($dependent);
const dependencyIndex = dependentDependencies.push($dependency) - 1;
dependentDependencyForbiddenFlags[dependencyIndex] = forbiddenFlags;
dependentDependencyOnReject[dependencyIndex] = onReject;
dependentDependencyDataOnly[dependencyIndex] = dataOnly;
(0, utils_ts_1.writeableArray)($dependency.dependents).push({
step: $dependent,
dependencyIndex,
});
return dependencyIndex;
}
addStepUnaryDependency($dependent, options) {
if (options.dataOnly) {
throw new Error(`${$dependent} attempted to add dataOnly unary dependency; this is not permitted.`);
}
const $dependency = options.step;
const { nonUnaryMessage = defaultNonUnaryMessage, ...rest } = options;
if (!$dependency._isUnary) {
throw new Error(nonUnaryMessage($dependent, $dependency));
}
$dependency._isUnaryLocked = true;
return this.addStepDependency($dependent, { ...rest, dataOnly: false });
}
setOutputPlanRootStep(outputPlan, $dependency) {
if (!this.activeSteps.has($dependency)) {
throw new Error(`Cannot add ${$dependency} to ${outputPlan} because it's deleted`);
}
const $existing = outputPlan.rootStep;
if ($existing) {
const outputPlansBy$existing = this.outputPlansByRootStep.get($existing);
if (!outputPlansBy$existing) {
throw new Error(`GrafastInternalError<f39690fc-f565-40d9-a781-e68a3bf5e84a>: ${outputPlan}.rootStep (${$existing}) isn't in 'outputPlansByRootStep'`);
}
outputPlansBy$existing.delete(outputPlan);
if (outputPlansBy$existing.size === 0) {
// PERF: Cleanup, tree shake, etc
}
}
outputPlan.rootStep = $dependency;
const store = this.outputPlansByRootStep.get($dependency);
if (store !== undefined) {
store.add(outputPlan);
}
else {
const outputPlans = new Set();
outputPlans.add(outputPlan);
this.outputPlansByRootStep.set($dependency, outputPlans);
}
}
setLayerPlanRootStep(layerPlan, $dependency) {
if (!this.activeSteps.has($dependency)) {
throw new Error(`Cannot add ${$dependency} to ${layerPlan} because it's deleted`);
}
const $existing = layerPlan.rootStep;
if ($existing) {
const layerPlansBy$existing = this.layerPlansByRootStep.get($existing);
if (!layerPlansBy$existing) {
throw new Error(`GrafastInternalError<7b5b7fe6-d403-48bd-a75f-1c9557b9a030>: ${layerPlan}.rootStep (${$existing}) isn't in 'layerPlansByRootStep'`);
}
layerPlansBy$existing.delete(layerPlan);
if (layerPlansBy$existing.size === 0) {
this.layerPlansByRootStep.delete($existing);
// PERF: Cleanup, tree shake, etc
}
}
layerPlan.rootStep = $dependency;
const store = this.layerPlansByRootStep.get($dependency);
if (store !== undefined) {
store.add(layerPlan);
}
else {
const layerPlans = new Set();
layerPlans.add(layerPlan);
this.layerPlansByRootStep.set($dependency, layerPlans);
}
}
/** @internal */
replaceStep($original, $replacement) {
if (!this.activeSteps.has($original)) {
// OPTIMIZE: seems like there's unnecessary work being done here.
// console.trace(`${$original} should be replaced with ${$replacement} but it's no longer alive`);
// Already handled
return;
}
// Replace all references to $original with $replacement
const oldAliases = this.aliasesById[$original.id];
const newAliases = this.aliasesById[$replacement.id] ?? [$replacement.id];
this.aliasesById[$replacement.id] = newAliases;
if (oldAliases !== undefined) {
for (const id of oldAliases) {
this.stepById[id] = $replacement;
newAliases.push(id);
}
this.aliasesById[$original.id] = undefined;
}
else {
this.stepById[$original.id] = $replacement;
newAliases.push($original.id);
}
{
// Transfer step dependents of $original to $replacement
const dependents = $original.dependents;
if (dependents.length > 0) {
const replacementDependents = (0, utils_ts_1.writeableArray)($replacement.dependents);
for (const dependent of dependents) {
(0, utils_ts_1.writeableArray)((0, utils_ts_1.sudo)(dependent.step).dependencies)[dependent.dependencyIndex] = $replacement;
replacementDependents.push(dependent);
}
$original.dependents = [];
}
}
{
// Convert root step of output plans from $original to $replacement
const outputPlans = this.outputPlansByRootStep.get($original);
if (outputPlans?.size) {
let outputPlansByReplacementStep = this.outputPlansByRootStep.get($replacement);
if (!outputPlansByReplacementStep) {
outputPlansByReplacementStep = new Set();
this.outputPlansByRootStep.set($replacement, outputPlansByReplacementStep);
}
for (const outputPlan of outputPlans) {
outputPlan.rootStep = $replacement;
outputPlansByReplacementStep.add(outputPlan);
}
outputPlans.clear();
}
}
{
// Convert root step of layer plans from $original to $replacement
const layerPlans = this.layerPlansByRootStep.get($original);
if (layerPlans?.size) {
let layerPlansByReplacementRootStep = this.layerPlansByRootStep.get($replacement);
if (!layerPlansByReplacementRootStep) {
layerPlansByReplacementRootStep = new Set();
this.layerPlansByRootStep.set($replacement, layerPlansByReplacementRootStep);
}
for (const layerPlan of layerPlans) {
layerPlan.rootStep = $replacement;
layerPlansByReplacementRootStep.add(layerPlan);
}
layerPlans.clear();
}
}
// Update combos
{
const layerPlans = this.layerPlansByDependentStep.get($original);
if (layerPlans?.size) {
let layerPlansByReplacementDependentStep = this.layerPlansByDependentStep.get($replacement);
if (!layerPlansByReplacementDependentStep) {
layerPlansByReplacementDependentStep = new Set();
this.layerPlansByDependentStep.set($replacement, layerPlansByReplacementDependentStep);
}
for (const layerPlan of layerPlans) {
for (const combo of layerPlan.combinations) {
for (const source of combo.sources) {
if (source.stepId === $original.id) {
source.stepId = $replacement.id;
}
}
}
layerPlansByReplacementDependentStep.add(layerPlan);
}
layerPlans.clear();
}
}
// NOTE: had to add the code ensuring all the layer plan parentStepId's
// existed to fix polymorphism, but it feels wrong. Should we be doing
// something different?
{
// Convert parent step of layer plans from $original to $replacement
const layerPlans = this.layerPlansByParentStep.get($original);
if (layerPlans?.size) {
let layerPlansByReplacementParentStep = this.layerPlansByParentStep.get($replacement);
if (!layerPlansByReplacementParentStep) {
layerPlansByReplacementParentStep = new Set();
this.layerPlansByParentStep.set($replacement, layerPlansByReplacementParentStep);
}
for (const layerPlan of layerPlans) {
layerPlan.reason.parentStep = $replacement;
layerPlansByReplacementParentStep.add(layerPlan);
}
layerPlans.clear();
}
}
// NOTE: I don't think side-effect plans need any special handling, since
// they cannot be deduplicated.
// NOTE: there may be more work required here for 'subprocedure' layerPlans
// (e.g. making sure their steps are retained), but it's not clear what
// work is necessary and we've not seen any issues from this yet.
// Remove this step (and perform localized tree-shaking)
this.eradicate($original);
}
treeShakeSteps() {
for (const $step of this.activeSteps) {
if (this.isNotNeeded($step)) {
this.eradicate($step);
}
}
}
/**
* Return true if this step can be tree-shaken.
*/
isNotNeeded($step) {
if ($step.dependents.length !== 0)
return false;
if ($step.hasSideEffects)
return false;
if (this.internalDependencies.has($step)) {
return false;
}
const s1 = this.outputPlansByRootStep.get($step);
if (s1 && s1.size !== 0)
return false;
const s2 = this.layerPlansByRootStep.get($step);
if (s2 && s2.size !== 0)
return false;
const s3 = this.layerPlansByParentStep.get($step);
if (s3 && s3.size !== 0)
return false;
const s4 = this.layerPlansByDependentStep.get($step);
if (s4 && s4.size !== 0)
return false;
return true;
}
/**
* Only for use during planField.
*/
purgeBackTo(count) {
const upper = this.stepCount;
const toRemove = new Set();
for (let i = count; i < upper; i++) {
const step = this.stepById[i];
if (step) {
toRemove.add(step);
}
}
const remove = (step) => {
if (this.stepById[step.id] !== step) {
return;
}
if (toRemove.has(step)) {
for (const dependent of step.dependents) {
if (dependent.step.id >= count) {
remove(dependent.step);
}
}
this.eradicate(step);
toRemove.delete(step);
}
};
for (const step of toRemove) {
remove(step);
}
}
/**
* ONLY CALL THIS IF NOTHING DEPENDS ON $original! It's intended to be called
* from `replaceStep` or from itself.
*
* This method removes $original from the various maps/sets/lists, and also
* removes the fact that it was dependent on other steps. If these other
* steps no longer have any dependents (steps, layer plans or output plans)
* then they can also be eradicated _except_ during the 'plan' phase.
*/
eradicate($original) {
if ($original[constants_ts_1.$$subroutine] !== null) {
this.deleteLayerPlan($original[constants_ts_1.$$subroutine]);
}
this.removeStepFromItsLayerPlan($original);
const oldAliases = this.aliasesById[$original.id];
if (oldAliases !== undefined) {
for (const id of oldAliases) {
// Nothing needs us, so set ourself null (DELIBERATELY BYPASSES TYPESCRIPT!)
this.stepById[id] = null;
}
this.aliasesById[$original.id] = undefined;
}
else if (this.stepById[$original.id] === $original) {
this.stepById[$original.id] = null;
}
// Since this step is being removed, it doesn't need its dependencies any more
const oldDependencies = (0, utils_ts_1.sudo)($original).dependencies;
for (const $dependency of oldDependencies) {
// $dependency is no longer a dependent of $original, since we're getting
// rid of $original
$dependency.dependents = $dependency.dependents.filter((dependent) => dependent.step !== $original);
// If we've done our first tree-shake, let's keep it tidy in here.
if (this.operationPlan.phase !== "plan" &&
this.isNotNeeded($dependency)) {
// Nothing depends on $dependency and it has no side effects - we can get rid of it!
this.eradicate($dependency);
}
}
// Ensure nothing depends on this step - steps, layer plans, output plans.
// This should already be the case, so we just do it in dev as a
// consistency check.
if (dev_ts_1.isDev) {
if ($original.dependents.length > 0) {
throw new Error(`${$original} eradicated, but it is needed by ${$original.dependents.map((d) => d.step)}`);
}
const outputPlansByRoot = this.outputPlansByRootStep.get($original);
if (outputPlansByRoot && outputPlansByRoot.size !== 0) {
throw new Error(`${$original} eradicated, but it is needed by ${[
...outputPlansByRoot,
]}`);
}
const layerPlansByRoot = this.layerPlansByRootStep.get($original);
if (layerPlansByRoot && layerPlansByRoot.size !== 0) {
throw new Error(`${$original} eradicated, but it is needed by ${[
...layerPlansByRoot,
]}`);
}
const layerPlansByParent = this.layerPlansByParentStep.get($original);
if (layerPlansByParent && layerPlansByParent.size !== 0) {
throw new Error(`${$original} eradicated, but it is needed by ${[
...layerPlansByParent,
]}`);
}
}
this.stepsWithNoDependenciesByConstructor
.get($original.constructor)
?.delete($original);
this.outputPlansByRootStep.delete($original);
this.layerPlansByRootStep.delete($original);
this.layerPlansByParentStep.delete($original);
this.activeSteps.delete($original);
// Referencing $original after this will likely cause errors.
$original.destroy();
}
moveStepToLayerPlan(step, targetLayerPlan) {
this.removeStepFromItsLayerPlan(step);
step.layerPlan = targetLayerPlan;
this.addStepToItsLayerPlan(step);
}
addStepToItsLayerPlan(step) {
const { layerPlan: { stepsByConstructor }, constructor, } = step;
let set = stepsByConstructor.get(constructor);
if (!set) {
set = new Set();
stepsByConstructor.set(constructor, set);
}
set.add(step);
}
removeStepFromItsLayerPlan(step) {
step.layerPlan.stepsByConstructor.get(step.constructor).delete(step);
}
lockNewSteps() {
if (!dev_ts_1.isDev)
return;
for (let i = this.lockedStepCount; i < this.stepCount; i++) {
const step = this.getStepById(i, true);
if (step && step.id === i) {
(0, lock_ts_1.lock)(step);
}
}
this.lockedStepCount = this.stepCount;
}
}
exports.StepTracker = StepTracker;
function defaultNonUnaryMessage($dependent, $dependency) {
return `${$dependent} attempted to create a unary step dependency on ${$dependency}, but that step is not unary. See https://err.red/gud`;
}
//# sourceMappingURL=StepTracker.js.map