@@ -63,57 +63,79 @@ function resolveSourceValue(doc: any, source: FieldEvaluationSource): string | u
6363 return first !== '' ? first : undefined ;
6464}
6565
66- /**
67- * Cascade: walks `whenClauses` in definition order — sourceMatch branches first, then condition
68- * branches — first match wins; if none match, uses raw `sourceValue` or `fallbackValue`.
69- * Shared by applyFieldEvaluations and getSourceMatchSpec.
70- */
71- function evaluateFieldEvaluation (
72- doc : any ,
73- evaluation : FieldEvaluation
74- ) : { value : string | null ; sourceMatchSpec : SourceMatchSpec } {
75- let sourceValue : string | undefined ;
76- for ( const source of evaluation . sources ) {
77- sourceValue = resolveSourceValue ( doc , source ) ;
78- if ( sourceValue !== undefined ) {
79- break ;
66+ /** First resolved string from `sources`, in definition order. */
67+ function readRawValueFromSources ( doc : any , sources : FieldEvaluationSource [ ] ) : string | undefined {
68+ for ( const source of sources ) {
69+ const candidate = resolveSourceValue ( doc , source ) ;
70+ if ( candidate !== undefined ) {
71+ return candidate ;
8072 }
8173 }
74+ return undefined ;
75+ }
8276
83- let value : string | null | undefined ;
84- let matchedSourceClause : { sourceMatchesAny : string [ ] } | undefined ;
85- let winningCondition : Condition | undefined ;
86-
87- for ( const clause of evaluation . whenClauses ) {
77+ /** First `whenClause` that applies to this document, in definition order. */
78+ function matchFirstWhenClause (
79+ doc : any ,
80+ rawValueFromSources : string | undefined ,
81+ whenClauses : FieldEvaluationWhenClause [ ]
82+ ) {
83+ for ( const clause of whenClauses ) {
8884 if ( isSourceMatchClause ( clause ) ) {
89- if ( sourceValue !== undefined && clause . sourceMatchesAny . includes ( sourceValue ) ) {
90- value = clause . then ;
91- matchedSourceClause = { sourceMatchesAny : clause . sourceMatchesAny } ;
92- break ;
85+ if (
86+ rawValueFromSources !== undefined &&
87+ clause . sourceMatchesAny . includes ( rawValueFromSources )
88+ ) {
89+ return { then : clause . then , matchedSourceValues : clause . sourceMatchesAny } ;
9390 }
9491 } else if ( isConditionClause ( clause ) && evaluateStreamlangCondition ( doc , clause . condition ) ) {
95- value = clause . then ;
96- winningCondition = clause . condition ;
97- break ;
92+ return { then : clause . then , winningCondition : clause . condition } ;
9893 }
9994 }
95+ return undefined ;
96+ }
10097
101- if ( value === undefined ) {
102- value = sourceValue === undefined ? evaluation . fallbackValue : sourceValue ;
98+ /** Destination field value after applying optional when-clause override. */
99+ function resolveFinalFieldValue (
100+ rawValueFromSources : string | undefined ,
101+ fallbackValue : string | null ,
102+ whenMatch : { then : string } | undefined
103+ ) : string | null {
104+ if ( whenMatch !== undefined ) {
105+ return whenMatch . then ;
103106 }
107+ return rawValueFromSources === undefined ? fallbackValue : rawValueFromSources ;
108+ }
104109
105- let sourceMatchSpec : SourceMatchSpec ;
106- if ( winningCondition !== undefined ) {
107- sourceMatchSpec = { type : 'condition' , condition : winningCondition } ;
108- } else if ( sourceValue === undefined ) {
109- sourceMatchSpec = { type : 'unknown' } ;
110- } else if ( matchedSourceClause !== undefined ) {
111- sourceMatchSpec = { type : 'values' , values : matchedSourceClause . sourceMatchesAny } ;
112- } else {
113- sourceMatchSpec = { type : 'values' , values : [ sourceValue ] } ;
110+ /** Builds `SourceMatchSpec` for filter construction without re-evaluating the document. */
111+ function buildEvaluationSourceMatchSpec (
112+ rawValueFromSources : string | undefined ,
113+ whenMatch : { winningCondition ?: Condition ; matchedSourceValues ?: string [ ] } | undefined
114+ ) : SourceMatchSpec {
115+ if ( whenMatch ?. winningCondition !== undefined ) {
116+ return { type : 'condition' , condition : whenMatch . winningCondition } ;
117+ }
118+ if ( rawValueFromSources === undefined ) {
119+ return { type : 'unknown' } ;
120+ }
121+ if ( whenMatch ?. matchedSourceValues !== undefined ) {
122+ return { type : 'values' , values : whenMatch . matchedSourceValues } ;
114123 }
124+ return { type : 'values' , values : [ rawValueFromSources ] } ;
125+ }
126+
127+ /** Applies one field evaluation: sources, when-clauses, value + filter spec. */
128+ function evaluateFieldEvaluation (
129+ doc : any ,
130+ evaluation : FieldEvaluation
131+ ) : { value : string | null ; sourceMatchSpec : SourceMatchSpec } {
132+ const rawValueFromSources = readRawValueFromSources ( doc , evaluation . sources ) ;
133+ const whenMatch = matchFirstWhenClause ( doc , rawValueFromSources , evaluation . whenClauses ) ;
115134
116- return { value, sourceMatchSpec } ;
135+ return {
136+ value : resolveFinalFieldValue ( rawValueFromSources , evaluation . fallbackValue , whenMatch ) ,
137+ sourceMatchSpec : buildEvaluationSourceMatchSpec ( rawValueFromSources , whenMatch ) ,
138+ } ;
117139}
118140
119141/**
0 commit comments