Update the shared precipitation timing template
This commit is contained in:
@@ -76,9 +76,9 @@ fail rendering instead of producing incomplete Markdown.
|
||||
|
||||
Daily and Tomorrow call the shared `daypart_forecast` partial. Today calls
|
||||
`today_daypart_forecast` so it can omit elapsed or missing dayparts. Daily,
|
||||
Today, and Tomorrow call the shared `precipitation_timing` partial. Partial
|
||||
files are parsed with each top-level template at render time and receive the
|
||||
same typed render context as the caller.
|
||||
Today, Tomorrow, and Hourly call the shared `precipitation_timing` partial.
|
||||
Partial files are parsed with each top-level template at render time and
|
||||
receive the same typed render context as the caller.
|
||||
|
||||
## Schema Contract
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ Shared named partials live under `internal/reporttemplate/templates/partials/`:
|
||||
|
||||
- `daypart_forecast.md.tmpl`, used by Daily and Tomorrow
|
||||
- `today_daypart_forecast.md.tmpl`, used by Today
|
||||
- `precipitation_timing.md.tmpl`, used by Daily, Today, and Tomorrow
|
||||
- `precipitation_timing.md.tmpl`, used by Daily, Today, Tomorrow, and Hourly
|
||||
|
||||
Templates are rendered from structured contexts such as `DailyRenderContext`,
|
||||
`TodayRenderContext`, `TomorrowRenderContext`, and `HourlyRenderContext`.
|
||||
@@ -294,7 +294,7 @@ Common fields:
|
||||
| `.Modules.PrecipTiming.PrecipitationWindows[].MaxPopTime` | string | Friendly local time for the window maximum. |
|
||||
| `.Modules.PrecipTiming.PrecipitationWindows[].MaxPopHourLabel` | string | Friendly hour label for the window maximum. |
|
||||
| `.Modules.PrecipTiming.PrecipitationWindows[].PrecipitationType` | string | Conservatively inferred precipitation type, such as `showers and thunderstorms`. |
|
||||
| `.Modules.PrecipTiming.PrecipitationWindows[].ExpectationPhrase` | string | Probability-based sentence used by day-style templates. |
|
||||
| `.Modules.PrecipTiming.PrecipitationWindows[].ExpectationPhrase` | string | Probability-based sentence used by precipitation timing templates. |
|
||||
| `.Modules.PrecipTiming.ThunderMentioned` | bool | Whether thunder is mentioned in the forecast text. |
|
||||
|
||||
### Daypart Summaries
|
||||
|
||||
@@ -236,7 +236,7 @@ func TestRenderHourly(t *testing.T) {
|
||||
MaxPopPercent: intPtr(70),
|
||||
MaxPopTime: "10 AM",
|
||||
PrecipitationWindows: []testPrecipWindow{
|
||||
{PeriodBegins: "10 AM", PeriodBeginsHourLabel: "10:00 AM", PeriodEnds: "12 PM", PeriodEndsHourLabel: "12:00 PM", MaxPopPercent: intPtr(70), MaxPopTime: "10 AM", MaxPopHourLabel: "10:00 AM"},
|
||||
{PeriodBegins: "10 AM", PeriodBeginsHourLabel: "10:00 AM", PeriodEnds: "12 PM", PeriodEndsHourLabel: "12:00 PM", MaxPopPercent: intPtr(70), MaxPopTime: "10 AM", MaxPopHourLabel: "10:00 AM", ExpectationPhrase: "Expect showers."},
|
||||
},
|
||||
},
|
||||
AlertDigest: &testAlertDigest{
|
||||
@@ -272,7 +272,7 @@ func TestRenderHourly(t *testing.T) {
|
||||
"- **Flood Watch**: Flood Watch until 2:30 PM",
|
||||
"- **9:00 AM:** 74°F and cloudy.",
|
||||
"- **10:00 AM:** 75°F and showers. Probability of precipitation is 70%.",
|
||||
"- **10:00 AM** to **12:00 PM**: Precipitation is expected during this period. The peak precipitation chance is 70% at 10:00 AM.",
|
||||
"- **10:00 AM** to **12:00 PM**: Expect showers. The peak precipitation chance is 70% at 10:00 AM.",
|
||||
"A cold front is moving into the region.",
|
||||
"A front will keep the region unsettled.",
|
||||
} {
|
||||
@@ -732,6 +732,48 @@ func TestRenderHourlyOmitsConditionalSectionsForClearWeather(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenderHourlyUsesSharedOpenEndedPrecipitationTiming(t *testing.T) {
|
||||
rendered, err := Render("hourly", testRenderContext{
|
||||
Report: testReportContext{
|
||||
Title: "Hourly Report",
|
||||
GeneratedAtLabel: "Saturday, June 14, 2026 at 9:14 AM",
|
||||
},
|
||||
GeneratedText: testGeneratedText{
|
||||
Summary: "Rain chances increase through midday.",
|
||||
ForecastDiscussion: "Showers may continue beyond the report period.",
|
||||
PrecipitationTiming: "Plan for wet roads through the end of the period.",
|
||||
},
|
||||
Modules: testModules{
|
||||
CurrentConditions: &testCurrentConditions{},
|
||||
HourlyForecast: &testHourlyForecast{},
|
||||
AlertDigest: &testAlertDigest{},
|
||||
PrecipTiming: &testPrecipTiming{
|
||||
PrecipitationWindows: []testPrecipWindow{
|
||||
{
|
||||
PeriodBeginsHourLabel: "8:00 AM",
|
||||
MaxPopPercent: intPtr(60),
|
||||
MaxPopHourLabel: "10:00 AM",
|
||||
ExpectationPhrase: "Showers likely.",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Render() error = %v", err)
|
||||
}
|
||||
text := string(rendered)
|
||||
for _, want := range []string{
|
||||
"## Precipitation Timing",
|
||||
"- **Starting at 8:00 AM**: Showers likely. The peak precipitation chance is 60% at 10:00 AM.",
|
||||
"Plan for wet roads through the end of the period.",
|
||||
} {
|
||||
if !strings.Contains(text, want) {
|
||||
t.Fatalf("rendered template missing %q:\n%s", want, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnknownAssetsReturnActionableErrors(t *testing.T) {
|
||||
if _, err := Template("missing"); err == nil || !strings.Contains(err.Error(), `unknown report template "missing"`) {
|
||||
t.Fatalf("Template() error = %v, want unknown template", err)
|
||||
|
||||
@@ -26,14 +26,7 @@ Current conditions are unavailable.
|
||||
- No hourly forecast rows are available.
|
||||
{{ end }}
|
||||
|
||||
{{ with .Modules.PrecipTiming }}{{ with .PrecipitationWindows }}
|
||||
## Precipitation Timing
|
||||
{{ range . }}{{ $window := . }}
|
||||
- **{{ if .PeriodBeginsHourLabel }}{{ .PeriodBeginsHourLabel }}{{ else }}{{ .PeriodBegins }}{{ end }}**{{ with .PeriodEndsHourLabel }} to **{{ . }}**{{ else }}{{ with .PeriodEnds }} to **{{ . }}**{{ end }}{{ end }}: Precipitation is expected during this period.{{ with .MaxPopPercent }} The peak precipitation chance is {{ . }}%{{ with $window.MaxPopHourLabel }} at {{ . }}{{ else }}{{ with $window.MaxPopTime }} at {{ . }}{{ end }}{{ end }}.{{ end }}
|
||||
{{ end }}{{ with $.GeneratedText.PrecipitationTiming }}
|
||||
{{ . }}
|
||||
{{ end }}
|
||||
{{ end }}{{ end }}
|
||||
{{ template "precipitation_timing" . }}
|
||||
## Forecast Discussion
|
||||
|
||||
{{ .GeneratedText.ForecastDiscussion }}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{{ define "precipitation_timing" }}{{ with .Modules.PrecipTiming }}{{ with .PrecipitationWindows }}
|
||||
## Precipitation Timing
|
||||
{{ range . }}{{ $window := . }}
|
||||
- **{{ if .PeriodBeginsHourLabel }}{{ .PeriodBeginsHourLabel }}{{ else }}{{ .PeriodBegins }}{{ end }}**{{ with .PeriodEndsHourLabel }} to **{{ . }}**{{ else }}{{ with .PeriodEnds }} to **{{ . }}**{{ end }}{{ end }}: {{ with .ExpectationPhrase }}{{ . }}{{ else }}Chance of precipitation.{{ end }}{{ with .MaxPopPercent }} The peak precipitation chance is {{ . }}%{{ with $window.MaxPopHourLabel }} at {{ . }}{{ else }}{{ with $window.MaxPopTime }} at {{ . }}{{ end }}{{ end }}.{{ end }}
|
||||
- **{{ if or .PeriodEndsHourLabel .PeriodEnds }}{{ if .PeriodBeginsHourLabel }}{{ .PeriodBeginsHourLabel }}{{ else }}{{ .PeriodBegins }}{{ end }}{{ else }}Starting at {{ if .PeriodBeginsHourLabel }}{{ .PeriodBeginsHourLabel }}{{ else }}{{ .PeriodBegins }}{{ end }}{{ end }}**{{ with .PeriodEndsHourLabel }} to **{{ . }}**{{ else }}{{ with .PeriodEnds }} to **{{ . }}**{{ end }}{{ end }}: {{ with .ExpectationPhrase }}{{ . }}{{ else }}Chance of precipitation.{{ end }}{{ with .MaxPopPercent }} The peak precipitation chance is {{ . }}%{{ with $window.MaxPopHourLabel }} at {{ . }}{{ else }}{{ with $window.MaxPopTime }} at {{ . }}{{ end }}{{ end }}.{{ end }}
|
||||
{{ end }}{{ with $.GeneratedText.PrecipitationTiming }}
|
||||
{{ . }}
|
||||
{{ end }}
|
||||
|
||||
Reference in New Issue
Block a user