text: // Licensed to the Software Freedom Conservancy (SFC) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The SFC licenses this file
  // to you under the Apache License, Version 2.0 (the
  // "License"); you may not use this file except in compliance
  // with the License.  You may obtain a copy of the License at
  //
  //   http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing,
  // software distributed under the License is distributed on an
  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied.  See the License for the
  // specific language governing permissions and limitations
  // under the License.
  
  'use strict'
  var __spreadArrays =
    (this && this.__spreadArrays) ||
    function () {
      for (var s = 0, i = 0, il = arguments.length; i < il; i++)
        s += arguments[i].length
      for (var r = Array(s), k = 0, i = 0; i < il; i++)
        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
          r[k] = a[j]
      return r
    }
  exports.__esModule = true
  var fs = require('fs')
  var path = require('path')
  console.log(process.argv)
  // TODO: @noj validate this via https://github.com/andischerer/typescript-json-typesafe against protocol-schema.d.ts
  var jsProtocol = JSON.parse(fs.readFileSync(process.argv[3]))
  var browserProtocol = JSON.parse(fs.readFileSync(process.argv[2]))
  var protocolDomains = jsProtocol.domains.concat(browserProtocol.domains)
  var numIndents = 0
  var emitStr = ''
  var emit = function (str) {
    emitStr += str
  }
  var getIndent = function () {
    return '    '.repeat(numIndents)
  } // 4 spaced indents
  var emitIndent = function () {
    emitStr += getIndent()
  }
  var emitLine = function (str) {
    if (str) {
      emitIndent()
      emit(str + '\n')
    } else {
      emit('\n')
    }
  }
  var emitOpenBlock = function (str, openChar) {
    if (openChar === void 0) {
      openChar = ' {'
    }
    emitLine('' + str + openChar)
    numIndents++
  }
  var emitCloseBlock = function (closeChar) {
    if (closeChar === void 0) {
      closeChar = '}'
    }
    numIndents--
    emitLine(closeChar)
  }
  var emitHeaderComments = function () {
    emitLine(
      '/**********************************************************************'
    )
    emitLine(
      ' * Auto-generated by protocol-dts-generator.ts, do not edit manually. *'
    )
    emitLine(
      ' **********************************************************************/'
    )
    emitLine()
  }
  var fixCamelCase = function (name) {
    var prefix = ''
    var result = name
    if (name[0] === '-') {
      prefix = 'Negative'
      result = name.substring(1)
    }
    var refined = result.split('-').map(toTitleCase).join('')
    return (
      prefix +
      refined.replace(/HTML|XML|WML|API/i, function (match) {
        return match.toUpperCase()
      })
    )
  }
  var emitEnum = function (enumName, enumValues) {
    emitOpenBlock('export const enum ' + enumName)
    enumValues.forEach(function (value) {
      emitLine(fixCamelCase(value) + " = '" + value + "',")
    })
    emitCloseBlock()
  }
  var emitModule = function (moduleName, domains) {
    moduleName = toTitleCase(moduleName)
    emitHeaderComments()
    emitOpenBlock('export namespace ' + moduleName)
    emitGlobalTypeDefs()
    domains.forEach(emitDomain)
    emitCloseBlock()
    emitLine()
    emitLine('export default ' + moduleName + ';')
  }
  var emitGlobalTypeDefs = function () {
    emitLine()
    emitLine('export type integer = number')
  }
  var emitDomain = function (domain) {
    var domainName = toTitleCase(domain.domain)
    emitLine()
    emitDescription(domain.description)
    emitOpenBlock('export namespace ' + domainName)
    if (domain.types) domain.types.forEach(emitDomainType)
    if (domain.commands) domain.commands.forEach(emitCommand)
    if (domain.events) domain.events.forEach(emitEvent)
    emitCloseBlock()
  }
  var getCommentLines = function (description) {
    var lines = description.split(/\r?\n/g).map(function (line) {
      return ' * ' + line
    })
    return __spreadArrays(['/**'], lines, [' */'])
  }
  var emitDescription = function (description) {
    if (description)
      getCommentLines(description).map(function (l) {
        return emitLine(l)
      })
  }
  var isPropertyInlineEnum = function (prop) {
    if ('$ref' in prop) {
      return false
    }
    return (
      prop.type === 'string' &&
      prop['enum'] !== null &&
      prop['enum'] !== undefined
    )
  }
  var getPropertyDef = function (interfaceName, prop) {
    // Quote key if it has a . in it.
    var propName = prop.name.includes('.') ? "'" + prop.name + "'" : prop.name
    var type = getPropertyType(interfaceName, prop)
    return '' + propName + (prop.optional ? '?' : '') + ': ' + type
  }
  var getPropertyType = function (interfaceName, prop) {
    if ('$ref' in prop) return prop.$ref
    else if (prop.type === 'array')
      return getPropertyType(interfaceName, prop.items) + '[]'
    else if (prop.type === 'object')
      if (!prop.properties) {
        // TODO: actually 'any'? or can use generic '[key: string]: string'?
        return 'any'
      } else {
        // hack: access indent, \n directly
        var objStr = '{\n'
        numIndents++
        objStr += prop.properties
          .map(function (p) {
            return '' + getIndent() + getPropertyDef(interfaceName, p) + ';\n'
          })
          .join('')
        numIndents--
        objStr += getIndent() + '}'
        return objStr
      }
    else if (prop.type === 'string' && prop['enum'])
      return (
        '(' +
        prop['enum']
          .map(function (v) {
            return "'" + v + "'"
          })
          .join(' | ') +
        ')'
      )
    return prop.type
  }
  var emitProperty = function (interfaceName, prop) {
    var description = prop.description
    if (isPropertyInlineEnum(prop)) {
      var enumName = interfaceName + toTitleCase(prop.name)
      description = (description || '') + ' (' + enumName + ' enum)'
    }
    emitDescription(description)
    emitLine(getPropertyDef(interfaceName, prop) + ';')
  }
  var emitInlineEnumForDomainType = function (type) {
    if (type.type === 'object') {
      emitInlineEnums(type.id, type.properties)
    }
  }
  var emitInlineEnumsForCommands = function (command) {
    emitInlineEnums(toCmdRequestName(command.name), command.parameters)
    emitInlineEnums(toCmdResponseName(command.name), command.returns)
  }
  var emitInlineEnumsForEvents = function (event) {
    emitInlineEnums(toEventPayloadName(event.name), event.parameters)
  }
  var emitInlineEnums = function (prefix, propertyTypes) {
    if (!propertyTypes) {
      return
    }
    for (
      var _i = 0, propertyTypes_1 = propertyTypes;
      _i < propertyTypes_1.length;
      _i++
    ) {
      var type = propertyTypes_1[_i]
      if (isPropertyInlineEnum(type)) {
        emitLine()
        var enumName = prefix + toTitleCase(type.name)
        emitEnum(enumName, type['enum'] || [])
      }
    }
  }
  var emitInterface = function (interfaceName, props) {
    emitOpenBlock('export interface ' + interfaceName)
    props
      ? props.forEach(function (prop) {
          return emitProperty(interfaceName, prop)
        })
      : emitLine('[key: string]: string;')
    emitCloseBlock()
  }
  var emitDomainType = function (type) {
    emitInlineEnumForDomainType(type)
    emitLine()
    emitDescription(type.description)
    if (type.type === 'object') {
      emitInterface(type.id, type.properties)
    } else {
      emitLine(
        'export type ' + type.id + ' = ' + getPropertyType(type.id, type) + ';'
      )
    }
  }
  var toTitleCase = function (str) {
    return str[0].toUpperCase() + str.substr(1)
  }
  var toCmdRequestName = function (commandName) {
    return toTitleCase(commandName) + 'Request'
  }
  var toCmdResponseName = function (commandName) {
    return toTitleCase(commandName) + 'Response'
  }
  var emitCommand = function (command) {
    emitInlineEnumsForCommands(command)
    // TODO(bckenny): should description be emitted for params and return types?
    if (command.parameters) {
      emitLine()
      emitInterface(toCmdRequestName(command.name), command.parameters)
    }
    if (command.returns) {
      emitLine()
      emitInterface(toCmdResponseName(command.name), command.returns)
    }
  }
  var toEventPayloadName = function (eventName) {
    return toTitleCase(eventName) + 'Event'
  }
  var emitEvent = function (event) {
    if (!event.parameters) {
      return
    }
    emitInlineEnumsForEvents(event)
    emitLine()
    emitDescription(event.description)
    emitInterface(toEventPayloadName(event.name), event.parameters)
  }
  var getEventMapping = function (event, domainName, modulePrefix) {
    // Use TS3.0+ tuples
    var payloadType = event.parameters
      ? '[' +
        modulePrefix +
        '.' +
        domainName +
        '.' +
        toEventPayloadName(event.name) +
        ']'
      : '[]'
    return {
      // domain-prefixed name since it will be used outside of the module.
      name: domainName + '.' + event.name,
      description: event.description,
      $ref: payloadType,
    }
  }
  var isWeakInterface = function (params) {
    return params.every(function (p) {
      return !!p.optional
    })
  }
  var getCommandMapping = function (command, domainName, modulePrefix) {
    var prefix = modulePrefix + '.' + domainName + '.'
    // Use TS3.0+ tuples for paramsType
    var requestType = '[]'
    if (command.parameters) {
      var optional = isWeakInterface(command.parameters) ? '?' : ''
      requestType = '[' + prefix + toCmdRequestName(command.name) + optional + ']'
    }
    var responseType = command.returns
      ? prefix + toCmdResponseName(command.name)
      : 'void'
    return {
      type: 'object',
      name: domainName + '.' + command.name,
      description: command.description,
      properties: [
        {
          name: 'paramsType',
          $ref: requestType,
        },
        {
          name: 'returnType',
          $ref: responseType,
        },
      ],
    }
  }
  var flatten = function (arr) {
    var _a
    return (_a = []).concat.apply(_a, arr)
  }
  var emitMapping = function (moduleName, protocolModuleName, domains) {
    moduleName = toTitleCase(moduleName)
    emitHeaderComments()
    emitLine("import Protocol from './" + protocolModuleName + "'")
    emitLine()
    emitDescription(
      'Mappings from protocol event and command names to the types required for them.'
    )
    emitOpenBlock('export namespace ' + moduleName)
    var protocolModulePrefix = toTitleCase(protocolModuleName)
    var eventDefs = flatten(
      domains.map(function (d) {
        var domainName = toTitleCase(d.domain)
        return (d.events || []).map(function (e) {
          return getEventMapping(e, domainName, protocolModulePrefix)
        })
      })
    )
    emitInterface('Events', eventDefs)
    emitLine()
    var commandDefs = flatten(
      domains.map(function (d) {
        var domainName = toTitleCase(d.domain)
        return (d.commands || []).map(function (c) {
          return getCommandMapping(c, domainName, protocolModulePrefix)
        })
      })
    )
    emitInterface('Commands', commandDefs)
    emitCloseBlock()
    emitLine()
    emitLine('export default ' + moduleName + ';')
  }
  var emitApiCommand = function (command, domainName, modulePrefix) {
    var prefix = modulePrefix + '.' + domainName + '.'
    emitDescription(command.description)
    var params = command.parameters
      ? 'params: ' + prefix + toCmdRequestName(command.name)
      : ''
    var response = command.returns
      ? '' + prefix + toCmdResponseName(command.name)
      : 'void'
    emitLine(command.name + '(' + params + '): Promise<' + response + '>;')
    emitLine()
  }
  var emitApiEvent = function (event, domainName, modulePrefix) {
    var prefix = modulePrefix + '.' + domainName + '.'
    emitDescription(event.description)
    var params = event.parameters
      ? 'params: ' + prefix + toEventPayloadName(event.name)
      : ''
    emitLine(
      "on(event: '" + event.name + "', listener: (" + params + ') => void): void;'
    )
    emitLine()
  }
  var emitDomainApi = function (domain, modulePrefix) {
    emitLine()
    var domainName = toTitleCase(domain.domain)
    emitOpenBlock('export interface ' + domainName + 'Api')
    if (domain.commands)
      domain.commands.forEach(function (c) {
        return emitApiCommand(c, domainName, modulePrefix)
      })
    if (domain.events)
      domain.events.forEach(function (e) {
        return emitApiEvent(e, domainName, modulePrefix)
      })
    emitCloseBlock()
  }
  var emitApi = function (moduleName, protocolModuleName, domains) {
    moduleName = toTitleCase(moduleName)
    emitHeaderComments()
    emitLine("import Protocol from './" + protocolModuleName + "'")
    emitLine()
    emitDescription('API generated from Protocol commands and events.')
    emitOpenBlock('export namespace ' + moduleName)
    emitLine()
    emitOpenBlock('export interface ProtocolApi')
    domains.forEach(function (d) {
      emitLine(d.domain + ': ' + d.domain + 'Api;')
      emitLine()
    })
    emitCloseBlock()
    emitLine()
    var protocolModulePrefix = toTitleCase(protocolModuleName)
    domains.forEach(function (d) {
      return emitDomainApi(d, protocolModulePrefix)
    })
    emitCloseBlock()
    emitLine()
    emitLine('export default ' + moduleName + ';')
  }
  var flushEmitToFile = function (path) {
    console.log('Writing to ' + path)
    fs.writeFileSync(path, emitStr, { encoding: 'utf-8' })
    numIndents = 0
    emitStr = ''
  }
  // Main
  var destProtocolFilePath = process.argv[4]
  var protocolModuleName = path.basename(destProtocolFilePath, '.d.js')
  emitModule(protocolModuleName, protocolDomains)
  flushEmitToFile(destProtocolFilePath)
  var destMappingFilePath = process.argv[5]
  var mappingModuleName = 'ProtocolMapping'
  emitMapping(mappingModuleName, protocolModuleName, protocolDomains)
  flushEmitToFile(destMappingFilePath)
  var destApiFilePath = process.argv[6]
  var apiModuleName = 'ProtocolProxyApi'
  emitApi(apiModuleName, protocolModuleName, protocolDomains)
  flushEmitToFile(destApiFilePath)
  