calliope-ts 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/.opencode/skills/calliope-ts/SKILL.md +74 -0
  3. package/LICENSE +201 -0
  4. package/README.md +485 -0
  5. package/dist/depfix.d.ts +13 -0
  6. package/dist/depfix.d.ts.map +1 -0
  7. package/dist/depfix.js +84 -0
  8. package/dist/display.d.ts +38 -0
  9. package/dist/display.d.ts.map +1 -0
  10. package/dist/display.js +890 -0
  11. package/dist/index.d.ts +50 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +504 -0
  14. package/dist/parser.d.ts +10 -0
  15. package/dist/parser.d.ts.map +1 -0
  16. package/dist/parser.js +688 -0
  17. package/dist/phonological.d.ts +41 -0
  18. package/dist/phonological.d.ts.map +1 -0
  19. package/dist/phonological.js +788 -0
  20. package/dist/rhyme.d.ts +26 -0
  21. package/dist/rhyme.d.ts.map +1 -0
  22. package/dist/rhyme.js +340 -0
  23. package/dist/scandroid.d.ts +17 -0
  24. package/dist/scandroid.d.ts.map +1 -0
  25. package/dist/scandroid.js +435 -0
  26. package/dist/scansion.d.ts +37 -0
  27. package/dist/scansion.d.ts.map +1 -0
  28. package/dist/scansion.js +1007 -0
  29. package/dist/scansion_debug.js +586 -0
  30. package/dist/stress.d.ts +32 -0
  31. package/dist/stress.d.ts.map +1 -0
  32. package/dist/stress.js +1372 -0
  33. package/dist/tagfix.d.ts +6 -0
  34. package/dist/tagfix.d.ts.map +1 -0
  35. package/dist/tagfix.js +101 -0
  36. package/dist/types.d.ts +173 -0
  37. package/dist/types.d.ts.map +1 -0
  38. package/dist/types.js +4 -0
  39. package/package.json +62 -0
  40. package/src/depfix.ts +88 -0
  41. package/src/display.ts +954 -0
  42. package/src/index.ts +541 -0
  43. package/src/parser.ts +837 -0
  44. package/src/phonological.ts +849 -0
  45. package/src/rhyme.ts +328 -0
  46. package/src/scandroid.ts +434 -0
  47. package/src/scansion.ts +1053 -0
  48. package/src/stress.ts +1381 -0
  49. package/src/tagfix.ts +104 -0
  50. package/src/types.ts +230 -0
