app/components/procedure-primers.tsx
79 lines and 12 functions in DrDustinEdwards/dustinedwards-info, at commit 1590ba4 on 2026-10-24. This file on GitHub.
Functions
| Function | Lines | Complexity | Covered | CRAP | Mutation |
|---|---|---|---|---|---|
| ProcedurePrimers | 15 to 80 | 9 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:17> | 17 to 17 | 2 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| productOf | 20 to 25 | 4 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:23> | 23 to 23 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:23> | 23 to 23 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:24> | 24 to 24 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:26> | 26 to 26 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:28> | 28 to 28 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:29> | 29 to 29 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:46> | 46 to 56 | 11 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:63> | 63 to 68 | 2 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:69> | 69 to 69 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
Imports
It imports app/kb/procedures/render.mjs, app/kb/registry/align.mjs, app/kb/registry/primer.mjs, app/kb/registry/tm.mjs. Imported by app/components/procedure.tsx.
Source
import { productsForRows } from "~/kb/registry/align.mjs";
import { primerFacts } from "~/kb/registry/primer.mjs";
import { NEB_TM_CALCULATOR, tmStatement } from "~/kb/registry/tm.mjs";
import type { ProcedureRecord } from "~/kb/procedures/render.mjs";
/**
* The primers a protocol uses, drawn from the record, which carries the lab registry's facts about each (docs/REGISTRY.md):
* the sequence is stored once, in the registry, and every page of the protocol prints that one. Each primer is also a page of
* its own under /research/lab/primers, with the reverse complement and the facts computed from the sequence. The bench
* sheet prints the same table without the estimate and its note, since it is for working from.
*
* The Tm is an estimate for comparing primers, never an annealing temperature, and the note
* says where an annealing temperature for a polymerase comes from.
*/
export function ProcedurePrimers({ record, brief = false }: { record: ProcedureRecord; brief?: boolean }) {
if (record.primers.length === 0) return null;
const rows = record.primers.map((p) => ({ ...p, facts: p.sequence ? primerFacts(p.sequence) : null }));
// A pair's product is computed from where its primers bind the reference they share (docs/REGISTRY.md), never typed.
const products = productsForRows(record.primers);
const productOf = (id: string) => {
const pair = products.get(id);
if (!pair) return "";
const sizes = [...new Set(pair.products.map((p) => p.length))].map((n) => `${n} bp`).join(" or ");
return pair.products.length > 1 && new Set(pair.products.map((p) => p.length)).size === 1 ? `${sizes} at ${pair.products.length} sites` : sizes;
};
const references = [...new Set([...products.values()].map((pair) => pair.reference))];
const showProduct = products.size > 0;
const showSet = rows.some((p) => p.set);
const showTm = !brief && rows.some((p) => p.facts?.tm != null);
return (
<>
<div className="table-scroll">
<table className="procedure-primers">
<thead>
<tr>
<th scope="col">Primer</th>
{showSet ? <th scope="col">Set</th> : null}
<th scope="col">Direction</th>
<th scope="col">Sequence (5′ to 3′)</th>
{brief ? null : <th scope="col">Length (nt)</th>}
{showTm ? <th scope="col">Tm estimate (°C)</th> : null}
{showProduct ? <th scope="col">Product (computed)</th> : null}
</tr>
</thead>
<tbody>
{rows.map((p) => (
<tr key={p.id}>
<th scope="row">{brief ? p.name : <a href={`/research/lab/primers/${p.id}`}>{p.name}</a>}</th>
{showSet ? <td>{p.set ?? ""}</td> : null}
<td>{p.direction ?? ""}</td>
<td>{p.sequence ? <code className="registry-seq">{p.sequence}</code> : ""}</td>
{brief ? null : <td>{p.facts?.length ?? ""}</td>}
{showTm ? <td>{p.facts?.tm ?? ""}</td> : null}
{showProduct ? <td>{productOf(p.id)}</td> : null}
</tr>
))}
</tbody>
</table>
</div>
{references.length > 0 ? (
<p className="procedure-primers-note">
Product sizes are computed from where the primers bind{" "}
{references.map((reference, i) => (
<span key={reference.id}>
{i > 0 ? ", " : ""}
<a href={`https://www.ncbi.nlm.nih.gov/nuccore/${reference.accession}`}>{reference.id}</a>
</span>
))}{" "}
({references.map((reference) => reference.description).join("; ")}), in the accession’s own coordinates.
</p>
) : null}
{brief ? null : (
<p className="procedure-primers-note">
{tmStatement()} The Tm estimate is not an annealing temperature. For the annealing temperature of a particular polymerase,
use the <a href={NEB_TM_CALCULATOR.url}>{NEB_TM_CALCULATOR.name}</a>.
</p>
)}
</>
);
}