All files compareTypes.js

100% Statements 25/25
100% Branches 18/18
100% Functions 1/1
100% Lines 25/25

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                1x                                         30x 30x   30x 1x     29x 1x     28x   17x 3x       14x 13x                   12x 10x 10x 10x 1x   9x 9x 9x 9x 2x     7x     2x     1x  
'use strict';
 
const {
	convertZListToItemArray,
	findIdentity,
	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 = findIdentity( comparand );
	const comparatorIdentity = findIdentity( 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;
		}
 
		// Case 2: identities are both references to built-in types.
		if ( isZReference( comparandIdentity ) ) {
			return comparandIdentity.Z9K1 === comparatorIdentity.Z9K1;
		}
	}
 
	// 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 };