@@ -12,6 +12,7 @@ import {
1212 TmplAstDeferredBlock ,
1313 TmplAstDeferredTrigger ,
1414 TmplAstHoverDeferredTrigger ,
15+ TmplAstIdleDeferredTrigger ,
1516 TmplAstImmediateDeferredTrigger ,
1617 TmplAstInteractionDeferredTrigger ,
1718 TmplAstTimerDeferredTrigger ,
@@ -60,6 +61,26 @@ function areLiteralMapsEqual(a: LiteralMap | null, b: LiteralMap | null): boolea
6061 return true ;
6162}
6263
64+ function getTimedTriggerValue (
65+ trigger : TmplAstTimerDeferredTrigger | TmplAstIdleDeferredTrigger ,
66+ ) : number | null {
67+ if ( trigger instanceof TmplAstTimerDeferredTrigger ) {
68+ return trigger . delay ;
69+ }
70+
71+ return trigger . timeout ;
72+ }
73+
74+ function formatTimedTrigger (
75+ trigger : TmplAstTimerDeferredTrigger | TmplAstIdleDeferredTrigger ,
76+ ) : string {
77+ if ( trigger instanceof TmplAstTimerDeferredTrigger ) {
78+ return `timer(${ trigger . delay } ms)` ;
79+ }
80+
81+ return trigger . timeout === null ? 'idle' : `idle(${ trigger . timeout } ms)` ;
82+ }
83+
6384/**
6485 * This check implements warnings for unreachable or redundant @defer triggers.
6586 * Emits ErrorCode.DEFER_TRIGGER_MISCONFIGURATION with messages matching the project's
@@ -119,21 +140,36 @@ class DeferTriggerMisconfiguration extends TemplateCheckWithVisitor<ErrorCode.DE
119140 const main = mains [ 0 ] ;
120141
121142 for ( const pre of prefetches ) {
122- // Timer vs Timer: warn when prefetch delay >= main delay
123- const isTimerTriggger =
143+ // Delay-based pairs (timer/idle): warn when prefetch fires no sooner than main.
144+
145+ const isTimerPair =
124146 main instanceof TmplAstTimerDeferredTrigger && pre instanceof TmplAstTimerDeferredTrigger ;
125- if ( isTimerTriggger ) {
126- const mainDelay = main . delay ;
127- const preDelay = pre . delay ;
128- if ( preDelay >= mainDelay ) {
129- const msg = `The Prefetch 'timer(${ preDelay } ms)' is not scheduled before the main 'timer(${ mainDelay } ms)', so it won’t run prior to rendering. Lower the prefetch delay or remove it.` ;
130- diags . push (
131- ctx . makeTemplateDiagnostic (
132- pre . sourceSpan ?? node . sourceSpan ,
133- formatExtendedError ( ErrorCode . DEFER_TRIGGER_MISCONFIGURATION , msg ) ,
134- ) ,
135- ) ;
147+
148+ const isIdlePair =
149+ main instanceof TmplAstIdleDeferredTrigger && pre instanceof TmplAstIdleDeferredTrigger ;
150+
151+ if ( isTimerPair || isIdlePair ) {
152+ const mainVal = getTimedTriggerValue ( main ) ;
153+ const preVal = getTimedTriggerValue ( pre ) ;
154+ const sameUntimedIdle = mainVal == null && preVal == null ;
155+ const comparableTimedPair = mainVal != null && preVal != null && preVal >= mainVal ;
156+
157+ if ( ! sameUntimedIdle && ! comparableTimedPair ) {
158+ continue ;
136159 }
160+
161+ const msg =
162+ `The Prefetch '${ formatTimedTrigger ( pre ) } ' is not scheduled before the main '${ formatTimedTrigger ( main ) } ',` +
163+ ` so it won't run prior to rendering. Lower the prefetch timing or remove it.` ;
164+
165+ diags . push (
166+ ctx . makeTemplateDiagnostic (
167+ pre . sourceSpan ?? node . sourceSpan ,
168+ formatExtendedError ( ErrorCode . DEFER_TRIGGER_MISCONFIGURATION , msg ) ,
169+ ) ,
170+ ) ;
171+
172+ continue ;
137173 }
138174
139175 // Reference-based triggers (hover/interaction/viewport): warn if both
0 commit comments