def lockfile() -> CoursierResolvedLockfile:

    # Calculate transitive deps
    transitive_ = {(i, k) for i, j in direct.items() for k in j}
    while True:
        old_len = len(transitive_)
        transitive_ |= {(i, k) for i, j in transitive_ for k in direct[j]}
        if old_len == len(transitive_):
            break
    transitive = DefaultDict(set)
    for (i, j) in transitive_:
        transitive[i].add(j)

    entries = (
        CoursierLockfileEntry(
            coord=coord,
            file_name=f"{coord.artifact}.jar",
            direct_dependencies=Coordinates(direct[coord]),
            dependencies=Coordinates(transitive[coord]),
            file_digest=mock.Mock(),
        )
        for coord in direct
    )

    return CoursierResolvedLockfile(entries=tuple(entries))