Share day-style render context and template blocks
This commit is contained in:
@@ -165,6 +165,31 @@ type DailyDaypartContext struct {
|
||||
Summary briefing.DerivedDaypartSummaryModule
|
||||
}
|
||||
|
||||
type dayStyleReportContext struct {
|
||||
Title string
|
||||
ForecastDate time.Time
|
||||
ForecastDateLabel string
|
||||
ForecastDayName string
|
||||
GeneratedAt time.Time
|
||||
GeneratedAtLabel string
|
||||
ValidPeriod timeutil.Period
|
||||
Timezone string
|
||||
}
|
||||
|
||||
type dayStyleTemplateModules struct {
|
||||
Metadata *briefing.MetadataModule
|
||||
CurrentConditions *briefing.CurrentConditionsModule
|
||||
HourlyForecast *briefing.HourlyForecastModule
|
||||
DerivedDailySummary *briefing.DerivedDailySummaryModule
|
||||
DerivedDaypartSummaries *map[string]briefing.DerivedDaypartSummaryModule
|
||||
PrecipTiming *briefing.PrecipTimingModule
|
||||
AlertDigest *briefing.AlertDigestModule
|
||||
SPCConvectiveOutlooks *briefing.SPCConvectiveOutlooksModule
|
||||
AreaForecastDiscussion *briefing.AreaForecastDiscussionModule
|
||||
SPCConvectiveDiscussion *briefing.SPCConvectiveDiscussionModule
|
||||
WeatherStory *briefing.WeatherStoryModule
|
||||
}
|
||||
|
||||
func BuildHourlyRenderContext(metadata briefing.Metadata, snapshot module.Snapshot, generated Hourly, collected facts.CollectedFacts, derived facts.DerivedFacts) (HourlyRenderContext, error) {
|
||||
location, err := timeutil.LoadLocation(metadata.Timezone)
|
||||
if err != nil {
|
||||
@@ -198,33 +223,18 @@ func BuildHourlyRenderContext(metadata briefing.Metadata, snapshot module.Snapsh
|
||||
}
|
||||
|
||||
func BuildDailyRenderContext(metadata briefing.Metadata, snapshot module.Snapshot, generated Daily, collected facts.CollectedFacts, derived facts.DerivedFacts) (DailyRenderContext, error) {
|
||||
location, err := timeutil.LoadLocation(metadata.Timezone)
|
||||
reportContext, err := buildDayStyleReportContext(metadata, "daily", func(dayName string) string {
|
||||
return dayName + "'s Weather"
|
||||
})
|
||||
if err != nil {
|
||||
return DailyRenderContext{}, fmt.Errorf("build daily render context: %w", err)
|
||||
}
|
||||
if metadata.GeneratedAt.IsZero() {
|
||||
return DailyRenderContext{}, fmt.Errorf("build daily render context: generatedAt is required")
|
||||
}
|
||||
if !metadata.ValidPeriod.IsValid() {
|
||||
return DailyRenderContext{}, fmt.Errorf("build daily render context: valid period is required")
|
||||
return DailyRenderContext{}, err
|
||||
}
|
||||
modules, err := dailyTemplateModules(snapshot, derived)
|
||||
if err != nil {
|
||||
return DailyRenderContext{}, err
|
||||
}
|
||||
forecastDate := metadata.ValidPeriod.Start.In(location)
|
||||
forecastDayName := forecastDate.Format("Monday")
|
||||
return DailyRenderContext{
|
||||
Report: DailyReportContext{
|
||||
Title: forecastDayName + "'s Weather",
|
||||
ForecastDate: forecastDate,
|
||||
ForecastDateLabel: forecastDate.Format("Monday, January 2, 2006"),
|
||||
ForecastDayName: forecastDayName,
|
||||
GeneratedAt: metadata.GeneratedAt,
|
||||
GeneratedAtLabel: generatedAtLabel(metadata.GeneratedAt, location),
|
||||
ValidPeriod: metadata.ValidPeriod,
|
||||
Timezone: metadata.Timezone,
|
||||
},
|
||||
Report: reportContext.dailyReportContext(),
|
||||
GeneratedText: generated,
|
||||
Modules: modules,
|
||||
Collected: collected,
|
||||
@@ -233,32 +243,18 @@ func BuildDailyRenderContext(metadata briefing.Metadata, snapshot module.Snapsho
|
||||
}
|
||||
|
||||
func BuildTodayRenderContext(metadata briefing.Metadata, snapshot module.Snapshot, generated Today, collected facts.CollectedFacts, derived facts.DerivedFacts) (TodayRenderContext, error) {
|
||||
location, err := timeutil.LoadLocation(metadata.Timezone)
|
||||
reportContext, err := buildDayStyleReportContext(metadata, "today", func(string) string {
|
||||
return "Today's Weather"
|
||||
})
|
||||
if err != nil {
|
||||
return TodayRenderContext{}, fmt.Errorf("build today render context: %w", err)
|
||||
}
|
||||
if metadata.GeneratedAt.IsZero() {
|
||||
return TodayRenderContext{}, fmt.Errorf("build today render context: generatedAt is required")
|
||||
}
|
||||
if !metadata.ValidPeriod.IsValid() {
|
||||
return TodayRenderContext{}, fmt.Errorf("build today render context: valid period is required")
|
||||
return TodayRenderContext{}, err
|
||||
}
|
||||
modules, err := todayTemplateModules(snapshot, derived)
|
||||
if err != nil {
|
||||
return TodayRenderContext{}, err
|
||||
}
|
||||
forecastDate := metadata.ValidPeriod.Start.In(location)
|
||||
return TodayRenderContext{
|
||||
Report: TodayReportContext{
|
||||
Title: "Today's Weather",
|
||||
ForecastDate: forecastDate,
|
||||
ForecastDateLabel: forecastDate.Format("Monday, January 2, 2006"),
|
||||
ForecastDayName: forecastDate.Format("Monday"),
|
||||
GeneratedAt: metadata.GeneratedAt,
|
||||
GeneratedAtLabel: generatedAtLabel(metadata.GeneratedAt, location),
|
||||
ValidPeriod: metadata.ValidPeriod,
|
||||
Timezone: metadata.Timezone,
|
||||
},
|
||||
Report: reportContext.todayReportContext(),
|
||||
GeneratedText: generated,
|
||||
Modules: modules,
|
||||
Collected: collected,
|
||||
@@ -267,33 +263,18 @@ func BuildTodayRenderContext(metadata briefing.Metadata, snapshot module.Snapsho
|
||||
}
|
||||
|
||||
func BuildTomorrowRenderContext(metadata briefing.Metadata, snapshot module.Snapshot, generated Tomorrow, collected facts.CollectedFacts, derived facts.DerivedFacts) (TomorrowRenderContext, error) {
|
||||
location, err := timeutil.LoadLocation(metadata.Timezone)
|
||||
reportContext, err := buildDayStyleReportContext(metadata, "tomorrow", func(dayName string) string {
|
||||
return dayName + "'s Weather"
|
||||
})
|
||||
if err != nil {
|
||||
return TomorrowRenderContext{}, fmt.Errorf("build tomorrow render context: %w", err)
|
||||
}
|
||||
if metadata.GeneratedAt.IsZero() {
|
||||
return TomorrowRenderContext{}, fmt.Errorf("build tomorrow render context: generatedAt is required")
|
||||
}
|
||||
if !metadata.ValidPeriod.IsValid() {
|
||||
return TomorrowRenderContext{}, fmt.Errorf("build tomorrow render context: valid period is required")
|
||||
return TomorrowRenderContext{}, err
|
||||
}
|
||||
modules, err := tomorrowTemplateModules(snapshot, derived)
|
||||
if err != nil {
|
||||
return TomorrowRenderContext{}, err
|
||||
}
|
||||
forecastDate := metadata.ValidPeriod.Start.In(location)
|
||||
forecastDayName := forecastDate.Format("Monday")
|
||||
return TomorrowRenderContext{
|
||||
Report: TomorrowReportContext{
|
||||
Title: forecastDayName + "'s Weather",
|
||||
ForecastDate: forecastDate,
|
||||
ForecastDateLabel: forecastDate.Format("Monday, January 2, 2006"),
|
||||
ForecastDayName: forecastDayName,
|
||||
GeneratedAt: metadata.GeneratedAt,
|
||||
GeneratedAtLabel: generatedAtLabel(metadata.GeneratedAt, location),
|
||||
ValidPeriod: metadata.ValidPeriod,
|
||||
Timezone: metadata.Timezone,
|
||||
},
|
||||
Report: reportContext.tomorrowReportContext(),
|
||||
GeneratedText: generated,
|
||||
Modules: modules,
|
||||
Collected: collected,
|
||||
@@ -301,49 +282,73 @@ func BuildTomorrowRenderContext(metadata briefing.Metadata, snapshot module.Snap
|
||||
}, nil
|
||||
}
|
||||
|
||||
func buildDayStyleReportContext(metadata briefing.Metadata, name string, title func(string) string) (dayStyleReportContext, error) {
|
||||
location, err := timeutil.LoadLocation(metadata.Timezone)
|
||||
if err != nil {
|
||||
return dayStyleReportContext{}, fmt.Errorf("build %s render context: %w", name, err)
|
||||
}
|
||||
if metadata.GeneratedAt.IsZero() {
|
||||
return dayStyleReportContext{}, fmt.Errorf("build %s render context: generatedAt is required", name)
|
||||
}
|
||||
if !metadata.ValidPeriod.IsValid() {
|
||||
return dayStyleReportContext{}, fmt.Errorf("build %s render context: valid period is required", name)
|
||||
}
|
||||
|
||||
forecastDate := metadata.ValidPeriod.Start.In(location)
|
||||
forecastDayName := forecastDate.Format("Monday")
|
||||
return dayStyleReportContext{
|
||||
Title: title(forecastDayName),
|
||||
ForecastDate: forecastDate,
|
||||
ForecastDateLabel: forecastDate.Format("Monday, January 2, 2006"),
|
||||
ForecastDayName: forecastDayName,
|
||||
GeneratedAt: metadata.GeneratedAt,
|
||||
GeneratedAtLabel: generatedAtLabel(metadata.GeneratedAt, location),
|
||||
ValidPeriod: metadata.ValidPeriod,
|
||||
Timezone: metadata.Timezone,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ctx dayStyleReportContext) dailyReportContext() DailyReportContext {
|
||||
return DailyReportContext{
|
||||
Title: ctx.Title,
|
||||
ForecastDate: ctx.ForecastDate,
|
||||
ForecastDateLabel: ctx.ForecastDateLabel,
|
||||
ForecastDayName: ctx.ForecastDayName,
|
||||
GeneratedAt: ctx.GeneratedAt,
|
||||
GeneratedAtLabel: ctx.GeneratedAtLabel,
|
||||
ValidPeriod: ctx.ValidPeriod,
|
||||
Timezone: ctx.Timezone,
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx dayStyleReportContext) todayReportContext() TodayReportContext {
|
||||
return TodayReportContext{
|
||||
Title: ctx.Title,
|
||||
ForecastDate: ctx.ForecastDate,
|
||||
ForecastDateLabel: ctx.ForecastDateLabel,
|
||||
ForecastDayName: ctx.ForecastDayName,
|
||||
GeneratedAt: ctx.GeneratedAt,
|
||||
GeneratedAtLabel: ctx.GeneratedAtLabel,
|
||||
ValidPeriod: ctx.ValidPeriod,
|
||||
Timezone: ctx.Timezone,
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx dayStyleReportContext) tomorrowReportContext() TomorrowReportContext {
|
||||
return TomorrowReportContext{
|
||||
Title: ctx.Title,
|
||||
ForecastDate: ctx.ForecastDate,
|
||||
ForecastDateLabel: ctx.ForecastDateLabel,
|
||||
ForecastDayName: ctx.ForecastDayName,
|
||||
GeneratedAt: ctx.GeneratedAt,
|
||||
GeneratedAtLabel: ctx.GeneratedAtLabel,
|
||||
ValidPeriod: ctx.ValidPeriod,
|
||||
Timezone: ctx.Timezone,
|
||||
}
|
||||
}
|
||||
|
||||
func dailyTemplateModules(snapshot module.Snapshot, derived facts.DerivedFacts) (DailyTemplateModules, error) {
|
||||
lookup := newModuleSnapshotLookup(snapshot)
|
||||
metadata, err := lookup.metadata()
|
||||
if err != nil {
|
||||
return DailyTemplateModules{}, err
|
||||
}
|
||||
current, err := lookup.currentConditions()
|
||||
if err != nil {
|
||||
return DailyTemplateModules{}, err
|
||||
}
|
||||
hourly, err := lookup.hourlyForecast()
|
||||
if err != nil {
|
||||
return DailyTemplateModules{}, err
|
||||
}
|
||||
daily, err := lookup.derivedDailySummary()
|
||||
if err != nil {
|
||||
return DailyTemplateModules{}, err
|
||||
}
|
||||
dayparts, err := lookup.derivedDaypartSummaries()
|
||||
if err != nil {
|
||||
return DailyTemplateModules{}, err
|
||||
}
|
||||
precip, err := lookup.precipTiming()
|
||||
if err != nil {
|
||||
return DailyTemplateModules{}, err
|
||||
}
|
||||
alerts, err := lookup.alertDigest()
|
||||
if err != nil {
|
||||
return DailyTemplateModules{}, err
|
||||
}
|
||||
outlooks, err := lookup.spcConvectiveOutlooks()
|
||||
if err != nil {
|
||||
return DailyTemplateModules{}, err
|
||||
}
|
||||
discussion, err := lookup.areaForecastDiscussion()
|
||||
if err != nil {
|
||||
return DailyTemplateModules{}, err
|
||||
}
|
||||
spcDiscussion, err := lookup.spcConvectiveDiscussion()
|
||||
if err != nil {
|
||||
return DailyTemplateModules{}, err
|
||||
}
|
||||
story, err := lookup.weatherStory()
|
||||
common, lookup, err := dayStyleTemplateModuleSnapshot(snapshot)
|
||||
if err != nil {
|
||||
return DailyTemplateModules{}, err
|
||||
}
|
||||
@@ -356,66 +361,25 @@ func dailyTemplateModules(snapshot module.Snapshot, derived facts.DerivedFacts)
|
||||
return DailyTemplateModules{}, err
|
||||
}
|
||||
return DailyTemplateModules{
|
||||
Metadata: metadata,
|
||||
CurrentConditions: current,
|
||||
HourlyForecast: hourly,
|
||||
DerivedDailySummary: daily,
|
||||
DerivedDaypartSummaries: dayparts,
|
||||
Dayparts: orderedDailyDayparts(dayparts, derived.DaypartSummaries),
|
||||
PrecipTiming: precip,
|
||||
AlertDigest: alerts,
|
||||
SPCConvectiveOutlooks: outlooks,
|
||||
AreaForecastDiscussion: discussion,
|
||||
SPCConvectiveDiscussion: spcDiscussion,
|
||||
WeatherStory: story,
|
||||
Metadata: common.Metadata,
|
||||
CurrentConditions: common.CurrentConditions,
|
||||
HourlyForecast: common.HourlyForecast,
|
||||
DerivedDailySummary: common.DerivedDailySummary,
|
||||
DerivedDaypartSummaries: common.DerivedDaypartSummaries,
|
||||
Dayparts: orderedDailyDayparts(common.DerivedDaypartSummaries, derived.DaypartSummaries),
|
||||
PrecipTiming: common.PrecipTiming,
|
||||
AlertDigest: common.AlertDigest,
|
||||
SPCConvectiveOutlooks: common.SPCConvectiveOutlooks,
|
||||
AreaForecastDiscussion: common.AreaForecastDiscussion,
|
||||
SPCConvectiveDiscussion: common.SPCConvectiveDiscussion,
|
||||
WeatherStory: common.WeatherStory,
|
||||
OutdoorWindows: outdoor,
|
||||
DailyPlanning: planning,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func todayTemplateModules(snapshot module.Snapshot, derived facts.DerivedFacts) (TodayTemplateModules, error) {
|
||||
lookup := newModuleSnapshotLookup(snapshot)
|
||||
metadata, err := lookup.metadata()
|
||||
if err != nil {
|
||||
return TodayTemplateModules{}, err
|
||||
}
|
||||
current, err := lookup.currentConditions()
|
||||
if err != nil {
|
||||
return TodayTemplateModules{}, err
|
||||
}
|
||||
hourly, err := lookup.hourlyForecast()
|
||||
if err != nil {
|
||||
return TodayTemplateModules{}, err
|
||||
}
|
||||
daily, err := lookup.derivedDailySummary()
|
||||
if err != nil {
|
||||
return TodayTemplateModules{}, err
|
||||
}
|
||||
dayparts, err := lookup.derivedDaypartSummaries()
|
||||
if err != nil {
|
||||
return TodayTemplateModules{}, err
|
||||
}
|
||||
precip, err := lookup.precipTiming()
|
||||
if err != nil {
|
||||
return TodayTemplateModules{}, err
|
||||
}
|
||||
alerts, err := lookup.alertDigest()
|
||||
if err != nil {
|
||||
return TodayTemplateModules{}, err
|
||||
}
|
||||
outlooks, err := lookup.spcConvectiveOutlooks()
|
||||
if err != nil {
|
||||
return TodayTemplateModules{}, err
|
||||
}
|
||||
discussion, err := lookup.areaForecastDiscussion()
|
||||
if err != nil {
|
||||
return TodayTemplateModules{}, err
|
||||
}
|
||||
spcDiscussion, err := lookup.spcConvectiveDiscussion()
|
||||
if err != nil {
|
||||
return TodayTemplateModules{}, err
|
||||
}
|
||||
story, err := lookup.weatherStory()
|
||||
common, lookup, err := dayStyleTemplateModuleSnapshot(snapshot)
|
||||
if err != nil {
|
||||
return TodayTemplateModules{}, err
|
||||
}
|
||||
@@ -424,18 +388,18 @@ func todayTemplateModules(snapshot module.Snapshot, derived facts.DerivedFacts)
|
||||
return TodayTemplateModules{}, err
|
||||
}
|
||||
return TodayTemplateModules{
|
||||
Metadata: metadata,
|
||||
CurrentConditions: current,
|
||||
HourlyForecast: hourly,
|
||||
DerivedDailySummary: daily,
|
||||
DerivedDaypartSummaries: dayparts,
|
||||
Dayparts: orderedTodayDayparts(dayparts, derived.DaypartSummaries),
|
||||
PrecipTiming: precip,
|
||||
AlertDigest: alerts,
|
||||
SPCConvectiveOutlooks: outlooks,
|
||||
AreaForecastDiscussion: discussion,
|
||||
SPCConvectiveDiscussion: spcDiscussion,
|
||||
WeatherStory: story,
|
||||
Metadata: common.Metadata,
|
||||
CurrentConditions: common.CurrentConditions,
|
||||
HourlyForecast: common.HourlyForecast,
|
||||
DerivedDailySummary: common.DerivedDailySummary,
|
||||
DerivedDaypartSummaries: common.DerivedDaypartSummaries,
|
||||
Dayparts: orderedTodayDayparts(common.DerivedDaypartSummaries, derived.DaypartSummaries),
|
||||
PrecipTiming: common.PrecipTiming,
|
||||
AlertDigest: common.AlertDigest,
|
||||
SPCConvectiveOutlooks: common.SPCConvectiveOutlooks,
|
||||
AreaForecastDiscussion: common.AreaForecastDiscussion,
|
||||
SPCConvectiveDiscussion: common.SPCConvectiveDiscussion,
|
||||
WeatherStory: common.WeatherStory,
|
||||
TodayPlanning: planning,
|
||||
}, nil
|
||||
}
|
||||
@@ -492,48 +456,7 @@ func hourlyTemplateModules(snapshot module.Snapshot) (HourlyTemplateModules, err
|
||||
}
|
||||
|
||||
func tomorrowTemplateModules(snapshot module.Snapshot, derived facts.DerivedFacts) (TomorrowTemplateModules, error) {
|
||||
lookup := newModuleSnapshotLookup(snapshot)
|
||||
metadata, err := lookup.metadata()
|
||||
if err != nil {
|
||||
return TomorrowTemplateModules{}, err
|
||||
}
|
||||
current, err := lookup.currentConditions()
|
||||
if err != nil {
|
||||
return TomorrowTemplateModules{}, err
|
||||
}
|
||||
hourly, err := lookup.hourlyForecast()
|
||||
if err != nil {
|
||||
return TomorrowTemplateModules{}, err
|
||||
}
|
||||
daily, err := lookup.derivedDailySummary()
|
||||
if err != nil {
|
||||
return TomorrowTemplateModules{}, err
|
||||
}
|
||||
dayparts, err := lookup.derivedDaypartSummaries()
|
||||
if err != nil {
|
||||
return TomorrowTemplateModules{}, err
|
||||
}
|
||||
precip, err := lookup.precipTiming()
|
||||
if err != nil {
|
||||
return TomorrowTemplateModules{}, err
|
||||
}
|
||||
alerts, err := lookup.alertDigest()
|
||||
if err != nil {
|
||||
return TomorrowTemplateModules{}, err
|
||||
}
|
||||
outlooks, err := lookup.spcConvectiveOutlooks()
|
||||
if err != nil {
|
||||
return TomorrowTemplateModules{}, err
|
||||
}
|
||||
discussion, err := lookup.areaForecastDiscussion()
|
||||
if err != nil {
|
||||
return TomorrowTemplateModules{}, err
|
||||
}
|
||||
spcDiscussion, err := lookup.spcConvectiveDiscussion()
|
||||
if err != nil {
|
||||
return TomorrowTemplateModules{}, err
|
||||
}
|
||||
story, err := lookup.weatherStory()
|
||||
common, lookup, err := dayStyleTemplateModuleSnapshot(snapshot)
|
||||
if err != nil {
|
||||
return TomorrowTemplateModules{}, err
|
||||
}
|
||||
@@ -542,20 +465,81 @@ func tomorrowTemplateModules(snapshot module.Snapshot, derived facts.DerivedFact
|
||||
return TomorrowTemplateModules{}, err
|
||||
}
|
||||
return TomorrowTemplateModules{
|
||||
Metadata: common.Metadata,
|
||||
CurrentConditions: common.CurrentConditions,
|
||||
HourlyForecast: common.HourlyForecast,
|
||||
DerivedDailySummary: common.DerivedDailySummary,
|
||||
DerivedDaypartSummaries: common.DerivedDaypartSummaries,
|
||||
Dayparts: orderedTomorrowDayparts(common.DerivedDaypartSummaries, derived.DaypartSummaries),
|
||||
PrecipTiming: common.PrecipTiming,
|
||||
AlertDigest: common.AlertDigest,
|
||||
SPCConvectiveOutlooks: common.SPCConvectiveOutlooks,
|
||||
AreaForecastDiscussion: common.AreaForecastDiscussion,
|
||||
SPCConvectiveDiscussion: common.SPCConvectiveDiscussion,
|
||||
WeatherStory: common.WeatherStory,
|
||||
TomorrowPlanning: planning,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func dayStyleTemplateModuleSnapshot(snapshot module.Snapshot) (dayStyleTemplateModules, moduleSnapshotLookup, error) {
|
||||
lookup := newModuleSnapshotLookup(snapshot)
|
||||
metadata, err := lookup.metadata()
|
||||
if err != nil {
|
||||
return dayStyleTemplateModules{}, moduleSnapshotLookup{}, err
|
||||
}
|
||||
current, err := lookup.currentConditions()
|
||||
if err != nil {
|
||||
return dayStyleTemplateModules{}, moduleSnapshotLookup{}, err
|
||||
}
|
||||
hourly, err := lookup.hourlyForecast()
|
||||
if err != nil {
|
||||
return dayStyleTemplateModules{}, moduleSnapshotLookup{}, err
|
||||
}
|
||||
daily, err := lookup.derivedDailySummary()
|
||||
if err != nil {
|
||||
return dayStyleTemplateModules{}, moduleSnapshotLookup{}, err
|
||||
}
|
||||
dayparts, err := lookup.derivedDaypartSummaries()
|
||||
if err != nil {
|
||||
return dayStyleTemplateModules{}, moduleSnapshotLookup{}, err
|
||||
}
|
||||
precip, err := lookup.precipTiming()
|
||||
if err != nil {
|
||||
return dayStyleTemplateModules{}, moduleSnapshotLookup{}, err
|
||||
}
|
||||
alerts, err := lookup.alertDigest()
|
||||
if err != nil {
|
||||
return dayStyleTemplateModules{}, moduleSnapshotLookup{}, err
|
||||
}
|
||||
outlooks, err := lookup.spcConvectiveOutlooks()
|
||||
if err != nil {
|
||||
return dayStyleTemplateModules{}, moduleSnapshotLookup{}, err
|
||||
}
|
||||
discussion, err := lookup.areaForecastDiscussion()
|
||||
if err != nil {
|
||||
return dayStyleTemplateModules{}, moduleSnapshotLookup{}, err
|
||||
}
|
||||
spcDiscussion, err := lookup.spcConvectiveDiscussion()
|
||||
if err != nil {
|
||||
return dayStyleTemplateModules{}, moduleSnapshotLookup{}, err
|
||||
}
|
||||
story, err := lookup.weatherStory()
|
||||
if err != nil {
|
||||
return dayStyleTemplateModules{}, moduleSnapshotLookup{}, err
|
||||
}
|
||||
return dayStyleTemplateModules{
|
||||
Metadata: metadata,
|
||||
CurrentConditions: current,
|
||||
HourlyForecast: hourly,
|
||||
DerivedDailySummary: daily,
|
||||
DerivedDaypartSummaries: dayparts,
|
||||
Dayparts: orderedTomorrowDayparts(dayparts, derived.DaypartSummaries),
|
||||
PrecipTiming: precip,
|
||||
AlertDigest: alerts,
|
||||
SPCConvectiveOutlooks: outlooks,
|
||||
AreaForecastDiscussion: discussion,
|
||||
SPCConvectiveDiscussion: spcDiscussion,
|
||||
WeatherStory: story,
|
||||
TomorrowPlanning: planning,
|
||||
}, nil
|
||||
}, lookup, nil
|
||||
}
|
||||
|
||||
type moduleSnapshotLookup struct {
|
||||
|
||||
@@ -272,6 +272,192 @@ func TestBuildTodayRenderContextAllowsOmittedOptionalModules(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildDayStyleRenderContextsPopulateSharedFieldsAndPlanningModules(t *testing.T) {
|
||||
type result struct {
|
||||
title string
|
||||
forecastDateLabel string
|
||||
generatedAtLabel string
|
||||
timezone string
|
||||
validPeriod timeutil.Period
|
||||
metadata bool
|
||||
current bool
|
||||
hourly bool
|
||||
dailySummary bool
|
||||
daypartSummaries bool
|
||||
dayparts int
|
||||
precip bool
|
||||
alerts bool
|
||||
outlooks bool
|
||||
discussion bool
|
||||
spcDiscussion bool
|
||||
story bool
|
||||
planning bool
|
||||
collected bool
|
||||
derived bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
wantTitle string
|
||||
wantGeneratedLabel string
|
||||
wantDayparts int
|
||||
build func(t *testing.T) result
|
||||
}{
|
||||
{
|
||||
name: "daily",
|
||||
wantTitle: "Monday's Weather",
|
||||
wantGeneratedLabel: "Saturday, June 13, 2026 at 9:14 AM",
|
||||
wantDayparts: 3,
|
||||
build: func(t *testing.T) result {
|
||||
t.Helper()
|
||||
collected := testCollected()
|
||||
derived := testDailyDerived()
|
||||
ctx, err := BuildDailyRenderContext(testDailyMetadata(), testDailySnapshot(t), Daily{
|
||||
Summary: "Daily summary.",
|
||||
ForecastDiscussion: []string{"Daily discussion."},
|
||||
}, collected, derived)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildDailyRenderContext() error = %v", err)
|
||||
}
|
||||
return result{
|
||||
title: ctx.Report.Title,
|
||||
forecastDateLabel: ctx.Report.ForecastDateLabel,
|
||||
generatedAtLabel: ctx.Report.GeneratedAtLabel,
|
||||
timezone: ctx.Report.Timezone,
|
||||
validPeriod: ctx.Report.ValidPeriod,
|
||||
metadata: ctx.Modules.Metadata != nil && ctx.Modules.Metadata.ReportID == report.Daily,
|
||||
current: ctx.Modules.CurrentConditions != nil,
|
||||
hourly: ctx.Modules.HourlyForecast != nil,
|
||||
dailySummary: ctx.Modules.DerivedDailySummary != nil,
|
||||
daypartSummaries: ctx.Modules.DerivedDaypartSummaries != nil,
|
||||
dayparts: len(ctx.Modules.Dayparts),
|
||||
precip: ctx.Modules.PrecipTiming != nil,
|
||||
alerts: ctx.Modules.AlertDigest != nil,
|
||||
outlooks: ctx.Modules.SPCConvectiveOutlooks != nil,
|
||||
discussion: ctx.Modules.AreaForecastDiscussion != nil,
|
||||
spcDiscussion: ctx.Modules.SPCConvectiveDiscussion != nil,
|
||||
story: ctx.Modules.WeatherStory != nil,
|
||||
planning: ctx.Modules.DailyPlanning != nil,
|
||||
collected: ctx.Collected.FetchedAt.Equal(collected.FetchedAt),
|
||||
derived: len(ctx.Derived.DaypartSummaries) == len(derived.DaypartSummaries),
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "today",
|
||||
wantTitle: "Today's Weather",
|
||||
wantGeneratedLabel: "Monday, June 15, 2026 at 7:14 AM",
|
||||
wantDayparts: 2,
|
||||
build: func(t *testing.T) result {
|
||||
t.Helper()
|
||||
collected := testCollected()
|
||||
derived := testTodayDerived()
|
||||
ctx, err := BuildTodayRenderContext(testTodayMetadata(), testTodaySnapshot(t), Today{
|
||||
Summary: "Today summary.",
|
||||
ForecastDiscussion: []string{"Today discussion."},
|
||||
}, collected, derived)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildTodayRenderContext() error = %v", err)
|
||||
}
|
||||
return result{
|
||||
title: ctx.Report.Title,
|
||||
forecastDateLabel: ctx.Report.ForecastDateLabel,
|
||||
generatedAtLabel: ctx.Report.GeneratedAtLabel,
|
||||
timezone: ctx.Report.Timezone,
|
||||
validPeriod: ctx.Report.ValidPeriod,
|
||||
metadata: ctx.Modules.Metadata != nil && ctx.Modules.Metadata.ReportID == report.Today,
|
||||
current: ctx.Modules.CurrentConditions != nil,
|
||||
hourly: ctx.Modules.HourlyForecast != nil,
|
||||
dailySummary: ctx.Modules.DerivedDailySummary != nil,
|
||||
daypartSummaries: ctx.Modules.DerivedDaypartSummaries != nil,
|
||||
dayparts: len(ctx.Modules.Dayparts),
|
||||
precip: ctx.Modules.PrecipTiming != nil,
|
||||
alerts: ctx.Modules.AlertDigest != nil,
|
||||
outlooks: ctx.Modules.SPCConvectiveOutlooks != nil,
|
||||
discussion: ctx.Modules.AreaForecastDiscussion != nil,
|
||||
spcDiscussion: ctx.Modules.SPCConvectiveDiscussion != nil,
|
||||
story: ctx.Modules.WeatherStory != nil,
|
||||
planning: ctx.Modules.TodayPlanning != nil,
|
||||
collected: ctx.Collected.FetchedAt.Equal(collected.FetchedAt),
|
||||
derived: len(ctx.Derived.DaypartSummaries) == len(derived.DaypartSummaries),
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "tomorrow",
|
||||
wantTitle: "Monday's Weather",
|
||||
wantGeneratedLabel: "Sunday, June 14, 2026 at 9:14 AM",
|
||||
wantDayparts: 2,
|
||||
build: func(t *testing.T) result {
|
||||
t.Helper()
|
||||
collected := testCollected()
|
||||
derived := testTomorrowDerived()
|
||||
ctx, err := BuildTomorrowRenderContext(testTomorrowMetadata(), testTomorrowSnapshot(t), Tomorrow{
|
||||
Summary: "Tomorrow summary.",
|
||||
ForecastDiscussion: []string{"Tomorrow discussion."},
|
||||
}, collected, derived)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildTomorrowRenderContext() error = %v", err)
|
||||
}
|
||||
return result{
|
||||
title: ctx.Report.Title,
|
||||
forecastDateLabel: ctx.Report.ForecastDateLabel,
|
||||
generatedAtLabel: ctx.Report.GeneratedAtLabel,
|
||||
timezone: ctx.Report.Timezone,
|
||||
validPeriod: ctx.Report.ValidPeriod,
|
||||
metadata: ctx.Modules.Metadata != nil && ctx.Modules.Metadata.ReportID == report.Tomorrow,
|
||||
current: ctx.Modules.CurrentConditions != nil,
|
||||
hourly: ctx.Modules.HourlyForecast != nil,
|
||||
dailySummary: ctx.Modules.DerivedDailySummary != nil,
|
||||
daypartSummaries: ctx.Modules.DerivedDaypartSummaries != nil,
|
||||
dayparts: len(ctx.Modules.Dayparts),
|
||||
precip: ctx.Modules.PrecipTiming != nil,
|
||||
alerts: ctx.Modules.AlertDigest != nil,
|
||||
outlooks: ctx.Modules.SPCConvectiveOutlooks != nil,
|
||||
discussion: ctx.Modules.AreaForecastDiscussion != nil,
|
||||
spcDiscussion: ctx.Modules.SPCConvectiveDiscussion != nil,
|
||||
story: ctx.Modules.WeatherStory != nil,
|
||||
planning: ctx.Modules.TomorrowPlanning != nil,
|
||||
collected: ctx.Collected.FetchedAt.Equal(collected.FetchedAt),
|
||||
derived: len(ctx.Derived.DaypartSummaries) == len(derived.DaypartSummaries),
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
result := test.build(t)
|
||||
if result.title != test.wantTitle {
|
||||
t.Fatalf("title = %q, want %q", result.title, test.wantTitle)
|
||||
}
|
||||
if result.forecastDateLabel != "Monday, June 15, 2026" {
|
||||
t.Fatalf("forecastDateLabel = %q, want Monday, June 15, 2026", result.forecastDateLabel)
|
||||
}
|
||||
if result.generatedAtLabel != test.wantGeneratedLabel {
|
||||
t.Fatalf("generatedAtLabel = %q, want %q", result.generatedAtLabel, test.wantGeneratedLabel)
|
||||
}
|
||||
if result.timezone != "America/Chicago" {
|
||||
t.Fatalf("timezone = %q, want America/Chicago", result.timezone)
|
||||
}
|
||||
if !result.validPeriod.IsValid() {
|
||||
t.Fatalf("validPeriod = %#v, want valid period", result.validPeriod)
|
||||
}
|
||||
if !result.metadata || !result.current || !result.hourly || !result.dailySummary || !result.daypartSummaries || !result.precip || !result.alerts || !result.outlooks || !result.discussion || !result.spcDiscussion || !result.story {
|
||||
t.Fatalf("common modules = %#v, want all shared modules populated", result)
|
||||
}
|
||||
if result.dayparts != test.wantDayparts {
|
||||
t.Fatalf("dayparts = %d, want %d", result.dayparts, test.wantDayparts)
|
||||
}
|
||||
if !result.planning {
|
||||
t.Fatalf("planning = false, want %s planning module populated", test.name)
|
||||
}
|
||||
if !result.collected || !result.derived {
|
||||
t.Fatalf("facts passthrough = collected:%t derived:%t, want both true", result.collected, result.derived)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildDailyRenderContext(t *testing.T) {
|
||||
metadata := testDailyMetadata()
|
||||
snapshot := testDailySnapshot(t)
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"text/template"
|
||||
)
|
||||
|
||||
//go:embed templates/*.md.tmpl schemas/*.schema.json
|
||||
//go:embed templates/*.md.tmpl templates/partials/*.md.tmpl schemas/*.schema.json
|
||||
var assets embed.FS
|
||||
|
||||
var templates = map[string]string{
|
||||
@@ -18,6 +18,12 @@ var templates = map[string]string{
|
||||
"tomorrow": "templates/tomorrow.md.tmpl",
|
||||
}
|
||||
|
||||
var templatePartials = []string{
|
||||
"templates/partials/daypart_forecast.md.tmpl",
|
||||
"templates/partials/precipitation_timing.md.tmpl",
|
||||
"templates/partials/today_daypart_forecast.md.tmpl",
|
||||
}
|
||||
|
||||
var schemas = map[string]string{
|
||||
"daily": "schemas/daily.generated_text.schema.json",
|
||||
"hourly": "schemas/hourly.generated_text.schema.json",
|
||||
@@ -58,6 +64,16 @@ func Render(id string, data any) ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse report template %q: %w", id, err)
|
||||
}
|
||||
for _, path := range templatePartials {
|
||||
partial, err := assets.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read report template partial %q: %w", path, err)
|
||||
}
|
||||
tmpl, err = tmpl.Parse(string(partial))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse report template partial %q: %w", path, err)
|
||||
}
|
||||
}
|
||||
var out bytes.Buffer
|
||||
if err := tmpl.Execute(&out, data); err != nil {
|
||||
return nil, fmt.Errorf("render report template %q: %w", id, err)
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestTomorrowTemplateLookup(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Template() error = %v", err)
|
||||
}
|
||||
for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", "## Daypart Forecast", "## Precipitation Timing", "## Forecast Discussion"} {
|
||||
for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", `{{ template "daypart_forecast" . }}`, `{{ template "precipitation_timing" . }}`, "## Forecast Discussion"} {
|
||||
if !strings.Contains(source, want) {
|
||||
t.Fatalf("template missing %q:\n%s", want, source)
|
||||
}
|
||||
@@ -36,7 +36,7 @@ func TestDailyTemplateLookup(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Template() error = %v", err)
|
||||
}
|
||||
for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", "## Daypart Forecast", "## Precipitation Timing", "## Forecast Discussion"} {
|
||||
for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", `{{ template "daypart_forecast" . }}`, `{{ template "precipitation_timing" . }}`, "## Forecast Discussion"} {
|
||||
if !strings.Contains(source, want) {
|
||||
t.Fatalf("template missing %q:\n%s", want, source)
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func TestTodayTemplateLookup(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Template() error = %v", err)
|
||||
}
|
||||
for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", "## Current Conditions", "## Daypart Forecast", "## Forecast Discussion"} {
|
||||
for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", "## Current Conditions", `{{ template "today_daypart_forecast" . }}`, `{{ template "precipitation_timing" . }}`, "## Forecast Discussion"} {
|
||||
if !strings.Contains(source, want) {
|
||||
t.Fatalf("template missing %q:\n%s", want, source)
|
||||
}
|
||||
|
||||
@@ -5,19 +5,9 @@
|
||||
|
||||
{{ .GeneratedText.Summary }}
|
||||
|
||||
## Daypart Forecast
|
||||
{{ with .Modules.Dayparts }}{{ range . }}{{ $daypart := . }}- **{{ if .Summary.DisplayName }}{{ .Summary.DisplayName }}{{ else }}{{ .Key }}{{ end }}:** {{ with .Summary.DominantConditionDisplay }}{{ . }}{{ else }}{{ with .Summary.DominantCondition }}{{ . }}{{ else }}Forecast details are limited{{ end }}{{ end }}{{ if eq .Summary.TemperatureTrend "rising" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures rising from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "falling" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures falling from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "peaking" }}{{ with .Summary.TemperaturePeakPhraseF }}, with temperatures peaking in the {{ . }}{{ end }}{{ else }}{{ with .Summary.TemperatureSteadyPhraseF }}, with temperatures in the {{ . }}{{ else }}{{ with .Summary.TemperaturePhraseF }}, with temperatures in the {{ . }}{{ end }}{{ end }}{{ end }}.{{ if .Summary.MentionPrecipitation }}{{ with .Summary.MaxPopPercent }} Chance of precipitation is {{ . }}%.{{ end }}{{ end }}
|
||||
{{ end }}{{ else }}- No daypart forecast details are available.
|
||||
{{ end }}
|
||||
{{ template "daypart_forecast" . }}
|
||||
|
||||
{{ 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
|
||||
{{ range .GeneratedText.ForecastDiscussion }}
|
||||
{{ . }}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{{ define "daypart_forecast" }}## Daypart Forecast
|
||||
{{ with .Modules.Dayparts }}{{ range . }}{{ $daypart := . }}- **{{ if .Summary.DisplayName }}{{ .Summary.DisplayName }}{{ else }}{{ .Key }}{{ end }}:** {{ with .Summary.DominantConditionDisplay }}{{ . }}{{ else }}{{ with .Summary.DominantCondition }}{{ . }}{{ else }}Forecast details are limited{{ end }}{{ end }}{{ if eq .Summary.TemperatureTrend "rising" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures rising from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "falling" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures falling from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "peaking" }}{{ with .Summary.TemperaturePeakPhraseF }}, with temperatures peaking in the {{ . }}{{ end }}{{ else }}{{ with .Summary.TemperatureSteadyPhraseF }}, with temperatures in the {{ . }}{{ else }}{{ with .Summary.TemperaturePhraseF }}, with temperatures in the {{ . }}{{ end }}{{ end }}{{ end }}.{{ if .Summary.MentionPrecipitation }}{{ with .Summary.MaxPopPercent }} Chance of precipitation is {{ . }}%.{{ end }}{{ end }}
|
||||
{{ end }}{{ else }}- No daypart forecast details are available.
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
@@ -0,0 +1,8 @@
|
||||
{{ 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 }}: 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 }}{{ end }}
|
||||
@@ -0,0 +1,5 @@
|
||||
{{ define "today_daypart_forecast" }}## Daypart Forecast
|
||||
{{ with .Modules.Dayparts }}{{ range . }}{{ $daypart := . }}{{ if or .Summary.DominantConditionDisplay .Summary.DominantCondition }}- **{{ if .Summary.DisplayName }}{{ .Summary.DisplayName }}{{ else }}{{ .Key }}{{ end }}:** {{ with .Summary.DominantConditionDisplay }}{{ . }}{{ else }}{{ with .Summary.DominantCondition }}{{ . }}{{ end }}{{ end }}{{ if eq .Summary.TemperatureTrend "rising" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures rising from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "falling" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures falling from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "peaking" }}{{ with .Summary.TemperaturePeakPhraseF }}, with temperatures peaking in the {{ . }}{{ end }}{{ else }}{{ with .Summary.TemperatureSteadyPhraseF }}, with temperatures in the {{ . }}{{ else }}{{ with .Summary.TemperaturePhraseF }}, with temperatures in the {{ . }}{{ end }}{{ end }}{{ end }}.{{ if .Summary.MentionPrecipitation }}{{ with .Summary.MaxPopPercent }} Chance of precipitation is {{ . }}%.{{ end }}{{ end }}
|
||||
{{ end }}{{ end }}{{ else }}- No daypart forecast details are available.
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
@@ -10,19 +10,9 @@
|
||||
{{ with .TemperatureF }}Currently, it is {{ . }}°F{{ with $.Modules.CurrentConditions.ConditionTextLower }} and {{ . }}{{ end }}.{{ else }}{{ with .ConditionText }}Currently, it is {{ . }}.{{ else }}Current conditions are unavailable.{{ end }}{{ end }}{{ with .ApparentTemperatureF }} It feels like {{ . }}°F{{ with $.Modules.CurrentConditions.RelativeHumidityPercent }}, with a relative humidity of {{ . }}%{{ end }}{{ with $.Modules.CurrentConditions.WindDirectionText }} and winds from the {{ . }}{{ with $.Modules.CurrentConditions.WindSpeedMph }} at {{ . }} mph{{ end }}{{ end }}.{{ else }}{{ with .RelativeHumidityPercent }} Relative humidity is {{ . }}%.{{ end }}{{ with .WindDirectionText }} Winds are from the {{ . }}{{ with $.Modules.CurrentConditions.WindSpeedMph }} at {{ . }} mph{{ end }}.{{ end }}{{ end }}
|
||||
|
||||
{{ end }}
|
||||
## Daypart Forecast
|
||||
{{ with .Modules.Dayparts }}{{ range . }}{{ $daypart := . }}{{ if or .Summary.DominantConditionDisplay .Summary.DominantCondition }}- **{{ if .Summary.DisplayName }}{{ .Summary.DisplayName }}{{ else }}{{ .Key }}{{ end }}:** {{ with .Summary.DominantConditionDisplay }}{{ . }}{{ else }}{{ with .Summary.DominantCondition }}{{ . }}{{ end }}{{ end }}{{ if eq .Summary.TemperatureTrend "rising" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures rising from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "falling" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures falling from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "peaking" }}{{ with .Summary.TemperaturePeakPhraseF }}, with temperatures peaking in the {{ . }}{{ end }}{{ else }}{{ with .Summary.TemperatureSteadyPhraseF }}, with temperatures in the {{ . }}{{ else }}{{ with .Summary.TemperaturePhraseF }}, with temperatures in the {{ . }}{{ end }}{{ end }}{{ end }}.{{ if .Summary.MentionPrecipitation }}{{ with .Summary.MaxPopPercent }} Chance of precipitation is {{ . }}%.{{ end }}{{ end }}
|
||||
{{ end }}{{ end }}{{ else }}- No daypart forecast details are available.
|
||||
{{ end }}
|
||||
{{ template "today_daypart_forecast" . }}
|
||||
|
||||
{{ 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
|
||||
{{ range .GeneratedText.ForecastDiscussion }}
|
||||
{{ . }}
|
||||
|
||||
@@ -5,19 +5,9 @@
|
||||
|
||||
{{ .GeneratedText.Summary }}
|
||||
|
||||
## Daypart Forecast
|
||||
{{ with .Modules.Dayparts }}{{ range . }}{{ $daypart := . }}- **{{ if .Summary.DisplayName }}{{ .Summary.DisplayName }}{{ else }}{{ .Key }}{{ end }}:** {{ with .Summary.DominantConditionDisplay }}{{ . }}{{ else }}{{ with .Summary.DominantCondition }}{{ . }}{{ else }}Forecast details are limited{{ end }}{{ end }}{{ if eq .Summary.TemperatureTrend "rising" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures rising from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "falling" }}{{ with .Summary.TemperatureStartPhraseF }}, with temperatures falling from the {{ . }}{{ with $daypart.Summary.TemperatureEndPhraseF }} to the {{ . }}{{ end }}{{ end }}{{ else if eq .Summary.TemperatureTrend "peaking" }}{{ with .Summary.TemperaturePeakPhraseF }}, with temperatures peaking in the {{ . }}{{ end }}{{ else }}{{ with .Summary.TemperatureSteadyPhraseF }}, with temperatures in the {{ . }}{{ else }}{{ with .Summary.TemperaturePhraseF }}, with temperatures in the {{ . }}{{ end }}{{ end }}{{ end }}.{{ if .Summary.MentionPrecipitation }}{{ with .Summary.MaxPopPercent }} Chance of precipitation is {{ . }}%.{{ end }}{{ end }}
|
||||
{{ end }}{{ else }}- No daypart forecast details are available.
|
||||
{{ end }}
|
||||
{{ template "daypart_forecast" . }}
|
||||
|
||||
{{ 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
|
||||
{{ range .GeneratedText.ForecastDiscussion }}
|
||||
{{ . }}
|
||||
|
||||
Reference in New Issue
Block a user