@@ -537,6 +537,12 @@ export function findNodeAtOffset(node: ASTNode, offset: number, includeRightBoun
537
537
return undefined ;
538
538
}
539
539
540
+ interface IValidationMatch {
541
+ schema : JSONSchema ;
542
+ validationResult : ValidationResult ;
543
+ matchingSchemas : ISchemaCollector ;
544
+ }
545
+
540
546
export class JSONDocument {
541
547
public isKubernetes : boolean ;
542
548
public disableAdditionalProperties : boolean ;
@@ -870,7 +876,7 @@ function validate(
870
876
const val = getNodeValue ( node ) ;
871
877
let enumValueMatch = false ;
872
878
for ( const e of schema . enum ) {
873
- if ( val === e || ( callFromAutoComplete && isString ( val ) && isString ( e ) && val && e . startsWith ( val ) ) ) {
879
+ if ( val === e || isAutoCompleteEqualMaybe ( callFromAutoComplete , node , val , e ) ) {
874
880
enumValueMatch = true ;
875
881
break ;
876
882
}
@@ -902,10 +908,7 @@ function validate(
902
908
903
909
if ( isDefined ( schema . const ) ) {
904
910
const val = getNodeValue ( node ) ;
905
- if (
906
- ! equals ( val , schema . const ) &&
907
- ! ( callFromAutoComplete && isString ( val ) && isString ( schema . const ) && schema . const . startsWith ( val ) )
908
- ) {
911
+ if ( ! equals ( val , schema . const ) && ! isAutoCompleteEqualMaybe ( callFromAutoComplete , node , val , schema . const ) ) {
909
912
validationResult . problems . push ( {
910
913
location : { offset : node . offset , length : node . length } ,
911
914
severity : DiagnosticSeverity . Warning ,
@@ -1508,23 +1511,11 @@ function validate(
1508
1511
node : ASTNode ,
1509
1512
maxOneMatch ,
1510
1513
subValidationResult : ValidationResult ,
1511
- bestMatch : {
1512
- schema : JSONSchema ;
1513
- validationResult : ValidationResult ;
1514
- matchingSchemas : ISchemaCollector ;
1515
- } ,
1514
+ bestMatch : IValidationMatch ,
1516
1515
subSchema ,
1517
1516
subMatchingSchemas
1518
- ) : {
1519
- schema : JSONSchema ;
1520
- validationResult : ValidationResult ;
1521
- matchingSchemas : ISchemaCollector ;
1522
- } {
1523
- if (
1524
- ! maxOneMatch &&
1525
- ! subValidationResult . hasProblems ( ) &&
1526
- ( ! bestMatch . validationResult . hasProblems ( ) || callFromAutoComplete )
1527
- ) {
1517
+ ) : IValidationMatch {
1518
+ if ( ! maxOneMatch && ! subValidationResult . hasProblems ( ) && ! bestMatch . validationResult . hasProblems ( ) ) {
1528
1519
// no errors, both are equally good matches
1529
1520
bestMatch . matchingSchemas . merge ( subMatchingSchemas ) ;
1530
1521
bestMatch . validationResult . propertiesMatches += subValidationResult . propertiesMatches ;
@@ -1545,19 +1536,30 @@ function validate(
1545
1536
validationResult : subValidationResult ,
1546
1537
matchingSchemas : subMatchingSchemas ,
1547
1538
} ;
1548
- } else if ( compareResult === 0 ) {
1539
+ } else if (
1540
+ compareResult === 0 ||
1541
+ ( ( node . value === null || node . type === 'null' ) && node . length === 0 ) // node with no value can match any schema potentially
1542
+ ) {
1549
1543
// there's already a best matching but we are as good
1550
- bestMatch . matchingSchemas . merge ( subMatchingSchemas ) ;
1551
- bestMatch . validationResult . mergeEnumValues ( subValidationResult ) ;
1552
- bestMatch . validationResult . mergeWarningGeneric ( subValidationResult , [
1553
- ProblemType . missingRequiredPropWarning ,
1554
- ProblemType . typeMismatchWarning ,
1555
- ProblemType . constWarning ,
1556
- ] ) ;
1544
+ mergeValidationMatches ( bestMatch , subMatchingSchemas , subValidationResult ) ;
1557
1545
}
1558
1546
}
1559
1547
return bestMatch ;
1560
1548
}
1549
+
1550
+ function mergeValidationMatches (
1551
+ bestMatch : IValidationMatch ,
1552
+ subMatchingSchemas : ISchemaCollector ,
1553
+ subValidationResult : ValidationResult
1554
+ ) : void {
1555
+ bestMatch . matchingSchemas . merge ( subMatchingSchemas ) ;
1556
+ bestMatch . validationResult . mergeEnumValues ( subValidationResult ) ;
1557
+ bestMatch . validationResult . mergeWarningGeneric ( subValidationResult , [
1558
+ ProblemType . missingRequiredPropWarning ,
1559
+ ProblemType . typeMismatchWarning ,
1560
+ ProblemType . constWarning ,
1561
+ ] ) ;
1562
+ }
1561
1563
}
1562
1564
1563
1565
function getSchemaSource ( schema : JSONSchema , originalSchema : JSONSchema ) : string | undefined {
@@ -1595,3 +1597,26 @@ function getSchemaUri(schema: JSONSchema, originalSchema: JSONSchema): string[]
1595
1597
function getWarningMessage ( problemType : ProblemType , args : string [ ] ) : string {
1596
1598
return localize ( problemType , ProblemTypeMessages [ problemType ] , args . join ( ' | ' ) ) ;
1597
1599
}
1600
+
1601
+ /**
1602
+ * if callFromAutoComplete than compare value from yaml and value from schema (s.const | s.enum[i])
1603
+ * allows partial match for autocompletion
1604
+ */
1605
+ function isAutoCompleteEqualMaybe (
1606
+ callFromAutoComplete : boolean ,
1607
+ node : ASTNode ,
1608
+ nodeValue : unknown ,
1609
+ schemaValue : unknown
1610
+ ) : boolean {
1611
+ if ( ! callFromAutoComplete ) {
1612
+ return false ;
1613
+ }
1614
+
1615
+ // if autocompletion property doesn't have value, then it could be a match
1616
+ const isWithoutValue = nodeValue === null && node . length === 0 ; // allows `prop: ` but ignore `prop: null`
1617
+ if ( isWithoutValue ) {
1618
+ return true ;
1619
+ }
1620
+
1621
+ return isString ( nodeValue ) && isString ( schemaValue ) && schemaValue . startsWith ( nodeValue ) ;
1622
+ }
0 commit comments