cronli5 0.3.4 → 0.8.0

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 (51) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/README.md +63 -13
  3. package/cronli5.min.js +2 -2
  4. package/dist/cronli5.cjs +72 -9
  5. package/dist/cronli5.js +72 -9
  6. package/dist/lang/de.cjs +14 -6
  7. package/dist/lang/de.js +14 -6
  8. package/dist/lang/en.cjs +14 -6
  9. package/dist/lang/en.js +14 -6
  10. package/dist/lang/es.cjs +14 -6
  11. package/dist/lang/es.js +14 -6
  12. package/dist/lang/fi.cjs +14 -6
  13. package/dist/lang/fi.js +14 -6
  14. package/dist/lang/fr.cjs +1211 -0
  15. package/dist/lang/fr.js +1187 -0
  16. package/dist/lang/pt.cjs +1592 -0
  17. package/dist/lang/pt.js +1568 -0
  18. package/dist/lang/zh.cjs +58 -9
  19. package/dist/lang/zh.js +58 -9
  20. package/package.json +13 -2
  21. package/src/core/cadence.ts +25 -12
  22. package/src/core/index.ts +7 -3
  23. package/src/core/quartz.ts +97 -0
  24. package/src/core/schedule.ts +1 -0
  25. package/src/core/specs.ts +2 -2
  26. package/src/cronli5.ts +20 -3
  27. package/src/lang/de/index.ts +3 -2
  28. package/src/lang/en/index.ts +3 -2
  29. package/src/lang/es/index.ts +3 -2
  30. package/src/lang/fi/index.ts +3 -2
  31. package/src/lang/fr/dialects.ts +49 -0
  32. package/src/lang/fr/index.ts +2116 -0
  33. package/src/lang/fr/notes.md +280 -0
  34. package/src/lang/fr/status.json +8 -0
  35. package/src/lang/pt/dialects.ts +56 -0
  36. package/src/lang/pt/index.ts +2804 -0
  37. package/src/lang/pt/notes.md +199 -0
  38. package/src/lang/pt/status.json +8 -0
  39. package/src/lang/zh/index.ts +61 -5
  40. package/src/lang/zh/notes.md +16 -4
  41. package/src/lang/zh/status.json +10 -1
  42. package/src/types.ts +44 -0
  43. package/types/core/cadence.d.ts +1 -0
  44. package/types/core/quartz.d.ts +4 -0
  45. package/types/core/schedule.d.ts +1 -0
  46. package/types/cronli5.d.ts +4 -4
  47. package/types/lang/fr/dialects.d.ts +11 -0
  48. package/types/lang/fr/index.d.ts +4 -0
  49. package/types/lang/pt/dialects.d.ts +13 -0
  50. package/types/lang/pt/index.d.ts +4 -0
  51. package/types/types.d.ts +39 -0
