@@ -110,15 +110,46 @@ export class SyntaxChecker {
110110 }
111111
112112 /**
113- * Check if a parameter is a function result parameter
113+ * Check if the syntax declares a return type
114+ * @param syntax - Command syntax
115+ * @returns True if syntax has a return type declaration (e.g., ") : Type")
116+ */
117+ private syntaxHasReturnType ( syntax : string ) : boolean {
118+ // Check for return type pattern: ) : Type at the end
119+ // This matches patterns like:
120+ // - "functionName ( params ) : ReturnType"
121+ // - "functionName ( params ) : cs.ViewPro.TableTheme"
122+ // - "functionName ( params ) : 4D.Object"
123+ // Type can be: simple (Text), namespaced (cs.Class), or dotted (4D.Object, cs.ViewPro.TableTheme)
124+ return / \) \s * : \s * [ \w . ] + \s * $ / . test ( syntax . trim ( ) ) ;
125+ }
126+
127+ /**
128+ * Check if a parameter represents the function's return value
129+ * This is used to exclude function results from regular parameter validation
114130 * @param param - Parameter to check
115- * @returns True if parameter is a function result (Result or Function result with Direction.Return)
131+ * @param syntax - Command syntax to check if it declares a return type
132+ * @returns True if parameter is a function result that should be excluded from parameter validation
116133 */
117- private isFunctionResult ( param : DocumentationParameter ) : boolean {
118- const name = param . name . toLowerCase ( ) ;
134+ private isFunctionResult ( param : DocumentationParameter , syntax ?: string ) : boolean {
119135 const direction = param . direction ;
120- return direction === Direction . Return &&
121- ( name === 'result' || name === 'function result' ) ;
136+
137+ // Must be a Return direction parameter
138+ if ( direction !== Direction . Return ) {
139+ return false ;
140+ }
141+
142+ // If no syntax provided, cannot determine - default to not excluding it
143+ if ( ! syntax ) {
144+ return false ;
145+ }
146+
147+ // A Return-direction parameter is a function result if:
148+ // The syntax declares a return type (e.g., "functionName(...) : Type")
149+ // This structurally distinguishes:
150+ // - Functions: "Abs(x : Real) : Real" - has return type, Return param is function result
151+ // - Commands with output: "EXECUTE METHOD(name : Text ; result : Variable)" - no return type, Return param is regular output
152+ return this . syntaxHasReturnType ( syntax ) ;
122153 }
123154
124155 /**
@@ -140,9 +171,10 @@ export class SyntaxChecker {
140171 /**
141172 * Get input parameter names (excluding return parameters)
142173 * @param params - Parameter array from documentation
174+ * @param syntax - Command syntax to determine if it's a function
143175 * @returns Array of input parameter names
144176 */
145- getInputParameterNames ( params : DocumentationParameter [ ] ) : string [ ] {
177+ getInputParameterNames ( params : DocumentationParameter [ ] , syntax ?: string ) : string [ ] {
146178 if ( ! params || params . length === 0 ) return [ ] ;
147179
148180 return params
@@ -153,7 +185,7 @@ export class SyntaxChecker {
153185 // But include other Direction.Return parameters as they are output parameters, not function results
154186 return (
155187 direction !== undefined &&
156- ! this . isFunctionResult ( param )
188+ ! this . isFunctionResult ( param , syntax )
157189 ) ;
158190 } )
159191 . map ( param => param . name . toLowerCase ( ) ) ;
@@ -164,9 +196,10 @@ export class SyntaxChecker {
164196 * @param variant - Parsed variant object
165197 * @param params - Actual parameter array
166198 * @param actualParamNames - Array of actual parameter names
199+ * @param syntax - Command syntax to determine if it's a function
167200 * @returns Validation result with extraParams and typeMismatches
168201 */
169- validateVariantParameters ( variant : ParsedVariant , params : DocumentationParameter [ ] , actualParamNames : string [ ] ) : ValidationResult {
202+ validateVariantParameters ( variant : ParsedVariant , params : DocumentationParameter [ ] , actualParamNames : string [ ] , syntax ?: string ) : ValidationResult {
170203 const parsedParamNames = variant . parameters
171204 . filter ( p => p . spread === - 1 ) // Don't validate spread parameters
172205 . map ( p => p . name . toLowerCase ( ) ) ;
@@ -179,10 +212,10 @@ export class SyntaxChecker {
179212 ) ;
180213
181214 // Check for type mismatches
182- const typeMismatches = this . checkTypeMismatches ( variant , params ) ;
215+ const typeMismatches = this . checkTypeMismatches ( variant , params , syntax ) ;
183216
184217 // Check for return type mismatches
185- const returnTypeMismatches = this . checkReturnTypeMismatches ( variant , params ) ;
218+ const returnTypeMismatches = this . checkReturnTypeMismatches ( variant , params , syntax ) ;
186219
187220 return { extraParams, typeMismatches, returnTypeMismatches } ;
188221 }
@@ -191,9 +224,10 @@ export class SyntaxChecker {
191224 * Check for type mismatches between parsed and actual parameters
192225 * @param variant - Parsed variant object
193226 * @param params - Actual parameter array
227+ * @param syntax - Command syntax to determine if it's a function
194228 * @returns Array of type mismatches
195229 */
196- checkTypeMismatches ( variant : ParsedVariant , params : DocumentationParameter [ ] ) : TypeMismatch [ ] {
230+ checkTypeMismatches ( variant : ParsedVariant , params : DocumentationParameter [ ] , syntax ?: string ) : TypeMismatch [ ] {
197231 const typeMismatches : TypeMismatch [ ] = [ ] ;
198232
199233 variant . parameters . forEach ( parsedParam => {
@@ -205,7 +239,7 @@ export class SyntaxChecker {
205239 const parsedName = parsedParam . name . toLowerCase ( ) ;
206240
207241 // Match by name but exclude function result parameters
208- return paramName === parsedName && ! this . isFunctionResult ( p ) ;
242+ return paramName === parsedName && ! this . isFunctionResult ( p , syntax ) ;
209243 } ) ;
210244
211245 if ( actualParam && parsedParam . type !== 'unknown' ) {
@@ -230,28 +264,37 @@ export class SyntaxChecker {
230264 * Check for return type mismatches between parsed and actual parameters
231265 * @param variant - Parsed variant object
232266 * @param params - Actual parameter array
267+ * @param syntax - Command syntax to determine if it declares a return type
233268 * @returns Array of return type mismatches
234269 */
235- checkReturnTypeMismatches ( variant : ParsedVariant , params : DocumentationParameter [ ] ) : TypeMismatch [ ] {
270+ checkReturnTypeMismatches ( variant : ParsedVariant , params : DocumentationParameter [ ] , syntax ?: string ) : TypeMismatch [ ] {
236271 const returnTypeMismatches : TypeMismatch [ ] = [ ] ;
237272
238273 // Check if the parsed variant has return type information
239274 if ( ! variant . returnType ) {
240275 return returnTypeMismatches ;
241276 }
242277
243- // Find the actual return type parameter (Result, Function result, or by specific name)
278+ // Find the actual return type parameter
279+ // If syntax declares a return type, look for ANY parameter with Return direction
280+ // Otherwise, match by specific name if provided in the variant
244281 const actualReturnParam = params . find ( p => {
245282 const direction = p . direction ;
246283 const name = p . name . toLowerCase ( ) ;
247284
248- // Check if it's the function result by name and direction
249- if ( this . isFunctionResult ( p ) ) {
285+ // Not a return direction parameter
286+ if ( direction !== Direction . Return ) {
287+ return false ;
288+ }
289+
290+ // If syntax declares a return type, any Return parameter matches
291+ if ( syntax && this . syntaxHasReturnType ( syntax ) ) {
250292 return true ;
251293 }
252294
253- // If variant has a specific return name, match by name and direction
254- if ( variant . returnType ! . name && direction === Direction . Return &&
295+ // Otherwise, match by specific name if variant provides one
296+ // This handles edge cases like named output parameters
297+ if ( variant . returnType ! . name &&
255298 name === variant . returnType ! . name . toLowerCase ( ) ) {
256299 return true ;
257300 }
@@ -275,7 +318,7 @@ export class SyntaxChecker {
275318
276319 if ( ! this . isTypeValid ( syntaxType , actualType ) ) {
277320 returnTypeMismatches . push ( {
278- name : variant . returnType ! . name || 'Function result' ,
321+ name : variant . returnType ! . name || actualReturnParam . name ,
279322 syntaxType : syntaxType ,
280323 paramsType : actualType
281324 } ) ;
@@ -340,9 +383,10 @@ export class SyntaxChecker {
340383 * @param variant - Parsed variant object
341384 * @param params - Actual parameter array (can be empty/undefined)
342385 * @param actualParamNames - Array of actual parameter names (can be empty)
386+ * @param syntax - Command syntax to determine if it's a function
343387 * @returns True if variant has any issues at current warning level
344388 */
345- private hasVariantIssues ( variant : ParsedVariant , params : DocumentationParameter [ ] = [ ] , actualParamNames : string [ ] = [ ] ) : boolean {
389+ private hasVariantIssues ( variant : ParsedVariant , params : DocumentationParameter [ ] = [ ] , actualParamNames : string [ ] = [ ] , syntax ?: string ) : boolean {
346390 // Always check for malformations first
347391 const hasMalformation = this . hasRelevantMalformation ( variant ) ;
348392
@@ -351,7 +395,7 @@ export class SyntaxChecker {
351395 return hasMalformation ;
352396 }
353397
354- const { extraParams, typeMismatches, returnTypeMismatches } = this . validateVariantParameters ( variant , params , actualParamNames ) ;
398+ const { extraParams, typeMismatches, returnTypeMismatches } = this . validateVariantParameters ( variant , params , actualParamNames , syntax ) ;
355399 const hasParameterErrors = extraParams . length > 0 || typeMismatches . length > 0 || returnTypeMismatches . length > 0 ;
356400
357401 return hasMalformation || hasParameterErrors ;
@@ -363,8 +407,9 @@ export class SyntaxChecker {
363407 * @param index - Variant index
364408 * @param params - Actual parameter array
365409 * @param actualParamNames - Array of actual parameter names
410+ * @param syntax - Command syntax to determine if it's a function
366411 */
367- outputVariantAnalysis ( variant : ParsedVariant , index : number , params : DocumentationParameter [ ] , actualParamNames : string [ ] ) : void {
412+ outputVariantAnalysis ( variant : ParsedVariant , index : number , params : DocumentationParameter [ ] , actualParamNames : string [ ] , syntax ?: string ) : void {
368413 console . log ( `\nVariant ${ index + 1 } analysis:` ) ;
369414 const parsedParamNames = variant . parameters . map ( p => p . name . toLowerCase ( ) ) ;
370415 console . log ( 'Parsed parameter names:' , parsedParamNames ) ;
@@ -379,7 +424,7 @@ export class SyntaxChecker {
379424 } ) ;
380425 }
381426
382- const { extraParams, typeMismatches, returnTypeMismatches } = this . validateVariantParameters ( variant , params , actualParamNames ) ;
427+ const { extraParams, typeMismatches, returnTypeMismatches } = this . validateVariantParameters ( variant , params , actualParamNames , syntax ) ;
383428
384429 if ( extraParams . length > 0 ) {
385430 console . log ( `⚠️ Extra/Invalid parameters: ${ extraParams . join ( ', ' ) } ` ) ;
@@ -420,12 +465,12 @@ export class SyntaxChecker {
420465
421466 // Check if there are any errors/warnings
422467 let hasErrors = false ;
423- const actualParamNames = params && params . length > 0 ? this . getInputParameterNames ( params ) : [ ] ;
468+ const actualParamNames = params && params . length > 0 ? this . getInputParameterNames ( params , syntax ) : [ ] ;
424469 const allParamInfo = params && params . length > 0 ? this . extractActualParamNames ( params ) : [ ] ;
425470
426471 // Check each parsed variant for issues (malformations and parameter errors)
427472 parsedParams . forEach ( ( variant ) => {
428- if ( this . hasVariantIssues ( variant , params , actualParamNames ) ) {
473+ if ( this . hasVariantIssues ( variant , params , actualParamNames , syntax ) ) {
429474 hasErrors = true ;
430475 }
431476 } ) ;
@@ -444,7 +489,7 @@ export class SyntaxChecker {
444489
445490 // Check each parsed variant
446491 parsedParams . forEach ( ( variant , index ) => {
447- this . outputVariantAnalysis ( variant , index , params , actualParamNames ) ;
492+ this . outputVariantAnalysis ( variant , index , params , actualParamNames , syntax ) ;
448493 } ) ;
449494 } else {
450495 console . log ( '\nNo Params field found for this command' ) ;
0 commit comments