/**
* @copyright Sister Software
* @license AGPL-3.0
* @author Teffen Ellis, et al.
*
* `po-box` slice recipe — synthetic PO box rows: tuples → {@link synthesizePoBoxRow} → aligned
* LabeledRow, plus optional self-contained US military/diplomatic rows (#517) at
* `--military-ratio`. Region is required EXCEPT region-less locales (NZ). Ported from
* scripts/build-po-box-slice.mjs.
*/
import { makeLcg } from "@mailwoman/core/utils"
import {
alignAndWrite,
readTuples,
sliceSourceID,
SYNTHETIC_TUPLE_LICENSE as LICENSE,
type CorpusRecipe,
} from "#recipes/scaffold"
import { synthesizeMilitaryPoBoxRow, synthesizePoBoxRow, type PoBoxBaseTuple } from "#synthesizers/po-box"
/**
* Slice recipe registered with the corpus builder — see the file header for the parse behaviour it exists to exercise,
* and `description` below for the surface form it generates.
*/
export const poBoxRecipe: CorpusRecipe = {
name: "po-box",
description: "PO box rows: tuples → synthesizePoBoxRow (+ optional US military/diplomatic rows)",
mode: "tuples",
options: [
{ flag: "--pmb-ratio
", description: "P(private-mailbox layout). Default 0.15" },
{ flag: "--military-ratio
", description: "P(emit one US military/diplomatic row per input, #517). Default 0" },
],
async run(opts, write) {
if (!opts.input) throw new Error("po-box recipe requires --input ")
const random = makeLcg(opts.seed)
const pmbRatio = opts.pmbRatio ?? 0.15
const militaryRatio = opts.militaryRatio ?? 0
// `--source-name` so a slice built for one class carries its own source label and its own dose. A
// military-only slice (`--variants 0 --military-ratio 1`) is otherwise indistinguishable from the
// leader-template rows in the mixture, and the two are dosed for different reasons (#517).
const source = opts.sourceName ?? "synth-po-box"
let read = 0
let emitted = 0
let skipped = 0
for await (const tuple of readTuples(opts.input)) {
read++
// Region required EXCEPT region-less locales (NZ: "Private Bag 12, Auckland 1010", #517).
const regionOptional = ["NZ", "NZL", "NEW ZEALAND"].includes(String(tuple.country || "").toUpperCase())
if (!tuple.locality || !tuple.postcode || !tuple.country || (!tuple.region && !regionOptional)) {
skipped++
continue
}
for (let v = 0; v < opts.variants; v++) {
const synth = synthesizePoBoxRow(tuple as PoBoxBaseTuple, { random, pmbRatio })
if (!synth) continue
const ok = alignAndWrite(
write,
{
raw: synth.raw,
components: synth.components,
country: tuple.country,
locale: synth.locale,
source,
source_id: sliceSourceID(source, {
locality: tuple.locality,
region: tuple.region,
postcode: tuple.postcode,
country: tuple.country,
v: String(v),
}),
corpus_version: "0.4.0",
license: LICENSE,
},
synth.template
)
if (ok) {
emitted++
} else {
skipped++
}
}
// US military/diplomatic rows (#517): self-contained, one per input line at --military-ratio.
// Default 0 → byte-stable (random() not called when off). US-only.
if (militaryRatio > 0 && random() < militaryRatio) {
const mil = synthesizeMilitaryPoBoxRow({ random })
const ok = alignAndWrite(
write,
{
raw: mil.raw,
components: mil.components,
country: "US",
locale: mil.locale,
source,
source_id: sliceSourceID(source, {
po_box: mil.components.po_box,
locality: mil.components.locality,
region: mil.components.region,
postcode: mil.components.postcode,
v: `mil${emitted}`,
}),
corpus_version: "0.4.0",
license: LICENSE,
},
mil.template
)
if (ok) {
emitted++
} else {
skipped++
}
}
}
return { read, emitted, skipped }
},
}