@@ -362,20 +362,7 @@ function checkFixture(manKey, fixKey, fixtureJson, uniqueValues = null) {
362
362
rangesInvalid = ! checkRange ( i ) ;
363
363
}
364
364
365
- const switchingChannelAliases = Object . keys ( cap . switchChannels ) ;
366
- if ( ! arraysEqual ( switchingChannelAliases , channel . switchingChannelAliases ) ) {
367
- result . errors . push ( `Capability '${ cap . name } ' (#${ i + 1 } ) must define the same switching channel aliases as all other capabilities in channel '${ channel . key } '.` ) ;
368
- }
369
- else {
370
- for ( const alias of switchingChannelAliases ) {
371
- const chKey = cap . switchChannels [ alias ] ;
372
- usedChannelKeys . add ( chKey . toLowerCase ( ) ) ;
373
-
374
- if ( channel . fixture . getChannelByKey ( chKey ) === null ) {
375
- result . errors . push ( `Channel '${ chKey } ' is referenced from capability '${ cap . name } ' (#${ i + 1 } ) in channel '${ channel . key } ' but is not defined.` ) ;
376
- }
377
- }
378
- }
365
+ checkCapability ( cap , `Capability '${ cap . name } ' (${ cap . rawDmxRange } ) in channel '${ channel . key } '` ) ;
379
366
}
380
367
381
368
/**
@@ -434,6 +421,28 @@ function checkFixture(manKey, fixKey, fixtureJson, uniqueValues = null) {
434
421
435
422
return values ;
436
423
}
424
+
425
+ /**
426
+ * Check that a capability is valid (except its DMX range).
427
+ * @param {!Capability } cap The capability to check.
428
+ * @param {!string } errorPrefix An identifier for the capability to use in errors and warnings.
429
+ */
430
+ function checkCapability ( cap , errorPrefix ) {
431
+ const switchingChannelAliases = Object . keys ( cap . switchChannels ) ;
432
+ if ( ! arraysEqual ( switchingChannelAliases , channel . switchingChannelAliases ) ) {
433
+ result . errors . push ( `${ errorPrefix } must define the same switching channel aliases as all other capabilities.` ) ;
434
+ }
435
+ else {
436
+ switchingChannelAliases . forEach ( alias => {
437
+ const chKey = cap . switchChannels [ alias ] ;
438
+ usedChannelKeys . add ( chKey . toLowerCase ( ) ) ;
439
+
440
+ if ( channel . fixture . getChannelByKey ( chKey ) === null ) {
441
+ result . errors . push ( `${ errorPrefix } references unknown channel '${ chKey } '.` ) ;
442
+ }
443
+ } ) ;
444
+ }
445
+ }
437
446
}
438
447
}
439
448
@@ -707,41 +716,107 @@ function checkFixture(manKey, fixKey, fixtureJson, uniqueValues = null) {
707
716
* Checks if the used channels fits to the fixture's categories and raise warnings suggesting to add/remove a category.
708
717
*/
709
718
function checkCategories ( ) {
710
- const fixtureChannels = fixture . availableChannels . concat ( fixture . matrixChannels . map ( matrixCh => matrixCh . wrappedChannel ) ) ;
719
+ const categories = {
720
+ 'Color Changer' : {
721
+ isSuggested : isColorChanger ( ) ,
722
+ suggestedPhrase : `there are at least one 'Multi-Color' or two 'Single Color' channels` ,
723
+ invalidPhrase : `there is no 'Multi-Color' and less than two 'Single Color' channels`
724
+ } ,
725
+ 'Moving Head' : {
726
+ isSuggested : isMovingHead ( ) ,
727
+ isInvalid : isNotMovingHead ( ) ,
728
+ suggestedPhrase : `focus.type is 'Head' or there's a 'Pan' and a 'Tilt' capability` ,
729
+ invalidPhrase : `focus.type is not 'Head'`
730
+ } ,
731
+ 'Scanner' : {
732
+ isSuggested : isScanner ( ) ,
733
+ isInvalid : isNotScanner ( ) ,
734
+ suggestedPhrase : `focus.type is 'Mirror' or there's a 'Pan' and a 'Tilt' capability` ,
735
+ invalidPhrase : `focus.type is not 'Mirror'`
736
+ } ,
737
+ 'Smoke' : {
738
+ isInvalid : ! hasChannelOfType ( `Fog` ) ,
739
+ invalidPhrase : `there is not 'Fog' channel.`
740
+ } ,
741
+ 'Hazer' : {
742
+ isInvalid : ! hasChannelOfType ( `Fog` ) ,
743
+ invalidPhrase : `there is not 'Fog' channel.`
744
+ }
745
+ } ;
746
+
747
+ for ( const categoryName of Object . keys ( categories ) ) {
748
+ const categoryUsed = fixture . categories . includes ( categoryName ) ;
749
+ const category = categories [ categoryName ] ;
711
750
712
- const hasMultiColorChannel = fixtureChannels . some ( channel => channel . type === `Multi-Color` ) ;
713
- const hasMultipleSingleColorChannels = fixtureChannels . filter ( channel => channel . type === `Single Color` ) . length > 1 ;
714
- const hasColorChangerCategory = fixture . categories . includes ( `Color Changer` ) ;
715
- if ( ! hasColorChangerCategory && hasMultiColorChannel ) {
716
- result . warnings . push ( `Category 'Color Changer' suggested since there is a 'Multi-Color' channel.` ) ;
751
+ if ( ! ( `isInvalid` in category ) ) {
752
+ category . isInvalid = ! category . isSuggested ;
753
+ }
754
+
755
+ if ( ! categoryUsed && category . isSuggested ) {
756
+ result . warnings . push ( `Category '${ categoryName } ' suggested since ${ category . suggestedPhrase } .` ) ;
757
+ }
758
+ else if ( categoryUsed && category . isInvalid ) {
759
+ result . errors . push ( `Category '${ categoryName } ' invalid since ${ category . invalidPhrase } .` ) ;
760
+ }
717
761
}
718
- else if ( ! hasColorChangerCategory && hasMultipleSingleColorChannels ) {
719
- result . warnings . push ( `Category 'Color Changer' suggested since there are multiple 'Single Color' channels.` ) ;
762
+
763
+ /**
764
+ * @returns {!boolean } Whether the 'Color Changer' category is suggested.
765
+ */
766
+ function isColorChanger ( ) {
767
+ return hasChannelOfType ( `Multi-Color` ) || hasChannelOfType ( `Single Color` , 2 ) ;
720
768
}
721
- else if ( hasColorChangerCategory && ! hasMultiColorChannel && ! hasMultipleSingleColorChannels ) {
722
- result . warnings . push ( `Category 'Color Changer' invalid since there is no 'Multi-Color' and less than 2 'Single Color' channels.` ) ;
769
+
770
+ /**
771
+ * @returns {!boolean } Whether the 'Moving Head' category is suggested.
772
+ */
773
+ function isMovingHead ( ) {
774
+ const hasFocusTypeHead = fixture . physical !== null && fixture . physical . focusType === `Head` ;
775
+ const hasOtherFocusType = fixture . physical !== null && fixture . physical . focusType !== null ;
776
+
777
+ return hasFocusTypeHead || ( hasPanTiltChannels ( ) && ! hasOtherFocusType ) ;
723
778
}
724
779
725
- const hasFocusTypeHead = fixture . physical !== null && fixture . physical . focusType === `Head` ;
726
- const hasMovingHeadCategory = fixture . categories . includes ( `Moving Head` ) ;
727
- if ( ! hasMovingHeadCategory && hasFocusTypeHead ) {
728
- result . warnings . push ( `Category 'Moving Head' suggested since focus.type is 'Head'.` ) ;
780
+ /**
781
+ * @returns {!boolean } Whether the 'Moving Head' category is invalid.
782
+ */
783
+ function isNotMovingHead ( ) {
784
+ return fixture . physical === null || fixture . physical . focusType !== `Head` ;
729
785
}
730
- else if ( hasMovingHeadCategory && ! hasFocusTypeHead ) {
731
- result . warnings . push ( `Category 'Moving Head' invalid since focus.type is not 'Head'.` ) ;
786
+
787
+ /**
788
+ * @returns {!boolean } Whether the 'Scanner' category is suggested.
789
+ */
790
+ function isScanner ( ) {
791
+ const hasFocusTypeMirror = fixture . physical !== null && fixture . physical . focusType === `Mirror` ;
792
+ const hasOtherFocusType = fixture . physical !== null && fixture . physical . focusType !== null ;
793
+
794
+ return hasFocusTypeMirror || ( hasPanTiltChannels ( ) && ! hasOtherFocusType ) ;
732
795
}
733
796
734
- const hasFogChannel = fixtureChannels . some ( channel => channel . type === `Fog` ) ;
735
- const hasSmokeCategory = fixture . categories . includes ( `Smoke` ) ;
736
- const hasHazerCategory = fixture . categories . includes ( `Hazer` ) ;
737
- if ( ! ( hasSmokeCategory || hasHazerCategory ) && hasFogChannel ) {
738
- result . warnings . push ( `Categories 'Smoke' and/or 'Hazer' suggested since there is a 'Fog' channel.` ) ;
797
+ /**
798
+ * @returns { !boolean } Whether the 'Scanner' category is invalid.
799
+ */
800
+ function isNotScanner ( ) {
801
+ return fixture . physical === null || fixture . physical . focusType !== `Mirror` ;
739
802
}
740
- else if ( hasSmokeCategory && ! hasFogChannel ) {
741
- result . warnings . push ( `Category 'Smoke' invalid since there is no 'Fog' channel.` ) ;
803
+
804
+ /**
805
+ * @returns {!boolean } Whether the fixture has both a Pan and a Tilt channel.
806
+ */
807
+ function hasPanTiltChannels ( ) {
808
+ return hasChannelOfType ( `Pan` ) && hasChannelOfType ( `Tilt` ) ;
742
809
}
743
- else if ( hasHazerCategory && ! hasFogChannel ) {
744
- result . warnings . push ( `Category 'Hazer' invalid since there is no 'Fog' channel.` ) ;
810
+
811
+ /**
812
+ * @param {!string } type What channel type to search for.
813
+ * @param {!number } [minimum=1] How many occurences are needed to succeed.
814
+ * @returns {!boolean } Whether the given channel type occurs at least at the given minimum times in the fixture.
815
+ */
816
+ function hasChannelOfType ( type , minimum = 1 ) {
817
+ return fixture . normalizedChannels . filter (
818
+ ch => ch . type === type
819
+ ) . length >= minimum ;
745
820
}
746
821
}
747
822
0 commit comments