cts / src /types.ts
AlekseyCalvin's picture
Upload 119 files
59f93ff verified
Raw
History Blame Contribute Delete
16.3 kB
// types.ts — Complete type declarations for Calliope_TS pipeline
// Reflects McAleese’s class diagrams (Figure 14) and additional phonological /
// metrical types required by stress, phonological hierarchy, scansion, and Scandroid modules.
/**
* Stress levels in McAleese’s relative system, in ascending order
* `x < w < n < m < s`. `x` is the "Zero Provision" tier (Hayes; Lerdahl &
* Jackendoff 1983): a level *weaker than a stressless overt syllable*, borne by
* maximally-reduced clitics (the/a/of/and…) and unfilled positions.
*/
export type StressLevel = 'x' | 'w' | 'n' | 'm' | 's';
/** A single syllable within a word, with phonetic and stress information */
export interface Syllable {
text: string; // the orthographic syllable (or entire word if unsplit)
phones: string; // CMU phonetic transcription (per-syllable ARPAbet)
weight?: 'H' | 'L'; // syllable weight (Heavy/Light)
stress: number; // numeric stress from CMU; modified by compound + nuclear rules
lexicalStress?: number; // stress before nuclear rule; used for relative mapping / meter detection
relativeStress?: StressLevel; // assigned after phrase‑stress rules and relative adjustment
extrametrical?: 'morphological' | 'light_noun' | 'derivational'; // extrametricality classification
}
/** Represents a word in the dependency‑parse graph */
export interface ClsWord {
index: number; // 1‑based index in the sentence (matching Antelope’s XML)
lexicalClass: string; // POS tag, e.g., 'VBD', 'NN', 'PRP'
lexicalDetails: string; // additional morphological info (empty if none)
lexicalPlural: boolean; // true if plural
position: string; // textual position (not always used)
word: string; // the surface form of the word (case-normalised for lookups:
// a sentence-initial capital is lowered unless proper noun)
displayWord?: string; // the ORIGINAL surface form when it differs from `word`
// (set by the parser's de-capitalisation) — what reports
// and the phonopoetics show to the reader
absoluteIndex: number; // 0‑based index among all words in the text
isContent: boolean;
// extended properties
syllables: Syllable[]; // array of syllables for the word
morphSuffix?: string; // productive suffix split off for OOV stress (e.g. 'est'); guides display syllabification
morphPrefix?: string; // productive prefix split off for OOV stress (e.g. 'dis'); guides display syllabification
phraseStress: number; // numeric phrase‑level stress after Nuclear Stress Rule
dependency?: ClsDependency; // back‑reference to dependency edge (if any)
node?: ClsNode; // back‑reference to the constituent node (if any)
// ─── Calliope engine substrate (additive; ignored by the legacy/Clio path) ───
canonicalRel?: string; // normalised Scenario relation (NOMD/AMOD/VPRT/DOBJ/IOBJ/OBL/…)
isPersonName?: boolean; // token is in the `humannames` list (proper noun = person)
isPlaceName?: boolean; // token is in the `cities-list` list (proper name = place)
// ─── Wagner/Krifka substrate (additive; 2026-06-29) ───
featsMap?: Record<string, string>; // UD morphological FEATS parsed from lexicalDetails
// (VerbForm/Voice/PronType/Number/Definite/Degree/Tense/…)
discourseGiven?: boolean; // a content word repeated from an earlier line of the same
// stanza — set only by the optional stanza-givenness pass
// (analyzeStanzas / analyzeReadingDocument), never single-line
coordinateGiven?: boolean; // a content word whose lemma is repeated as the HEAD of a
// coordinate structure within the same line ("young blood and
// high blood" → the second "blood" is anaphorically given;
// contrastive focus falls on the modifier "high"). Set by the
// relativiser's coordinate-givenness pre-pass.
rhymeFocal?: boolean; // a line-final FUNCTION word that carries a strong end-rhyme
// with a stressed (content) line-final elsewhere in the stanza
// ("…one of THREE" / "…stopp'st thou ME") — the rhyme template
// transfers a beat. Set only by the stanza rhyme-fellow pass
// (analyzeStanzas / analyzeReadingDocument), never single-line.
acuteSyllable?: number; // syllable index carrying the poet's explicit ACUTE diacritic
// ("Milésien") — an overriding stress cue: the lexical primary
// moves here, and the surface grade never sinks below 'm'.
// Set by assignLexicalStress; honoured at the very end of
// applySurfacePostProcessing, after every demotion pass.
}
/** A typed dependency edge between two words (as in Antelope’s XML) */
export interface ClsDependency {
index: number; // 1‑based dependency index
governorIndex: number; // word index of the governor (head)
dependentIndex: number; // word index of the dependent
dependentType: string; // type label: 'aux','nsubj','dobj','prep','det','poss','possessive','pobj',…
governorName: string; // surface form of the governor
dependentName: string; // surface form of the dependent
governor: ClsWord; // reference to the governor word object
dependent: ClsWord; // reference to the dependent word object
}
/** A constituent node in the parse tree (mirrors Figure 14) */
export interface ClsNode {
index: string; // node identifier, e.g., '1', '1.2'
nodeName: string; // label (e.g., 'SQ', 'NP', 'VP', 'PP', or a word index)
parent: ClsNode | null; // parent node, null for root
contains: (ClsNode | ClsWord)[]; // children: either sub‑nodes or words
}
/** A single parsed sentence */
export interface ClsSentence {
index: number; // sentence number (1‑based)
nodes: ClsNode | null; // root node of the parse tree
dependencies: ClsDependency[]; // all dependency edges in this sentence
words: ClsWord[]; // word objects in order
xml: string; // serialised XML representation (optional)
}
/** Top‑level document containing parsed sentences */
export interface ClsDocument {
sentences: ClsSentence[]; // list of parsed sentences
xml: string; // full XML document (optional)
}
// ─── Phonological Hierarchy (CP, PP, IU) ────────────────────────────
/** A clitic group: one content word plus its attached function words */
export interface CliticGroup {
tokens: ClsWord[];
}
/** A phonological phrase: one or more clitic groups related syntactically */
export interface PhonologicalPhrase {
cliticGroups: CliticGroup[];
}
/** An intonational unit: one or more phonological phrases bounded by punctuation/line‑end */
export interface IntonationalUnit {
phonologicalPhrases: PhonologicalPhrase[];
}
// ─── Metre‑ and scansion‑related types ─────────────────────────────
/** Recognised metre names */
export type MetreName =
| 'iambic'
| 'trochaic'
| 'spondaic'
| 'pyrrhic'
| 'anapestic'
| 'dactylic'
| 'amphibrachic'
| 'bacchic';
/** Definition of a metre candidate: its foot shape and syllable count per foot */
export interface MetreCandidate {
name: MetreName;
foot: string; // e.g., 'ws', 'sw', 'wws'
syllableCount: number; // number of syllables in one foot (2 or 3)
}
/** A key‑stress pattern extracted from one unit of the phonological hierarchy */
export interface KeyStress {
unitType: 'PW' | 'CP' | 'PP' | 'IU'; // type of prosodic unit
pattern: string; // stress pattern, e.g., 'ws', 'sw', 'wsw'
weight: number; // importance weight (1–3) as per McAleese’s scoring
positions: number[]; // global syllable indices involved in this key stress
}
/** Result of scansion for a single line */
export interface ScansionResult {
meter: MetreName | 'free verse'; // identified metre, or free verse if below threshold
scansion: string; // the foot‑delimited scansion string, e.g., "ws|ws|ws|ws|ws"
certainty: number; // percentage of maximum possible weighted score
weightScore: number; // actual accumulated weight
maxPossibleWeight: number; // theoretical maximum weight for the line
algorithm?: string; // optional, to distinguish Phonological vs Scandroid results
}
/** One candidate meter's overall fit score (internal composite, not a probability) */
export interface MeterScore {
meter: MetreName | 'free verse';
score: number; // scoreMeters' finalScore — a relative fit score, higher = better
}
/** Detailed phonological scansion for a single line */
export interface PhonologicalScansionDetail {
all: string; // hierarchical string, e.g. "<{[nm/ws\n]}mn/sw\]m]}>"
keyStresses: string; // key‑stress string, e.g. "<{[xx/ws\n]}xx/sw\]m]}>"
meter: string; // e.g. "iambic pentameter"
meterName: MetreName | 'free verse'; // enum value for tests
footCount: number; // e.g. 5
summary: string; // e.g. "IU=1 PP=1 PW=1" counts per metre direction
scansion: string; // foot‑separated, e.g. "xx/ws|nx/xs/wm"
certainty: number; // 0‑100
weightScore: number;
maxPossibleWeight: number;
ranking?: MeterScore[]; // candidate meters ranked by fit score (best first); optional
consensusMeter?: string; // set by applyStanzaConsensus when this line's standalone meter
// diverges from, yet closely fits, the stanza's dominant meter.
// The continuity-rename pass (index.ts) then normally CONVERTS
// this annotation: the line adopts the dominant meter as its BASE
// reading (meter/scansion/footCount/certainty re-fitted under it),
// consensusMeter is cleared, and standaloneMeter records the
// numerically-best standalone reading. consensusMeter survives
// only when the forced re-fit fails.
standaloneMeter?: string; // the line's numerically best standalone meter (e.g. "dactylic
// tetrameter"), kept when stanza/poem continuity renamed the base
// reading to the dominant meter.
rhythmNote?: string; // non-classical rhythm classification (Russian-metrics taxonomy):
// "4-ictus dolnik", "3-ictus taktovik", "4-beat accentual",
// "alternating 4·3-ictus accentual" — set at stanza level when
// beat counts are regular but syllable counts vary and no
// classical meter dominates; or per-line to refine a free-verse
// reading. NOT a form verdict: "ballad" etc. belong to the
// rhyme-aware form layer (rhyme.ts).
metricalityNote?: string; // advisory prose-likeness hedge (scansion.ts), set when
// a long, non-committal, weak-fit line reads as plausible
// prose: "No consistent metered rhythm(s) discerned. …".
// Display-only — never alters meter/scansion/certainty.
rhyme?: { // rhyme annotation (rhyme.ts), LYRICAL-compatible typology.
// Letters are assigned POEM-WIDE (a rhyme sound keeps its
// letter across stanza breaks), in reading order.
endWord: string;
letter: string; // END-rhyme scheme letter 'A'/'B'/…, or '·' when unrhymed
type?: string; // perfect/rich/family/assonant/consonant/augmented/
// diminished/wrenched/eye/identical
matchedLine?: number; // 0-based poem line index this end-rhyme first binds to
internal?: { // pre-caesural INTERNAL rhymes on this line (strong-tier
// only), in left-to-right order; share the poem-wide
// letter space with the end rhymes.
word: string;
letter: string;
type?: string;
}[];
notation?: string; // assembled scheme cell: internal letters parenthesised
// then the end letter — e.g. "(A)B", "(C)C", "A", "·".
};
formNote?: string; // stanza/poem FORM verdict (rhyme-aware): "ballad stanza
// (ABCB, 4·3)", "blank verse", "Shakespearean Sonnet",
// "terza rima (ABA BCB CDC…)", "limerick"…
}
/** Complete per‑line result from the pipeline */
export interface LineResult {
sentence: ClsSentence; // parsed sentence with words, dependencies, nodes
phonologicalHierarchy: IntonationalUnit[]; // CP/PP/IU structure
keyStresses: KeyStress[]; // extracted key patterns with weights
phonologicalScansion: PhonologicalScansionDetail; // scansion via phonological scoring
// Charles Hartman's Scandroid (2005) run as a genuinely INDEPENDENT second
// opinion: its own dictionary, its own syllabifier, its own two iambic
// algorithms and its own anapestic engine, working ONLY from the raw line
// text (src/scandroidNative/). Never derived from anything above. This is
// the Calliope (main) pipeline's field.
scandroidNative?: import('./scandroidNative/engine.js').ScandroidNativeLineResult;
// Clio (the frozen legacy pipeline, src/clio/) still derives its Scandroid
// comparison from Calliope-style stress grades via its own untouched
// src/clio/scandroid.ts — kept here only so Clio's frozen code continues to
// compile; the main pipeline never sets these.
scandroidCorral?: ScansionResult;
scandroidMaximise?: ScansionResult;
}
// ─── Display formatting types ──────────────────────────────────────
/** Per-syllable information for display rendering */
export interface SyllableDisplayEntry {
wordText: string;
sylText: string; // orthographic text of this syllable
sylIndex: number; // 0‑based index within the word
sylCount: number; // total syllables in the word
relativeStress: StressLevel;
globalIndex: number;
wordIndex: number; // 0‑based index among non-punctuation words
}
/** A single foot in the display, mapping scansion pattern to its syllables */
export interface FootDisplayEntry {
footIndex: number;
footPattern: string; // raw foot pattern from scansion, e.g., 'ws', '-ms'
syllables: SyllableDisplayEntry[];
}
/** All formatted display representations for a single line */
export interface FormattedDisplay {
originalText: string;
diacriticText: string;
uppercaseText: string;
ansiText: string;
sylColoredText: string;
footAligned: string;
syllableBreakdown: string;
}
/** Options controlling display formatting */
export interface DisplayOptions {
ansi: boolean;
diacritics: boolean;
footAligned: boolean;
verbose: boolean;
phrasal: boolean;
}