# Javascript Templates
Templates:
    # Syntax
    EqualitySyntaxTemplate: &EqualitySyntaxTemplate !!js/function >
        (lhs, op, rhs) => {
            if (op.includes('!')) {
                return `${lhs} != ${rhs}`;
            }
            else {
                return `${lhs} == ${rhs}`;
            }
        }
    EosTemplate: &EosSyntaxTemplate null
    EofTemplate: &EofSyntaxTemplate null
    # BSON Object Type templates
    CodeTypeTemplate: &CodeTypeTemplate null
    StringTypeTemplate: &StringTypeTemplate null
    RegexTypeTemplate: &RegexTypeTemplate null
    BoolTypeTemplate: &BoolTypeTemplate null
    IntegerTypeTemplate: &IntegerTypeTemplate null
    DecimalTypeTemplate: &DecimalTypeTemplate null
    LongBasicTypeTemplate: &LongBasicTypeTemplate null
    HexTypeTemplate: &HexTypeTemplate null
    OctalTypeTemplate: &OctalTypeTemplate null
    NumericTypeTemplate: &NumericTypeTemplate null
    ArrayTypeTemplate: &ArrayTypeTemplate !!js/function >
        (literal, depth) => {
            if (literal === '') {
                return '[]'
            }
            const indent = '\n' + '  '.repeat(depth);
            const closingIndent = '\n' + '  '.repeat(depth - 1);

            return `[${indent}${literal}${closingIndent}]`;
        }
    ArrayTypeArgsTemplate: &ArrayTypeArgsTemplate null
    NullTypeTemplate: &NullTypeTemplate !!js/function >
        () => {
            return 'null';
        }
    UndefinedTypeTemplate: &UndefinedTypeTemplate !!js/function >
        () => {
            return 'undefined';
        }
    ObjectTypeTemplate: &ObjectTypeTemplate !!js/function >
        (literal) => {
            if (literal === '') {
                return '{}';
            }
            return literal;
        }
    ObjectTypeArgsTemplate: &ObjectTypeArgsTemplate !!js/function >
        (args, depth) => {
            const indent = '\n' + '  '.repeat(depth);
            const closingIndent = '\n' + '  '.repeat(depth - 1);
            const pairs = args.map((arg) => {
                return `${indent}${arg[0]}: ${arg[1]}`;
            }).join(', ');

            return `{${pairs}${closingIndent}}`
        }
    # BSON Object Method templates
    CodeCodeTemplate: &CodeCodeTemplate null
    CodeCodeArgsTemplate: &CodeCodeArgsTemplate null
    CodeScopeTemplate: &CodeScopeTemplate null
    CodeScopeArgsTemplate: &CodeScopeArgsTemplate null
    ObjectIdToStringTemplate: &ObjectIdToStringTemplate null
    ObjectIdToStringArgsTemplate: &ObjectIdToStringArgsTemplate null
    ObjectIdEqualsTemplate: &ObjectIdEqualsTemplate null
    ObjectIdEqualsArgsTemplate: &ObjectIdEqualsArgsTemplate null
    ObjectIdGetTimestampTemplate: &ObjectIdGetTimestampTemplate null
    ObjectIdGetTimestampArgsTemplate: &ObjectIdGetTimestampArgsTemplate null
    BinaryValueTemplate: &BinaryValueTemplate null
    BinaryValueArgsTemplate: &BinaryValueArgsTemplate null
    BinaryLengthTemplate: &BinaryLengthTemplate null
    BinaryLengthArgsTemplate: &BinaryLengthArgsTemplate null
    BinaryToStringTemplate: &BinaryToStringTemplate null
    BinaryToStringArgsTemplate: &BinaryToStringArgsTemplate null
    BinarySubtypeTemplate: &BinarySubtypeTemplate !!js/function >
        (lhs) => {
            return `${lhs}.sub_type`;
        }
    BinarySubtypeArgsTemplate: &BinarySubtypeArgsTemplate !!js/function >
        () => {
            return '';
        }
    DBRefGetDBTemplate: &DBRefGetDBTemplate !!js/function >
        (lhs) => {
            return `${lhs}.db`;
        }
    DBRefGetCollectionTemplate: &DBRefGetCollectionTemplate !!js/function >
        (lhs) => {
            return `${lhs}.namespace`;
        }
    DBRefGetIdTemplate: &DBRefGetIdTemplate !!js/function >
        (lhs) => {
            return `${lhs}.oid`;
        }
    DBRefGetDBArgsTemplate: &DBRefGetDBArgsTemplate !!js/function >
        () => {
            return '';
        }
    DBRefGetCollectionArgsTemplate: &DBRefGetCollectionArgsTemplate !!js/function >
        () => {
            return '';
        }
    DBRefGetIdArgsTemplate: &DBRefGetIdArgsTemplate !!js/function >
        () => {
            return '';
        }
    DBRefToStringTemplate: &DBRefToStringTemplate null
    DBRefToStringArgsTemplate: &DBRefToStringArgsTemplate null
    DoubleValueOfTemplate: &DoubleValueOfTemplate null
    DoubleValueOfArgsTemplate: &DoubleValueOfArgsTemplate null
    Int32ValueOfTemplate: &Int32ValueOfTemplate null
    Int32ValueOfArgsTemplate: &Int32ValueOfArgsTemplate null
    Int32ToStringTemplate: &Int32ToStringTemplate null
    Int32ToStringArgsTemplate: &Int32ToStringArgsTemplate null
    LongEqualsTemplate: &LongEqualsTemplate null
    LongEqualsArgsTemplate: &LongEqualsArgsTemplate null
    LongToStringTemplate: &LongToStringTemplate null # Has emit method
    LongToStringArgsTemplate: &LongToStringArgsTemplate null
    LongToIntTemplate: &LongToIntTemplate !!js/function >
        (lhs) => {
            return `${lhs}.toInt`;
        }
    LongToIntArgsTemplate: &LongToIntArgsTemplate null
    LongValueOfTemplate: &LongValueOfTemplate !!js/function >
        (lhs) => {
            return `${lhs}.toInt`;
        }
    LongValueOfArgsTemplate: &LongValueOfArgsTemplate null
    LongToNumberTemplate: &LongToNumberTemplate null
    LongToNumberArgsTemplate: &LongToNumberArgsTemplate null
    LongAddTemplate: &LongAddTemplate null
    LongAddArgsTemplate: &LongAddArgsTemplate null
    LongSubtractTemplate: &LongSubtractTemplate null
    LongSubtractArgsTemplate: &LongSubtractArgsTemplate null
    LongMultiplyTemplate: &LongMultiplyTemplate null
    LongMultiplyArgsTemplate: &LongMultiplyArgsTemplate null
    LongDivTemplate: &LongDivTemplate null
    LongDivArgsTemplate: &LongDivArgsTemplate null
    LongModuloTemplate: &LongModuloTemplate null
    LongModuloArgsTemplate: &LongModuloArgsTemplate null
    LongAndTemplate: &LongAndTemplate null
    LongAndArgsTemplate: &LongAndArgsTemplate null
    LongOrTemplate: &LongOrTemplate null
    LongOrArgsTemplate: &LongOrArgsTemplate null
    LongXorTemplate: &LongXorTemplate null
    LongXorArgsTemplate: &LongXorArgsTemplate null
    LongShiftLeftTemplate: &LongShiftLeftTemplate null
    LongShiftLeftArgsTemplate: &LongShiftLeftArgsTemplate null
    LongShiftRightTemplate: &LongShiftRightTemplate null
    LongShiftRightArgsTemplate: &LongShiftRightArgsTemplate null
    LongCompareTemplate: &LongCompareTemplate null
    LongCompareArgsTemplate: &LongCompareArgsTemplate null
    LongIsOddTemplate: &LongIsOddTemplate null
    LongIsOddArgsTemplate: &LongIsOddArgsTemplate null
    LongIsZeroTemplate: &LongIsZeroTemplate null
    LongIsZeroArgsTemplate: &LongIsZeroArgsTemplate null
    LongIsNegativeTemplate: &LongIsNegativeTemplate null
    LongIsNegativeArgsTemplate: &LongIsNegativeArgsTemplate null
    LongNegateTemplate: &LongNegateTemplate null
    LongNegateArgsTemplate: &LongNegateArgsTemplate null
    LongNotTemplate: &LongNotTemplate null
    LongNotArgsTemplate: &LongNotArgsTemplate null
    LongNotEqualsTemplate: &LongNotEqualsTemplate null
    LongNotEqualsArgsTemplate: &LongNotEqualsArgsTemplate null
    LongGreaterThanTemplate: &LongGreaterThanTemplate null
    LongGreaterThanArgsTemplate: &LongGreaterThanArgsTemplate null
    LongGreaterThanOrEqualTemplate: &LongGreaterThanOrEqualTemplate null
    LongGreaterThanOrEqualArgsTemplate: &LongGreaterThanOrEqualArgsTemplate null
    LongLessThanTemplate: &LongLessThanTemplate null
    LongLessThanArgsTemplate: &LongLessThanArgsTemplate null
    LongLessThanOrEqualTemplate: &LongLessThanOrEqualTemplate null
    LongLessThanOrEqualArgsTemplate: &LongLessThanOrEqualArgsTemplate null
    LongFloatApproxTemplate: &LongFloatApproxTemplate !!js/function >
        (lhs) => {
            return `${lhs}.toNumber()`;
        }
    LongTopTemplate: &LongTopTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getHighBits()`;
        }
    LongBottomTemplate: &LongBottomTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getLowBits()`;
        }
    TimestampToStringTemplate: &TimestampToStringTemplate null
    TimestampToStringArgsTemplate: &TimestampToStringArgsTemplate null
    TimestampEqualsTemplate: &TimestampEqualsTemplate null
    TimestampEqualsArgsTemplate: &TimestampEqualsArgsTemplate null
    TimestampGetLowBitsTemplate: &TimestampGetLowBitsTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getLowBits`;
        }
    TimestampGetLowBitsArgsTemplate: &TimestampGetLowBitsArgsTemplate null
    TimestampGetHighBitsTemplate: &TimestampGetHighBitsTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getHighBits`;
        }
    TimestampGetHighBitsArgsTemplate: &TimestampGetHighBitsArgsTemplate null
    TimestampTTemplate: &TimestampTTemplate !!js/function >
        (lhs) => {
            return `${lhs}.getLowBits()`;
        }
    TimestampITemplate: &TimestampITemplate !!js/function
        (lhs) => {
            return `${lhs}.getHighBits()`;
        }
    TimestampCompareTemplate: &TimestampCompareTemplate null
    TimestampCompareArgsTemplate: &TimestampCompareArgsTemplate null
    TimestampNotEqualsTemplate: &TimestampNotEqualsTemplate null
    TimestampNotEqualsArgsTemplate: &TimestampNotEqualsArgsTemplate null
    TimestampGreaterThanTemplate: &TimestampGreaterThanTemplate null
    TimestampGreaterThanArgsTemplate: &TimestampGreaterThanArgsTemplate null
    TimestampGreaterThanOrEqualTemplate: &TimestampGreaterThanOrEqualTemplate null
    TimestampGreaterThanOrEqualArgsTemplate: &TimestampGreaterThanOrEqualArgsTemplate null
    TimestampLessThanTemplate: &TimestampLessThanTemplate null
    TimestampLessThanArgsTemplate: &TimestampLessThanArgsTemplate null
    TimestampLessThanOrEqualTemplate: &TimestampLessThanOrEqualTemplate null
    TimestampLessThanOrEqualArgsTemplate: &TimestampLessThanOrEqualArgsTemplate null
    SymbolValueOfTemplate: &SymbolValueOfTemplate null
    SymbolValueOfArgsTemplate: &SymbolValueOfArgsTemplate null
    SymbolInspectTemplate: &SymbolInspectTemplate null
    SymbolInspectArgsTemplate: &SymbolInspectArgsTemplate null
    SymbolToStringTemplate: &SymbolToStringTemplate null
    SymbolToStringArgsTemplate: &SymbolToStringArgsTemplate null
    # Symbol Templates
    CodeSymbolTemplate: &CodeSymbolTemplate null
    CodeSymbolArgsTemplate: &CodeSymbolArgsTemplate !!js/function >
        (lhs, code, scope) => {
            code = code === undefined ? '\'\'' : code;
            scope = scope === undefined ? '' : `, ${scope}`;
            return `(${code}${scope})`;
        }
    ObjectIdSymbolTemplate: &ObjectIdSymbolTemplate null
    ObjectIdSymbolArgsTemplate: &ObjectIdSymbolArgsTemplate !!js/function >
        (lhs, str) => {
          let newStr = str;
          if (
            (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
            (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
            newStr = str.substr(1, str.length - 2);
          }
          return `('${newStr.replace(/\\([\s\S])|(")/g, '\\$1$2')}')`;
        }
    BinarySymbolTemplate: &BinarySymbolTemplate !!js/function >
        () => {
            return 'Binary';
        }
    BinarySymbolArgsTemplate: &BinarySymbolArgsTemplate !!js/function >
        (lhs, buffer, subtype) => {
            return `(${buffer.toString('base64')}, '${subtype}')`;
        }
    BinarySymbolSubtypeDefaultTemplate: &BinarySymbolSubtypeDefaultTemplate null
    BinarySymbolSubtypeFunctionTemplate: &BinarySymbolSubtypeFunctionTemplate null
    BinarySymbolSubtypeByteArrayTemplate: &BinarySymbolSubtypeByteArrayTemplate null
    BinarySymbolSubtypeUuidOldTemplate: &BinarySymbolSubtypeUuidOldTemplate null
    BinarySymbolSubtypeUuidTemplate: &BinarySymbolSubtypeUuidTemplate null
    BinarySymbolSubtypeMd5Template: &BinarySymbolSubtypeMd5Template null
    BinarySymbolSubtypeUserDefinedTemplate: &BinarySymbolSubtypeUserDefinedTemplate null
    DBRefSymbolTemplate: &DBRefSymbolTemplate null
    DBRefSymbolArgsTemplate: &DBRefSymbolArgsTemplate null
    DoubleSymbolTemplate: &DoubleSymbolTemplate null
    DoubleSymbolArgsTemplate: &DoubleSymbolArgsTemplate null
    Int32SymbolTemplate: &Int32SymbolTemplate !!js/function >
        () => {
            return 'Int32';
        }
    Int32SymbolArgsTemplate: &Int32SymbolArgsTemplate !!js/function >
        (lhs, arg) => {
            arg = arg === undefined ? 0 : arg;
            return `(${arg})`;
        }
    LongSymbolTemplate: &LongSymbolTemplate !!js/function >
        () => {
            return '';
        }
    LongSymbolArgsTemplate: &LongSymbolArgsTemplate !!js/function >
        (lhs, arg, type) => {
            arg = arg === undefined ? 0 : arg;
            if (type === '_string') {
                return `Long.fromString(${arg})`;
            }
            return `Long.fromNumber(${arg})`;
        }
    LongSymbolMaxTemplate: &LongSymbolMaxTemplate null
    LongSymbolMaxArgsTemplate: &LongSymbolMaxArgsTemplate null
    LongSymbolMinTemplate: &LongSymbolMinTemplate null
    LongSymbolMinArgsTemplate: &LongSymbolMinArgsTemplate null
    LongSymbolZeroTemplate: &LongSymbolZeroTemplate null
    LongSymbolZeroArgsTemplate: &LongSymbolZeroArgsTemplate null
    LongSymbolOneTemplate: &LongSymbolOneTemplate null
    LongSymbolOneArgsTemplate: &LongSymbolOneArgsTemplate null
    LongSymbolNegOneTemplate: &LongSymbolNegOneTemplate null
    LongSymbolNegOneArgsTemplate: &LongSymbolNegOneArgsTemplate null
    LongSymbolFromBitsTemplate: &LongSymbolFromBitsTemplate null
    LongSymbolFromBitsArgsTemplate: &LongSymbolFromBitsArgsTemplate null
    LongSymbolFromIntTemplate: &LongSymbolFromIntTemplate null
    LongSymbolFromIntArgsTemplate: &LongSymbolFromIntArgsTemplate null
    LongSymbolFromNumberTemplate: &LongSymbolFromNumberTemplate null
    LongSymbolFromNumberArgsTemplate: &LongSymbolFromNumberArgsTemplate null
    LongSymbolFromStringTemplate: &LongSymbolFromStringTemplate null
    LongSymbolFromStringArgsTemplate: &LongSymbolFromStringArgsTemplate null
    MinKeySymbolTemplate: &MinKeySymbolTemplate null
    MinKeySymbolArgsTemplate: &MinKeySymbolArgsTemplate null
    MaxKeySymbolTemplate: &MaxKeySymbolTemplate null
    MaxKeySymbolArgsTemplate: &MaxKeySymbolArgsTemplate null
    TimestampSymbolTemplate: &TimestampSymbolTemplate null
    TimestampSymbolArgsTemplate: &TimestampSymbolArgsTemplate !!js/function >
        (lhs, arg1, arg2) => {
            return `(${arg1 === undefined ? 0 : arg1}, ${arg2 === undefined ? 0 : arg2})`;
        }
    SymbolSymbolTemplate: &SymbolSymbolTemplate null
    SymbolSymbolArgsTemplate: &SymbolSymbolArgsTemplate null
    BSONRegExpSymbolTemplate: &BSONRegExpSymbolTemplate null # Has process method
    BSONRegExpSymbolArgsTemplate: &BSONRegExpSymbolArgsTemplate null
    Decimal128SymbolTemplate: &Decimal128SymbolTemplate !!js/function >
        () => {
            return 'Decimal128.fromString';
        }
    Decimal128SymbolArgsTemplate: &Decimal128SymbolArgsTemplate !!js/function >
        (lhs, arg) => {
            arg = arg === undefined ? '0' : arg.toString();
            if (arg.charAt(0) === '\'' && arg.charAt(arg.length - 1) === '\'') {
                return `(${arg})`;
            }
            return `('${arg}')`;
        }
    Decimal128SymbolFromStringTemplate: &Decimal128SymbolFromStringTemplate null
    Decimal128SymbolFromStringArgsTemplate: &Decimal128SymbolFromStringArgsTemplate null
    Decimal128ToStringTemplate: &Decimal128ToStringTemplate null
    Decimal128ToStringArgsTemplate: &Decimal128ToStringArgsTemplate null
    # BSON Util Templates
    ObjectIdCreateFromHexStringTemplate: &ObjectIdCreateFromHexStringTemplate null
    ObjectIdCreateFromHexStringArgsTemplate: &ObjectIdCreateFromHexStringArgsTemplate null
    ObjectIdCreateFromTimeTemplate: &ObjectIdCreateFromTimeTemplate !!js/function >
        (lhs) => {
            return `${lhs}.createFromTime`;
        }
    ObjectIdCreateFromTimeArgsTemplate: &ObjectIdCreateFromTimeArgsTemplate null
    ObjectIdIsValidTemplate: &ObjectIdIsValidTemplate null
    ObjectIdIsValidArgsTemplate: &ObjectIdIsValidArgsTemplate null
    # JS Symbol Templates
    ObjectSymbolTemplate: &ObjectSymbolTemplate null
    ObjectSymbolArgsTemplate: &ObjectSymbolArgsTemplate null
    ObjectSymbolCreateTemplate: &ObjectSymbolCreateTemplate null
    ObjectSymbolCreateArgsTemplate: &ObjectSymbolCreateArgsTemplate null
    NumberSymbolTemplate: &NumberSymbolTemplate null
    NumberSymbolArgsTemplate: &NumberSymbolArgsTemplate !!js/function >
        (lhs, arg) => {
            arg = arg === undefined ? '0' : arg;
            return `(${arg})`;
        }
    DateSymbolTemplate: &DateSymbolTemplate null
    DateSymbolArgsTemplate: &DateSymbolArgsTemplate null
    DateSymbolNowTemplate: &DateSymbolNowTemplate null
    DateSymbolNowArgsTemplate: &DateSymbolNowArgsTemplate null
    RegExpSymbolTemplate: &RegExpSymbolTemplate null
    RegExpSymbolArgsTemplate: &RegExpSymbolArgsTemplate null
    ImportTemplate: &ImportTemplate !!js/function >
        (args) => {
            const bson = [];
            const other = [];
            Object.keys(args).map(
                (m) => {
                    if (m > 99 && m < 200) {
                        bson.push(args[m]);
                    } else {
                        other.push(args[m]);
                    }
                }
            );
            if (bson.length) {
                other.push(`const {\n  ${bson.join(',\n  ')}\n} = require('mongo');`);
            }
            return other.join('\n');
        }
    0ImportTemplate: &0ImportTemplate null
    1ImportTemplate: &1ImportTemplate null
    2ImportTemplate: &2ImportTemplate null
    3ImportTemplate: &3ImportTemplate null
    4ImportTemplate: &4ImportTemplate null
    5ImportTemplate: &5ImportTemplate null
    6ImportTemplate: &6ImportTemplate null
    7ImportTemplate: &7ImportTemplate null
    8ImportTemplate: &8ImportTemplate null
    9ImportTemplate: &9ImportTemplate null
    10ImportTemplate: &10ImportTemplate null
    11ImportTemplate: &11ImportTemplate null
    12ImportTemplate: &12ImportTemplate null
    100ImportTemplate: &100ImportTemplate !!js/function >
        () => {
            return 'Code';
        }
    101ImportTemplate: &101ImportTemplate !!js/function >
        () => {
            return 'ObjectId';
        }
    102ImportTemplate: &102ImportTemplate !!js/function >
        () => {
            return 'Binary';
        }
    103ImportTemplate: &103ImportTemplate !!js/function >
        () => {
            return 'DBRef';
        }
    104ImportTemplate: &104ImportTemplate !!js/function >
        () => {
            return 'Double';
        }
    105ImportTemplate: &105ImportTemplate !!js/function >
        () => {
            return 'Int32';
        }
    106ImportTemplate: &106ImportTemplate !!js/function >
        () => {
            return 'Long';
        }
    107ImportTemplate: &107ImportTemplate !!js/function >
        () => {
            return 'MinKey';
        }
    108ImportTemplate: &108ImportTemplate !!js/function >
        () => {
            return 'MaxKey';
        }
    109ImportTemplate: &109ImportTemplate !!js/function >
        () => {
            return 'BSONRegExp';
        }
    110ImportTemplate: &110ImportTemplate !!js/function >
        () => {
            return 'Timestamp';
        }
    111ImportTemplate: &111ImportTemplate !!js/function >
        () => {
            return 'Symbol';
        }
    112ImportTemplate: &112ImportTemplate !!js/function >
        () => {
            return 'Decimal128';
        }
    113ImportTemplate: &113ImportTemplate null
    114ImportTemplate: &114ImportTemplate null
    200ImportTemplate: &200ImportTemplate null
    201ImportTemplate: &201ImportTemplate null
    300ImportTemplate: &300ImportTemplate null
    301ImportTemplate: &301ImportTemplate null
    302ImportTemplate: &302ImportTemplate null
    303ImportTemplate: &303ImportTemplate null
    304ImportTemplate: &304ImportTemplate null
    305ImportTemplate: &305ImportTemplate null
    306ImportTemplate: &306ImportTemplate null
