All files compareTypes.js

100% Statements 31/31
90% Branches 27/30
100% Functions 1/1
100% Lines 31/31

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92                  1x                                         30x 30x   30x 1x     29x 1x     28x   27x 3x     24x 23x 23x     23x 10x       13x 13x 6x                       9x 7x 7x 7x 1x   6x 9x 9x 9x 2x     4x     2x     1x  
'use strict';
 
const {
	convertZListToItemArray,
	findTypeIdentity,
	isBuiltInType,
	isZFunctionCall,
	isZReference,
	isZType
} = require( './utils.js' );
 
/**
 * Determine whether comparand type-compares to comparator.
 *
 * Type-comparison adheres to the following rules. Type A (comparand) type-compares
 * as type B (comparator) iff
 * - the identity of type B is Z1, OR
 * - the identity of type A is identical to that of type B, OR
 * - type A and type B are both Z4s, AND
 *   - for every key in type A, the key's type type-compares as the corresponding
 *     key in type B
 *
 * For the moment, type-comparison just doesn't touch generic types. If either
 * comparand or comparator is a function call, compareTypes returns true.
 *
 * @param {Object} comparand type A, as defined above
 * @param {Object} comparator type B, as defined above
 * @return {boolean} whether comparand type-compares as comparator
 */
function compareTypes( comparand, comparator ) {
	const comparandIdentity = findTypeIdentity( comparand );
	const comparatorIdentity = findTypeIdentity( comparator );
 
	if ( isZFunctionCall( comparandIdentity ) ) {
		return true;
	}
 
	if ( isZFunctionCall( comparatorIdentity ) ) {
		return true;
	}
 
	if ( isZReference( comparatorIdentity ) ) {
		// Case 1: comparatorIdentity is Z1.
		if ( comparatorIdentity.Z9K1 === 'Z1' ) {
			return true;
		}
 
		if ( isZReference( comparandIdentity ) ) {
			const comparandReference = comparandIdentity.Z9K1;
			const comparatorReference = comparatorIdentity.Z9K1;
 
			// Case 2: identities are identical references.
			if ( comparandReference === comparatorReference ) {
				return true;
			}
 
			// Case 3: at least one identity is built-in and the references are not equal.
			Eif ( comparandReference !== comparatorReference ) {
				if ( isBuiltInType( comparandReference ) || isBuiltInType( comparatorReference ) ) {
					return false;
				}
			}
		}
	}
 
	// If we reach this point, it means that the two types are user-defined
	// (and not generic for now; see function docstring). In this case, we
	// define type-comparison via a sort of duck-typing. If type A's keys stand
	// in a 1:1 relationship with type B's such that each key in type A
	// type-compares to the corresponding key in type B, then we say that the
	// two types type-compare.
	if ( isZType( comparator ) && isZType( comparand ) ) {
		const comparandKeys = convertZListToItemArray( comparand.Z4K2 || [] );
		const comparatorKeys = convertZListToItemArray( comparator.Z4K2 || [] );
		if ( comparatorKeys.length !== comparandKeys.length ) {
			return false;
		}
		for ( const index in comparatorKeys ) {
			const comparatorKey = comparatorKeys[ index ];
			const comparandKey = comparandKeys[ index ];
			if ( !compareTypes( comparandKey.Z3K1, comparatorKey.Z3K1 ) ) {
				return false;
			}
		}
		return true;
	}
 
	return false;
}
 
module.exports = { compareTypes };