@@ -0,0 +1,26 @@
1
+ import { LineResult } from './types.js';
2
+ export type RhymeTypeName = 'identical' | 'rich' | 'perfect' | 'family' | 'assonant' | 'consonant' | 'augmented' | 'diminished' | 'wrenched' | 'eye';
3
+ export interface RhymePair {
4
+ type: RhymeTypeName;
5
+ /** masculine (stress on final syllable) / feminine (penult) / dactylic (antepenult) */
6
+ structure?: 'masculine' | 'feminine' | 'dactylic';
7
+ }
8
+ /** Classify the rhyme relation between two line-end words (or null). */
9
+ export declare function classifyRhymePair(a: string, b: string): RhymePair | null;
10
+ export interface LineRhyme {
11
+ endWord: string;
12
+ letter: string;
13
+ type?: RhymeTypeName;
14
+ matchedLine?: number;
15
+ }
16
+ /** Detect a stanza's rhyme scheme from its line-end words. Strong rhymes
17
+ * bind; slant-tier rhymes bind only when no strong candidate exists. */
18
+ export declare function detectScheme(endWords: string[]): LineRhyme[];
19
+ /**
20
+ * Annotate rhyme letters/types (`detail.rhyme`) and form verdicts
21
+ * (`detail.formNote`) across a poem. Stanza forms are per-stanza; a poem-level
22
+ * form (sonnet, terza rima) overrides stanza notes. Annotation-only — no
23
+ * meter/scansion/certainty is touched.
24
+ */
25
+ export declare function applyRhymeAndForm(stanzas: LineResult[][]): void;
26
+ //# sourceMappingURL=rhyme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rhyme.d.ts","sourceRoot":"","sources":["../src/rhyme.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,UAAU,EAA8B,MAAM,YAAY,CAAC;AAIpE,MAAM,MAAM,aAAa,GACrB,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAC3C,UAAU,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,GACrD,UAAU,GAAG,KAAK,CAAC;AAEvB,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,aAAa,CAAC;IACpB,uFAAuF;IACvF,SAAS,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;CACnD;AA6DD,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAkDxE;AAMD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;yEACyE;AACzE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CA6C5D;AAyGD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,GAAG,IAAI,CAe/D"}
package/dist/rhyme.js ADDED
@@ -0,0 +1,340 @@
1
+ // rhyme.ts — Rhyme-pair classification, stanza rhyme-scheme detection, and
2
+ // poetic FORM identification.
3
+ //
4
+ // Rhyme typology follows the maintainer's LYRICAL app (meter_exemplars.ts
5
+ // RHYME_TYPES) so the two toolkits stay cross-compatible: perfect / rich /
6
+ // family / assonant / consonant / augmented / diminished / wrenched / eye /
7
+ // identical, with the structural qualifiers masculine / feminine / dactylic.
8
+ // Phonology comes from the augmented CMU dictionary (nounsing-pro); the
9
+ // orthographic (eye/wrenched) tier is a deliberately guarded fallback.
10
+ //
11
+ // FORM is a stanza/poem-level verdict (this is where "ballad" lives — a
12
+ // quatrain with ballad rhyme AND alternating 4·3 beats — NOT in the rhythm
13
+ // pass). Form names align with LYRICAL's FORM_REGISTRY where they overlap
14
+ // (Couplet, Triplet, Quatrain, Limerick, Petrarchan/Shakespearean Sonnet…).
15
+ import * as nounsing from 'nounsing-pro';
16
+ import { isPunctuation } from './parser.js';
17
+ import { ictusProfile } from './scansion.js';
18
+ const VOWEL_RE = /^(AA|AE|AH|AO|AW|AY|EH|ER|EY|IH|IY|OW|OY|UH|UW)/;
19
+ const PLOSIVES = new Set(['B', 'D', 'G', 'P', 'T', 'K']);
20
+ const FRICATIVES = new Set(['V', 'DH', 'Z', 'ZH', 'JH', 'F', 'TH', 'S', 'SH', 'CH', 'HH']);
21
+ const NASALS = new Set(['M', 'N', 'NG']);
22
+ const isVowelPhone = (p) => VOWEL_RE.test(p);
23
+ const base = (p) => p.replace(/[0-9]/g, '');
24
+ const sameFamily = (a, b) => (PLOSIVES.has(a) && PLOSIVES.has(b)) || (FRICATIVES.has(a) && FRICATIVES.has(b)) || (NASALS.has(a) && NASALS.has(b));
25
+ function phonesOf(word) {
26
+ const clean = word.toLowerCase().replace(/[^a-z']/g, '');
27
+ if (!clean)
28
+ return null;
29
+ try {
30
+ const ph = nounsing.firstPhonesForWord(clean);
31
+ if (typeof ph === 'string' && ph.length > 0)
32
+ return ph.split(' ');
33
+ }
34
+ catch { /* OOV */ }
35
+ return null;
36
+ }
37
+ /** Index of the LAST stressed (1/2) vowel; falls back to the last vowel. */
38
+ function lastStressedIdx(ph) {
39
+ let lastVowel = -1;
40
+ for (let i = ph.length - 1; i >= 0; i--) {
41
+ if (!isVowelPhone(ph[i]))
42
+ continue;
43
+ if (lastVowel < 0)
44
+ lastVowel = i;
45
+ if (/[12]$/.test(ph[i]))
46
+ return i;
47
+ }
48
+ return lastVowel;
49
+ }
50
+ /** masculine/feminine/dactylic from how many vowels FOLLOW the rhyming vowel. */
51
+ function structureOf(ph, idx) {
52
+ let after = 0;
53
+ for (let i = idx + 1; i < ph.length; i++)
54
+ if (isVowelPhone(ph[i]))
55
+ after++;
56
+ return after === 0 ? 'masculine' : after === 1 ? 'feminine' : 'dactylic';
57
+ }
58
+ /** Guarded orthographic tier: shared ending ≥3 chars, matching final phone if
59
+ * known, and never on a shared bare "-ing" (mass false positives). */
60
+ function orthographicTier(a, b, pa, pb) {
61
+ const wa = a.toLowerCase().replace(/[^a-z]/g, '');
62
+ const wb = b.toLowerCase().replace(/[^a-z]/g, '');
63
+ if (wa.length < 3 || wb.length < 3)
64
+ return null;
65
+ let common = 0;
66
+ while (common < Math.min(wa.length, wb.length) && wa[wa.length - 1 - common] === wb[wb.length - 1 - common])
67
+ common++;
68
+ if (common < 3)
69
+ return null;
70
+ if (wa.slice(-3) === 'ing' && wb.slice(-3) === 'ing' && common <= 4)
71
+ return null;
72
+ if (pa && pb && base(pa[pa.length - 1]) !== base(pb[pb.length - 1]))
73
+ return null;
74
+ // Wrenched when the shared ending is an UNSTRESSED suffix of a polysyllable
75
+ // (temperate/date, manifestation/convention); plain eye-rhyme otherwise.
76
+ const polyUnstressed = (ph) => {
77
+ if (!ph)
78
+ return false;
79
+ const idx = lastStressedIdx(ph);
80
+ return idx >= 0 && structureOf(ph, idx) !== 'masculine';
81
+ };
82
+ return polyUnstressed(pa) !== polyUnstressed(pb) ? 'wrenched' : 'eye';
83
+ }
84
+ /** Classify the rhyme relation between two line-end words (or null). */
85
+ export function classifyRhymePair(a, b) {
86
+ const wa = a.toLowerCase().replace(/[^a-z']/g, '');
87
+ const wb = b.toLowerCase().replace(/[^a-z']/g, '');
88
+ if (!wa || !wb)
89
+ return null;
90
+ const pa = phonesOf(a);
91
+ const pb = phonesOf(b);
92
+ if (wa === wb)
93
+ return { type: 'identical', structure: pa ? structureOf(pa, lastStressedIdx(pa)) : undefined };
94
+ if (!pa || !pb) {
95
+ const t = orthographicTier(a, b, pa, pb);
96
+ return t ? { type: t } : null;
97
+ }
98
+ const ia = lastStressedIdx(pa);
99
+ const ib = lastStressedIdx(pb);
100
+ if (ia < 0 || ib < 0)
101
+ return null;
102
+ const ra = pa.slice(ia);
103
+ const rb = pb.slice(ib);
104
+ const structure = structureOf(pa, ia);
105
+ const sameStructure = structure === structureOf(pb, ib);
106
+ const norm = (seg) => seg.map(base);
107
+ const na = norm(ra);
108
+ const nb = norm(rb);
109
+ const partsEqual = na.length === nb.length && na.every((p, i) => p === nb[i]);
110
+ if (partsEqual && sameStructure) {
111
+ const onsetA = ia > 0 ? base(pa[ia - 1]) : '';
112
+ const onsetB = ib > 0 ? base(pb[ib - 1]) : '';
113
+ return { type: onsetA === onsetB ? 'rich' : 'perfect', structure };
114
+ }
115
+ const vowelSame = na[0] === nb[0];
116
+ const codaA = na.slice(1).filter(p => !isVowelPhone(p));
117
+ const codaB = nb.slice(1).filter(p => !isVowelPhone(p));
118
+ const codaEq = codaA.length === codaB.length && codaA.every((p, i) => p === codaB[i]);
119
+ if (vowelSame) {
120
+ // Same stressed vowel. Matching-length codas whose consonants pair up
121
+ // within one phonetic family (wet/deck, dame/grain) → family rhyme.
122
+ if (codaA.length === codaB.length && codaA.length > 0
123
+ && codaA.every((p, i) => p === codaB[i] || sameFamily(p, codaB[i]))) {
124
+ return { type: 'family', structure };
125
+ }
126
+ // One extra trailing consonant on the second/first word (bray/brave).
127
+ if (codaA.length + 1 === codaB.length && codaA.every((p, i) => p === codaB[i]))
128
+ return { type: 'augmented', structure };
129
+ if (codaB.length + 1 === codaA.length && codaB.every((p, i) => p === codaA[i]))
130
+ return { type: 'diminished', structure };
131
+ return { type: 'assonant', structure };
132
+ }
133
+ if (codaEq && codaA.length > 0)
134
+ return { type: 'consonant', structure };
135
+ const t = orthographicTier(a, b, pa, pb);
136
+ return t ? { type: t } : null;
137
+ }
138
+ // Strength tiers for scheme detection.
139
+ const STRONG = new Set(['identical', 'rich', 'perfect', 'family']);
140
+ const SLANT = new Set(['assonant', 'consonant', 'augmented', 'diminished', 'wrenched', 'eye']);
141
+ /** Detect a stanza's rhyme scheme from its line-end words. Strong rhymes
142
+ * bind; slant-tier rhymes bind only when no strong candidate exists. */
143
+ export function detectScheme(endWords) {
144
+ const out = [];
145
+ let nextLetter = 0;
146
+ for (let i = 0; i < endWords.length; i++) {
147
+ let best = null;
148
+ for (let j = i - 1; j >= 0; j--) {
149
+ const pair = classifyRhymePair(endWords[j], endWords[i]);
150
+ if (!pair)
151
+ continue;
152
+ if (STRONG.has(pair.type)) {
153
+ best = { j, pair };
154
+ break;
155
+ } // nearest strong wins
156
+ if (!best && SLANT.has(pair.type))
157
+ best = { j, pair }; // else nearest slant
158
+ }
159
+ if (best) {
160
+ out.push({ endWord: endWords[i], letter: out[best.j].letter, type: best.pair.type, matchedLine: best.j });
161
+ }
162
+ else {
163
+ out.push({ endWord: endWords[i], letter: String.fromCharCode(65 + (nextLetter++ % 26)) });
164
+ }
165
+ }
166
+ // Rebind pass: a STRONG rhyme claims its partner back from an earlier
167
+ // slant-tier binding. (Sonnet 130: "rare" first slant-binds to the red/head
168
+ // group, then "compare" arrives as its perfect partner — the couplet wins.)
169
+ for (let k = 0; k < out.length; k++) {
170
+ const r = out[k];
171
+ if (r.matchedLine === undefined || !r.type || !STRONG.has(r.type))
172
+ continue;
173
+ const target = out[r.matchedLine];
174
+ if (target.matchedLine !== undefined && target.type && SLANT.has(target.type)) {
175
+ const fresh = String.fromCharCode(65 + (nextLetter++ % 26));
176
+ target.letter = fresh;
177
+ target.type = undefined;
178
+ target.matchedLine = undefined;
179
+ r.letter = fresh;
180
+ }
181
+ }
182
+ // Lines whose letter never recurs are unrhymed: mark '·' for readability.
183
+ const counts = new Map();
184
+ for (const r of out)
185
+ counts.set(r.letter, (counts.get(r.letter) ?? 0) + 1);
186
+ for (const r of out)
187
+ if ((counts.get(r.letter) ?? 0) < 2)
188
+ r.letter = '·';
189
+ // Re-letter the survivors in order of first appearance (A, B, C…).
190
+ const remap = new Map();
191
+ let k = 0;
192
+ for (const r of out) {
193
+ if (r.letter === '·')
194
+ continue;
195
+ if (!remap.has(r.letter))
196
+ remap.set(r.letter, String.fromCharCode(65 + (k++ % 26)));
197
+ r.letter = remap.get(r.letter);
198
+ }
199
+ return out;
200
+ }
201
+ const schemeStr = (rs) => rs.map(r => r.letter).join('');
202
+ /** Canonical scheme for FORM matching: every line gets a letter in sequential
203
+ * first-appearance order, unrhymed lines (·) each their own — so "·A·A"
204
+ * compares as "ABCB". */
205
+ function canonicalScheme(rs) {
206
+ const remap = new Map();
207
+ let k = 0;
208
+ const next = () => String.fromCharCode(65 + (k++ % 26));
209
+ let out = '';
210
+ for (const r of rs) {
211
+ if (r.letter === '·') {
212
+ out += next();
213
+ continue;
214
+ }
215
+ if (!remap.has(r.letter))
216
+ remap.set(r.letter, next());
217
+ out += remap.get(r.letter);
218
+ }
219
+ return out;
220
+ }
221
+ /** Stanza-level form verdict (LYRICAL-compatible names where they overlap). */
222
+ function stanzaForm(rhymes, details) {
223
+ const s = canonicalScheme(rhymes);
224
+ const n = rhymes.length;
225
+ const meters = details.map(d => (d.consensusMeter ?? d.meter).split(' ')[0]);
226
+ const dominant = (name, frac = 0.5) => meters.filter(m => m === name).length / n >= frac;
227
+ if (n === 2 && s === 'AA')
228
+ return 'couplet';
229
+ if (n === 3) {
230
+ if (s === 'ABA')
231
+ return 'triplet (tercet, ABA)';
232
+ if (s === 'AAA')
233
+ return 'mono-rhymed triplet';
234
+ }
235
+ if (n === 4) {
236
+ // Beat counts for the ballad gate: footCount (classical) or ictus count.
237
+ const beats = details.map((d, i) => d.footCount > 0 ? d.footCount : ictusProfile(d.scansion).ictuses);
238
+ const alt43 = beats.length === 4 && beats[0] === beats[2] && beats[1] === beats[3]
239
+ && beats[0] === beats[1] + 1;
240
+ if (s === 'ABAB' || s === 'ABCB') {
241
+ if (alt43)
242
+ return `ballad stanza (${s}, ${beats[0]}·${beats[1]})`;
243
+ return s === 'ABAB' ? 'quatrain (cross-rhymed, ABAB)' : `ballad-rhyme quatrain (ABCB)`;
244
+ }
245
+ if (s === 'ABBA')
246
+ return 'quatrain (envelope, ABBA)';
247
+ if (s === 'AABB')
248
+ return 'quatrain (couplet pair, AABB)';
249
+ if (s === 'AAAA')
250
+ return 'mono-rhymed quatrain';
251
+ }
252
+ if (n === 5 && s === 'AABBA') {
253
+ const ternary = meters.filter(m => m === 'anapestic' || m === 'amphibrachic' || m === 'dactylic').length >= 3;
254
+ return ternary ? 'limerick (AABBA, ternary)' : 'limerick rhyme (AABBA)';
255
+ }
256
+ if (n === 6 && s === 'ABABCC')
257
+ return 'sextilla / Venus-and-Adonis stanza (ABABCC)';
258
+ if (n === 7 && s === 'ABABBCC')
259
+ return 'rhyme royal (ABABBCC)';
260
+ if (n === 8 && (s === 'ABABABCC' || s === 'ABABABAB'))
261
+ return `octave (${s})`;
262
+ // Unrhymed stanza: blank verse when iambic pentameter dominates.
263
+ const unrhymed = rhymes.every(r => r.letter === '·');
264
+ if (unrhymed && n >= 3) {
265
+ const iambicPenta = details.filter(d => (d.consensusMeter ?? d.meter) === 'iambic pentameter').length / n;
266
+ if (iambicPenta >= 0.6)
267
+ return 'blank verse';
268
+ if (details.every(d => d.meterName === 'free verse') || details.some(d => d.rhythmNote))
269
+ return undefined; // rhythm layer already speaks
270
+ }
271
+ return undefined;
272
+ }
273
+ /** Poem-level form verdicts that span stanzas (sonnets, terza rima…). */
274
+ function poemForm(stanzas) {
275
+ const all = stanzas.flatMap(st => st.rhymes);
276
+ const n = all.length;
277
+ // Whole-poem scheme with stanza-local letters concatenated is NOT meaningful;
278
+ // re-detect across the full poem for sonnet/terza checks.
279
+ if (n === 14) {
280
+ const rs = detectScheme(all.map(r => r.endWord));
281
+ const s = canonicalScheme(rs);
282
+ if (/^ABABCDCDEFEFGG$/.test(s))
283
+ return 'Shakespearean Sonnet';
284
+ if (/^ABBAABBA/.test(s))
285
+ return 'Petrarchan Sonnet';
286
+ if (s.endsWith('GG') || /(..)\1*..$/.test(s)) {
287
+ // 14 iambic-pentameter lines with a closing couplet still reads sonnet-like.
288
+ const last2 = rs[12].letter !== '·' && rs[12].letter === rs[13].letter;
289
+ const iambicPenta = stanzas.flatMap(st => st.details)
290
+ .filter(d => (d.consensusMeter ?? d.meter) === 'iambic pentameter').length / 14;
291
+ if (last2 && iambicPenta >= 0.5)
292
+ return 'sonnet (14 lines, closing couplet)';
293
+ }
294
+ }
295
+ // Terza rima: chained tercets ABA BCB CDC…
296
+ if (stanzas.length >= 3 && stanzas.every(st => st.rhymes.length === 3)) {
297
+ let chained = true;
298
+ for (let i = 0; i + 1 < stanzas.length && chained; i++) {
299
+ const mid = stanzas[i].rhymes[1].endWord;
300
+ const nxt = stanzas[i + 1].rhymes;
301
+ const p1 = classifyRhymePair(mid, nxt[0].endWord);
302
+ const p3 = classifyRhymePair(mid, nxt[2].endWord);
303
+ if (!(p1 && STRONG.has(p1.type)) || !(p3 && STRONG.has(p3.type)))
304
+ chained = false;
305
+ }
306
+ if (chained)
307
+ return 'terza rima (ABA BCB CDC…)';
308
+ }
309
+ return undefined;
310
+ }
311
+ /** Last syllable-bearing word of a line (across its merged sentences). */
312
+ function lineEndWord(line) {
313
+ const ws = line.sentence.words.filter(w => !isPunctuation(w.lexicalClass) && w.syllables.length > 0);
314
+ return ws.length ? ws[ws.length - 1].word : '';
315
+ }
316
+ /**
317
+ * Annotate rhyme letters/types (`detail.rhyme`) and form verdicts
318
+ * (`detail.formNote`) across a poem. Stanza forms are per-stanza; a poem-level
319
+ * form (sonnet, terza rima) overrides stanza notes. Annotation-only — no
320
+ * meter/scansion/certainty is touched.
321
+ */
322
+ export function applyRhymeAndForm(stanzas) {
323
+ const analyzed = stanzas.map(lines => {
324
+ const details = lines.map(l => l.phonologicalScansion);
325
+ const rhymes = detectScheme(lines.map(lineEndWord));
326
+ return { details, rhymes };
327
+ });
328
+ for (const { details, rhymes } of analyzed) {
329
+ const form = stanzaForm(rhymes, details);
330
+ for (let i = 0; i < details.length; i++) {
331
+ details[i].rhyme = rhymes[i];
332
+ details[i].formNote = form;
333
+ }
334
+ }
335
+ const pform = poemForm(analyzed);
336
+ if (pform)
337
+ for (const { details } of analyzed)
338
+ for (const d of details)
339
+ d.formNote = pform;
340
+ }
@@ -0,0 +1,17 @@
1
+ import { StressLevel, MetreName, ScansionResult } from './types.js';
2
+ export declare function scandroidCorralWeird(marks: string, numFeet: number): {
3
+ footlist: string[];
4
+ scansionMarks: string;
5
+ };
6
+ export declare function scandroidMaximizeNormal(marks: string, numFeet: number): {
7
+ footlist: string[];
8
+ scansionMarks: string;
9
+ };
10
+ export declare function scandroidAnapestic(marks: string, numFeet?: number): {
11
+ footlist: string[];
12
+ scansionMarks: string;
13
+ };
14
+ export declare function stressToMarks(stressArray: StressLevel[]): string;
15
+ export declare function marksToFeetString(footlist: string[]): string;
16
+ export declare function scansionResultFromFootlist(footlist: string[], meter: MetreName, complexity?: number): ScansionResult;
17
+ //# sourceMappingURL=scandroid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scandroid.d.ts","sourceRoot":"","sources":["../src/scandroid.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAyIpE,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CA6E/C;AAID,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CA4E/C;AAID,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,MAAM,GACf;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CA4E/C;AAsBD,wBAAgB,aAAa,CAAC,WAAW,EAAE,WAAW,EAAE,GAAG,MAAM,CAEhE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAE5D;AAID,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAAE,EAClB,KAAK,EAAE,SAAS,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,cAAc,CAShB"}