All files compareTypes.js

100% Statements 30/30
100% Branches 28/28
100% Functions 1/1
100% Lines 30/30

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                  1x                                         31x 31x   31x 1x     30x 1x     29x   28x 3x     25x 24x 24x     24x 10x       14x 6x                     10x 8x 8x 8x 1x   7x 9x 9x 9x 2x     5x     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.
			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 };