
    vXj0              	      4   d Z ddlmZ ddlZddlZddlmZ ddlmZ d\  Z	Z
dZdZ ej                  d	ej                        d
ddf ej                  dej                        d
ddf ej                  dej                        d
ddf ej                  dej                        d
ddf ej                  dej                        dddf ej                  dej                        dddfgZ ej                  d      Zedd       Zed d       Zd!ddZd"dZd#dZy)$a  Writing-style checks for forecast text: the forecaster's own wording, phrase
suggestions, and Claude's suggested text all go through `check`.

Precedence (app/sources.py): USDA FS Forecast Guidance writing rules come first
and weigh more; Writing for Busy Readers (Rogers & Lasky-Fink 2023) is
advisory. Its wordy-phrase list is filtered so it never rewrites Forecast
Guidance vocabulary (see app/data/style-rules.json "excluded").
    )annotationsN)	lru_cache)Path)fgbusy_readers      z\bfacet(?:s|ed)?\bbottom_line   FG §3.3u6   Jargon: say “sugary snow” instead of “facets”.z\bwind[- ]?slabs?\bu:   Jargon: say “wind drifts” instead of “wind slabs”.z\b(?:surface|depth) hoar\bz/Jargon: describe the weak layer in plain words.z\bpropagat\w*z.Jargon: say how widely avalanches could break.z\bno (?:chance of avalanches|avalanche (?:danger|hazard))\b|\bavalanches? (?:are|is|will be) (?:not possible|impossible)\b|\bsafe avalanche conditions\bu   FG §3.2z3Don't tell people there is no chance of avalanches.zF\b(?:is|are|was|were|be|been|being)\s+(?:\w+ly\s+)?\w+(?:ed|en)\s+by\bu   FG §3.1z,Passive voice: say who or what did it first.z[^.!?]+[.!?]*c                     t        j                  t        t              j                  dz  dz  j                               S )Ndatazstyle-rules.json)jsonloadsr   __file__parent	read_text     &/var/www/avy-guidance/api/app/style.pyrulesr   $   s/    ::tH~,,v58JJUUWXXr   c                     t               d   D  ci c]  } | d   | 
 }} t        |t        d      }t        j                  ddj                  d |D              z   dz   t        j                        }||fS c c} w )	NwordyphraseT)keyreversez(?<![\w-])(?:|c              3  F   K   | ]  }t        j                  |        y wN)reescape).0ps     r   	<genexpr>z_wordy_regex.<locals>.<genexpr>-   s     /K		!/Ks   !z
)(?![\w-]))r   sortedlenr   compilejoinI)w	by_phrasealtsrxs       r   _wordy_regexr-   )   sr    ).)9:A8a:I:)d3D	$sxx/Kd/K'KKm[]_]a]a	bBy= ;s   A5c                    | ||||||xs g dS )Nsourceruletextstartendmatchreplacementsr   r/   s          r   _findingr7   1   s#    dD5QT_d(.B0 0r   c                    t         j                  |       D cg c]P  }|j                         j                         s"|j	                         |j                         |j                         fR c}S c c}w r   )	_SENTENCEfinditergroupstripr3   r4   )r2   ms     r   	sentencesr>   6   sO    5>5G5G5McQRQXQXQZQ`Q`QbQWWY+cccs
   #A01A0c                *   | xs d} g g }}t         D ]p  \  }}}}|||k(  s|j                  |       }|s$|j                  t        t        |||j                         |j                         |j                                      r t        |       }	|dk(  r?t        |	      t        kD  r-|j                  t        t        ddt        |	       d             |	D ]a  \  }
}}t        |j                               }|t        kD  s*|j                  t        t        dd| d	|
||j                         dd
              c t               \  }}|j!                  |       D ]  }||j                         j#                            }dj%                  d |d   D              }|d   r	d|d    dnd}|j                  t        t        dd|j                          d| | d|j                         |j                         |j                         |d                 ||z   S )z8Findings for one piece of text, Forecast Guidance first. Nr
   r   z+Aim for three sentences or fewer (this has z).zBusy Readers 2zLong sentence (z! words): write shorter sentences.<   z / c              3  (   K   | ]
  }d | d  yw)u   “u   ”Nr   )r!   os     r   r#   zcheck.<locals>.<genexpr>N   s     =1Cs#,=s   optionsnotez ()zBusy Readers 1u
   Wordy: “u   ” → .)_FG_PATTERNSsearchappendr7   FGr3   r4   r;   r>   r%   BOTTOM_LINE_MAX_SENTENCESsplitLONG_SENTENCE_WORDSBUSYr<   r-   r:   lowerr'   )r2   fieldr   busyr,   onlyr1   rE   r=   sentsr3   r4   snr*   r)   optss                    r   checkrX   :   s   :2D2B , SD$<45=		$A		(2tT1779aeegqwwyQR	S
 dOE#e*/H"H
		(2z-XY\]bYcXddf+ghi >sA	N""KK'7?1#Mn9o!&QWWYs^= >>
 !NMB	[[ 7aggioo'(zz=)==$%fIAfI;a 2HT#3z!'')HUYTZ[_Z``a5bdedkdkdmopototovWWY)6 	7	7 9r   )returndict)rY   ztuple[re.Pattern, dict])NNNN)r2   strrY   zlist[tuple[int, int, str]])r2   z
str | NonerQ   r[   rY   z
list[dict])__doc__
__future__r   r   r   	functoolsr   pathlibr   rK   rO   rN   rL   r&   r(   rH   r9   r   r-   r7   r>   rX   r   r   r   <module>r`      sk   #  	  D   RZZ%rtt,mZ  JB  CRZZ&-}j  KG  HRZZ-rtt4mZ  RC  DRZZ "$$'
DtuRZZ OPRPTPTV	:LN RZZY[][_[_`	:EG
 BJJ'(	 Y Y  0
dr   