@@ -0,0 +1,280 @@
1
+ # Français (fr, target fr-FR) — Language Notes
2
+
3
+ **donor: es.** Derived by sibling-derivation (tooling/docs/language-pipeline.md):
4
+ the Spanish module supplies the structure, plan override, OR-frame, predicates,
5
+ re-strategies, and dialect mechanism; this doc records only where **fr-FR
6
+ diverges** from that donor. The es→fr gap is wider than es→pt (a deliberate
7
+ stress test of the workflow), so several divergences below need genuine renderer
8
+ logic, not string swaps. The shipped table today is **fr-FR**; fr-CA is a future
9
+ dialect axis (below). **pt** is referenced where it solved an analogous Romance
10
+ problem (contractions, gender) — but fr is authored fresh and **never imports
11
+ pt**: the only cross-module reference is the donor (es). The donor's contract is
12
+ [`../es/notes.md`](../es/notes.md); pt's analogous layer is
13
+ [`../pt/notes.md`](../pt/notes.md).
14
+
15
+ ## Anchors
16
+
17
+ French norm (Imprimerie nationale / Académie française, plus cronstrue `fr`):
18
+ lowercase month and weekday names, **24-hour clock by default** with the **`h`
19
+ separator** between hour and minute. **Decided: spaced "9 h 30" form**
20
+ (Imprimerie nationale: a thin/regular space each side of `h`), hour rendered
21
+ **unpadded** ("1 h", "9 h", "17 h 30"), top-of-hour as bare "9 h" (no "h 00").
22
+ Rationale: the spaced `h` is the typographic standard fr-FR reference (IN
23
+ *Lexique des règles typographiques*); the colon "09:30" reads as Anglophone/SI
24
+ and the unspaced "9h30" is the casual register. **Ratified** by the blind fr-FR
25
+ native panel (everyday / copy-editor / technical, 2026-06-27): spaced "9 h 30" is
26
+ the default, unspaced "9h30" remains the opt-in dialect register.
27
+
28
+ **minuit / midi for exact 0:00 / 12:00** (replacing es "medianoche/mediodía").
29
+ These are **bare nouns, no article and no `h`** — "à minuit", "à midi" (not "à
30
+ 0 h" / "à 12 h"). minuit is masculine, midi is masculine.
31
+
32
+ **minuit/midi are the exact-POINT form only — panel-ratified (2026-06-27).** A
33
+ range *over* the midnight or noon hour (the whole 0:00–0:59 / 12:00–12:59 hour
34
+ as a per-hour window) must **not** mix the word with a numeric endpoint: render
35
+ **"de 0 h à 0 h 59"**, **"de 12 h à 12 h 59"** — never "de minuit à 0 h 59" /
36
+ "de midi à 12 h 59" (the panel found the word+numeric mix within one window
37
+ jarring and register-inconsistent). minuit/midi are reserved for the bare exact
38
+ instant ("à minuit") and for a cadence/range whose endpoint genuinely **is** the
39
+ 0:00 / 12:00 point ("toutes les sept heures **de minuit** à 21 h", "de minuit à
40
+ 5 h 59" — minuit is the real first fire there, not a 0:00–0:59 window).
41
+
42
+ **Seconds-clock: "H h MM min SS s", with the zero-minute SUPPRESSED —
43
+ panel-ratified (2026-06-27).** The full hours/minutes/seconds form is "9 h 30 min
44
+ 15 s" (SI abbreviations `min` / `s`, spaced per the `h` convention). When the
45
+ minute is **zero**, drop the "0 min" segment entirely: **"9 h 30 s"** (not
46
+ "9 h 0 min 30 s") — nobody says "neuf heures zéro minute trente secondes". Keep
47
+ "min" only when the minute is non-zero.
48
+
49
+ **Bare-numeral hour lists carry the `h` — panel-ratified (2026-06-27).** An
50
+ index-style active-hours list ("pendant les heures de …") uses the **"X h"** form
51
+ for every value, consistent with the clock convention everywhere else: "pendant
52
+ les heures de 0 h, 3 h, 6 h, …" (not the bare "0, 3, 6, …" the donor's
53
+ unit-less list would give).
54
+
55
+ **12-hour {ampm} mode — decided: NOT supported; {ampm} is a documented no-op
56
+ for fr.** Rationale: fr-FR overwhelmingly uses the 24-hour clock in writing and
57
+ speech; "du matin / de l'après-midi / du soir" exist but are colloquial qualifiers
58
+ on an already-spoken hour, not a true 12-hour clock with an AM/PM mark, and fr has
59
+ no clean 12-noon-boundary meridiem. So fr ships **24h-only**; an explicit
60
+ `{ampm: true}` is accepted and ignored (no throw). This is a real es→fr
61
+ divergence: es made {ampm} a first-class clock; fr declines it. The es day-period
62
+ band machinery (madrugada/mañana/tarde/noche) therefore has **no fr analog** and
63
+ is dropped, not ported. **Ratified** by the fr-FR panel (2026-06-27): the 24h-only
64
+ decline is the safe, idiomatic default.
65
+
66
+ ## Per-value ordinals (the named fr hazard)
67
+
68
+ es used invariant date forms ("el 1", "el día N"). fr requires a **per-VALUE**
69
+ rule the renderer must implement:
70
+
71
+ - **The 1st of the month is "le 1er"** (premier); **every other day is the bare
72
+ cardinal with the article — "le 2", "le 15", "le 31".** This is a deep fr-FR
73
+ norm (calendars, official/legal texts, speech): "le premier janvier" but "le
74
+ 2 janvier". The renderer selects per value, not once per field.
75
+ - The "1er" carries into **ranges** (first term only — "du 1er au 15"), **lists**
76
+ ("le 1er, le 15 et le 20"), and **OR-union date arms** ("le 1er de chaque
77
+ mois"). Every other position stays cardinal.
78
+ - **Ratified** by the fr-FR panel (2026-06-27) as correct and natural; it remains
79
+ one of the three es→fr stress points needing real per-value logic (with
80
+ contractions and gender).
81
+
82
+ ## Quartz nth-weekday ordinals (gendered)
83
+
84
+ es used invariant "primer/último". fr nth ordinals **agree in gender** with the
85
+ target noun: **premier/première, deuxième, troisième, quatrième, cinquième,
86
+ dernier/dernière.** Weekdays are **masculine** in fr (le lundi), so
87
+ "le premier lundi du mois", "le dernier vendredi du mois". "le dernier jour du
88
+ mois" (jour masculine). The feminine "première/dernière" form is needed for any
89
+ feminine target noun (e.g. "la dernière semaine" if a week-scoped form arises).
90
+ gender selection is renderer logic, like pt; but fr weekdays are masculine
91
+ (unlike pt's feminine -feira), so the common case is the masculine ordinal. The
92
+ gendered-ordinal selection was **ratified** by the fr-FR panel (2026-06-27).
93
+
94
+ ## W operator: "ouvrable", not "ouvré"
95
+
96
+ The Quartz `W` / `LW` tokens (nearest weekday to a date / last weekday of the
97
+ month) render with **"ouvrable"** — "le jour ouvrable le plus proche du 15", "le
98
+ dernier jour ouvrable du mois". **Panel-ratified (2026-06-27), replacing the
99
+ candidate's "ouvré".** Rationale: *ouvrable* = a legally-workable day (the
100
+ calendar-defined Mon–Fri/non-holiday day the `W` token actually selects), whereas
101
+ *ouvré* = an actually-worked day (a payroll/accounting term implying the day was
102
+ in fact worked). `W` is a calendar predicate, not a worked-time count, so
103
+ *ouvrable* is the precise term.
104
+
105
+ ## Contractions (es lacks these; pt solved the analogous problem)
106
+
107
+ French fuses *de* and *à* with the masculine/plural definite article; the
108
+ renderer must form these wherever es emitted a bare preposition + article
109
+ (pt's contraction layer is the reference approach — gender/number-driven
110
+ formation, not string substitution):
111
+
112
+ - *de* + le → **du**; *de* + les → **des**. (*de* + la → **de la**, *de* +
113
+ l' → **de l'** stay unfused.)
114
+ - *à* + le → **au**; *à* + les → **aux**. (*à* + la → **à la**, *à* + l' →
115
+ **à l'** stay unfused.)
116
+
117
+ Where the renderer needs them:
118
+ - **"de chaque mois / de chaque heure"** — de + chaque (no article, no fusion);
119
+ but **"du mois"** (de+le mois) in date-range scopes ("du 1er au 15 **du
120
+ mois**").
121
+ - **clock list / "at"** — fr uses bare **"à"** + the time ("à 9 h 30"), and
122
+ **"à minuit" / "à midi"**; no article on a clock time, so no fusion there
123
+ (unlike es "a las"). The fusion bites on **date/scope** nouns, not the clock.
124
+ - **date ranges** — "du 1er au 15", "de juin à septembre" (de+proper-noun, no
125
+ fusion), "du lundi au vendredi" (de+le, à+le → du/au).
126
+ - **windows / cadences** — per-hour minute windows read "de 9 h à 9 h 59"
127
+ (de/à + bare hour, no article, no fusion); an hour cadence "toutes les deux
128
+ heures **de** 9 h **à** 17 h".
129
+
130
+ **FLAGGED** as the principal structural es→fr divergence and the expected RED in
131
+ the TDD port — gender/number-driven formation, mirroring pt's layer.
132
+
133
+ ## Gender and agreement
134
+
135
+ es is largely invariant; fr needs agreement the renderer must handle:
136
+
137
+ - **Weekdays are masculine** (le lundi … le dimanche); **months masculine**
138
+ (janvier … décembre). This drives "le lundi", "le premier lundi".
139
+ - **"chaque" is invariant** (chaque heure, chaque mois, chaque jour) — no gender
140
+ choice, simpler than es "cada"/"todos". **"tous les jours"** (m.pl.) for "every
141
+ day"; **"toutes les heures"** (f.pl.), **"tous les mois"** (m.pl.) for the
142
+ cadence determiner. *heure* is feminine, *mois/jour* masculine — the
143
+ determiner agrees.
144
+ - **Cardinal "deux" etc. are invariant** in "toutes les deux heures" (no
145
+ feminine inflection of the number itself), simpler than pt's "duas horas".
146
+ - Quartz nth ordinals agree with the (masculine) weekday — see above.
147
+
148
+ ## Weekday recurrence
149
+
150
+ es uses the plural article "los lunes" = every Monday. **Decided: "le lundi"**
151
+ (singular definite article = the habitual/recurrent every-Monday), the standard
152
+ fr-FR generic-recurrence form — "le lundi" already means "on Mondays / every
153
+ Monday", so a plural "les lundis" is **not** used (it reads as several specific
154
+ Mondays, the wrong sense). **Ratified** by the fr-FR panel (2026-06-27): "le
155
+ lundi" (singular definite habitual) is the default.
156
+
157
+ - **Multi-day lists stay singular-definite — panel-ratified (2026-06-27), a
158
+ deliberate es divergence.** A weekday list repeats the singular "le" per day:
159
+ **"le mardi, le jeudi, le samedi et le dimanche"** — *not* the es-style plural
160
+ "les mardis, les jeudis, …". es pluralizes ("los martes, jueves, …"); fr keeps
161
+ the distributive singular habitual, consistent with the single-day "le lundi".
162
+ Applies uniformly to every weekday-list entry (plain lists and OR-union DOW arms
163
+ alike).
164
+ - **Ranges: "du lundi au vendredi"** (de+le → du, à+le → au), the idiomatic fr
165
+ weekday range.
166
+ - **Lists: "le lundi, le mercredi et le vendredi"** — the article repeats per
167
+ day (no suffix-ellipsis like pt's *-feira*; fr has no such affix). A bare-noun
168
+ list "lundi, mercredi et vendredi" reads as *this coming* set, so the article
169
+ is kept for the recurrence sense.
170
+ - **No "tous les" on weekdays** — "le lundi" already carries "every", so
171
+ "tous les lundis" would be redundant emphasis (parallels es's "no todos on
172
+ weekdays" rule; "tous les jours" stays because "les jours" alone is not "every
173
+ day").
174
+
175
+ ## Connectives
176
+
177
+ - and → **et** (no comma before *et* in a simple series — fr, like pt, has **no**
178
+ RAE-style "coma ante y"; the es day-period-join comma re-strategy is **dropped**,
179
+ not ported. Moot anyway since fr has no day periods.)
180
+ - or → **ou** (the OR-union connector; see OR-union frame).
181
+ - range / until → **à** ("de … à …", "du … au …") and **jusqu'à** where a
182
+ terminal "until" reads better; default to **à** to mirror es "de … a …".
183
+
184
+ ## OR-union frame (date-OR-weekday)
185
+
186
+ es "ya sea X o Y" → **decided: "soit X soit Y"** (the fr either-or correlative),
187
+ e.g. "le 1er de chaque mois, soit le 1er, soit le lundi". Rationale: "soit …
188
+ soit …" is the unambiguous fr inclusive-alternative correlative and reads as the
189
+ union of two independent day conditions, parallel to es "ya sea … o". A bare
190
+ "X ou Y" risks an intersection misread when the arms are themselves complex; the
191
+ "soit … soit" frame brackets each arm. **Ratified** by the fr-FR panel
192
+ (2026-06-27): "soit … soit …" is the precision-appropriate **inclusive**-union
193
+ correlative (the technical reviewer confirmed the inclusive reading is standard in
194
+ technical prose; all three personas read the union, not an intersection or an
195
+ exclusive or). The shared month is fronted once and the arms are month-less,
196
+ exactly as in es. The weekday arm reads the fr recurrence ("le lundi" / "du lundi
197
+ au vendredi"); a **single-weekday** arm reads **"n'importe quel lundi"** (es
198
+ "cualquier lunes"), and a **range** arm keeps a nominal head: **"n'importe quel
199
+ jour du lundi au vendredi"**. Both "n'importe quel …" forms ratified by the panel
200
+ as idiomatic and unambiguous.
201
+
202
+ ## Names
203
+
204
+ - **Lowercase months and weekdays** (confirmed fr-FR norm — Académie/IN: janvier,
205
+ lundi are common nouns, never capitalized mid-sentence).
206
+
207
+ ## Ported re-strategies (language-neutral; fr forms)
208
+
209
+ - **Per-hour windows for wildcard minutes over hour lists** (es §wildcard minutes
210
+ → per-hour windows): keep the strategy; fr form **"de 9 h à 9 h 59"** (bare
211
+ hours, de/à, no article). A shared scope is said once per range; the es 12-hour
212
+ day-period folding has no fr analog (24h-only), so each window is a plain hour
213
+ span.
214
+ - **OR-union unified frame** — the "soit … soit …" frame above; month fronted
215
+ once, arms month-less, exactly as es.
216
+ - **No-fold month range** — a month range never folds into another phrase
217
+ ("le 1er juin à septembre" parses as "(le 1er juin) à septembre"); dates scope
218
+ it instead ("le 1er de chaque mois, de juin à septembre"); mixed lists repeat
219
+ the preposition per piece ("en janvier et de mars à juin"). Same rule as es and
220
+ English.
221
+ - **Step-flattening** — step segments inside lists always flatten into their
222
+ fires (months, weekdays, dates, minutes, seconds); no raw step token reaches
223
+ the output. Identical to es.
224
+ - **Anchored minutes/seconds** read as **"à la minute 30 de chaque heure"**
225
+ (à+la → no fusion; de+chaque → no fusion), the donor's "en el minuto 30 de
226
+ cada hora" — not a calque of "past the hour".
227
+
228
+ ## Dialect axis (future)
229
+
230
+ fr-CA (OQLF / Canadian French) is a **future dialect** — it carries clock and
231
+ lexical/typographic divergences from fr-FR (e.g. OQLF prefers the non-spaced or
232
+ differently-spaced `h`, and some date register differs), mirroring es's
233
+ es-ES / es-419 split and pt's pt-PT axis. **One `fr` table today = fr-FR.** A
234
+ future `fr-CA` (and any colloquial-clock custom field such as an unspaced "9h30"
235
+ style) would clear its own native panel before shipping, per the dialect rules
236
+ in the pipeline.
237
+
238
+ ## Anticipated renderer divergences (the es→fr stress points)
239
+
240
+ Recorded for Stage-4 port — where the RED is expected, the analogue of pt's
241
+ contraction/gender layer but wider:
242
+
243
+ 1. **Contractions (du/des/au/aux)** — gender/number-driven fusion of de/à + the
244
+ article, on date/scope nouns (not the clock). Net-new vs es.
245
+ 2. **Per-value ordinals (le 1er vs le N)** — a per-value selector on dates, not
246
+ the invariant es form. Net-new logic.
247
+ 3. **Gender/ordinal agreement** — premier/première, dernier/dernière selected by
248
+ target-noun gender; masculine weekdays/months; the agreeing cadence
249
+ determiner (toutes les heures / tous les mois).
250
+ 4. **Clock formatter** — "9 h 30" / "1 h" (unpadded, spaced `h`) and the bare
251
+ minuit/midi, replacing es's padded "09:30" + article + day-period machinery;
252
+ {ampm} declined (no-op).
253
+ 5. **Recurrence head** — "le lundi" singular-definite, replacing es's plural
254
+ "los lunes".
255
+
256
+ ## Residual inherited from es (panel-flagged, NOT fixed here)
257
+
258
+ The blind fr-FR panel (2026-06-27) found one structural residual it did **not**
259
+ ask fr to fix in isolation, because it is inherited from the es donor and shows
260
+ identically in es (and pt):
261
+
262
+ - **Double-"et" boundary on `* 2/4,18-20 * * *`.** The hour field unions a step
263
+ segment {2,6,10,14,18,22} with a range {18,19,20}; the renderer emits the
264
+ step segment's per-hour windows and then the range window, joining them with a
265
+ second "et": "… et de 22 h à 22 h 59 **et** de 18 h à 20 h 59". The two
266
+ consecutive "et" at the step/range join can momentarily read as one chained
267
+ range (hour 18 is covered by both arms — the same overlap behind the es+pt
268
+ hour-window-overlap residual on this exact cron). Fire set is correct;
269
+ meaning-preserving. A clean fix collapses the overlapping step/range arms to
270
+ the hour union, which is a change to the **shared es-derived rendering**, not
271
+ fr-only — tracked as a joint es+fr (and es+pt) follow-up in docs/backlog.md
272
+ (per-language follow-ups). Left as-is in this corpus.
273
+
274
+ ## Known trade-offs
275
+
276
+ - `short` only switches spelled numbers to digits; fr name abbreviations
277
+ (lun., janv.) are not yet implemented (same residue as es/pt).
278
+ - The spaced-`h` clock and the per-value "1er" are correctness/register-critical;
279
+ the renderer forms both programmatically rather than hard-coding strings.
280
+
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "French",
3
+ "status": "beta",
4
+ "humanReview": null,
5
+ "modelReview": "sibling-derived from es (the validated Romance sibling): the es renderer's structure was ported (plan override, OR-union frame, parity predicates, re-strategies, dialect scaffold) and its lexicon translated to fr-FR, then TDD'd to green against the reviewed fr-FR corpus. The corpus was a candidate translated from the reviewed es corpus and finalized by a blind 3-persona fr-FR Sonnet panel (everyday / copy-editor / technical, 2026-06-27) before the port (corpus -> review -> port; tooling/docs/language-pipeline.md). The es->fr gap is wider than es->pt (a deliberate stress test): the divergences the panel and TDD surfaced and the renderer now handles are three net-new layers plus a clock rewrite — (1) the 'à 9 h 30' 24-hour clock (no article, unpadded, spaced typographic 'h', minuit/midi for the exact 0:00/12:00 point only, the seconds-clock 'H h MM min SS s' with the zero-minute suppressed; the es 12-hour day-period machinery dropped and {ampm} accepted as a documented no-op); (2) preposition+article contraction (de+le=du, de+les=des, a+le=au, a+les=aux; de la / a la / l' unfused) on date/scope nouns; (3) the per-VALUE 'le 1er' ordinal (the 1st only; every other day the bare cardinal 'le N'), carried into ranges, lists, and OR-union date arms; (4) gender agreement (masculine weekdays/months, gendered Quartz nth ordinals, the agreeing cadence determiner toutes les heures / tous les mois). Plus 'le lundi' singular-definite recurrence (multi-day lists singular-definite, 'du lundi au vendredi' ranges), the 'soit X soit Y' inclusive-union frame with 'n'importe quel' weekday arms, 'ouvrable' for the W operator, and no comma before 'et'. Objective gates (round-trip orchestrator-run, fuzz dropped-value detector, both-side OR-scope, cRonstrue fr reference) plus the panel gate beta.",
6
+ "note": "BETA — model-validated: sibling-derived from es (a proven structure/style anchor), TDD-green over a blind-panel-reviewed fr-FR corpus, and clean on the corpus-independent mechanical gates (fuzz, conciseness, cRonstrue fr). One structural residual is inherited unchanged from the es donor and is NOT an fr regression (tracked as a joint es+fr/es+pt follow-up; notes.md §Residual): the double-'et' boundary on '* 2/4,18-20 * * *' where a step segment's per-hour windows join the range window with a second 'et' (fire set correct, meaning-preserving). The 'short' style switches spelled numbers to digits but fr name abbreviations (lun., janv.) are not yet implemented (same residue as es/pt). Graduates to stable only on fluent-fr human review. fr-CA (OQLF / Canadian French — a non-spaced or differently-spaced 'h', divergent date register) is a future dialect axis (notes.md §Dialect axis); no regional dialect ships yet, and the colloquial unspaced '9h30' clock is an opt-in custom style.",
7
+ "dialects": {}
8
+ }
@@ -0,0 +1,56 @@
1
+ // Portuguese dialect style tables. Dialect names are language-scoped; the
2
+ // default `pt` style is anchored to the Brazilian norm (VOLP / Academia
3
+ // Brasileira de Letras, plus cronstrue `pt_BR`); see notes.md. Custom objects
4
+ // merge over the `pt` defaults. pt-PT is a future dialect axis (notes.md
5
+ // §"Dialect axis"); no regional dialect ships yet.
6
+ import type {Cronli5Options} from '../../types.js';
7
+
8
+ /**
9
+ * Portuguese's own resolved style shape has a separator,
10
+ * clock default, meridiem form, and `h` suffix.
11
+ */
12
+ export interface PortugueseStyle {
13
+ // Clock default: false renders 24-hour times (pt-BR norm), true renders
14
+ // 12-hour day-period times. An explicit `{ampm}` option still overrides this.
15
+ ampm: boolean;
16
+ // Append an "h" after a clock time ("às 09:00 h"). Opt-in only — the "h"
17
+ // register reads colloquial/formal in pt-BR, deferred per notes.md.
18
+ hSuffix: boolean;
19
+ // How a 12-hour time names its half of the day: 'descriptors' for the
20
+ // pt-BR "da madrugada/manhã/tarde/noite", 'english' for the AM/PM meridiem.
21
+ // No shipped dialect uses 'english'; kept for parity with the donor scaffold.
22
+ meridiem: 'descriptors' | 'english';
23
+ // Separator between hours, minutes, and seconds. The colon is the pt-BR
24
+ // default; a custom style can opt into the period.
25
+ sep: string;
26
+ }
27
+
28
+ // The pt-BR default: 24-hour, colon.
29
+ const pt: PortugueseStyle = {
30
+ ampm: false,
31
+ hSuffix: false,
32
+ meridiem: 'descriptors',
33
+ sep: ':'
34
+ };
35
+
36
+ // One `pt` table today = pt-BR. pt-PT is a future dialect axis (notes.md);
37
+ // it would clear its own native panel before shipping, so it is not declared
38
+ // here yet.
39
+ const dialects: {[name: string]: PortugueseStyle} = {
40
+ pt,
41
+ // Brazil is the default; named explicitly so it is a recognized choice and
42
+ // has a home if it ever diverges.
43
+ 'pt-BR': pt
44
+ };
45
+
46
+ // Resolve the `dialect` option to a style table.
47
+ function resolveDialect(dialect: Cronli5Options['dialect']): PortugueseStyle {
48
+ if (typeof dialect === 'object' && dialect !== null) {
49
+ return {...dialects.pt, ...dialect};
50
+ }
51
+
52
+ // A string dialect indexes the table; unknown names fall back to `pt`.
53
+ return dialects[dialect as string] || dialects.pt;
54
+ }
55
+
56
+ export {resolveDialect};