Source: description.js

import { OpenSearchUrl } from './url';
import { parseXml, getElements, getText, find, assign } from './utils';

/**
 * Class to parse the OpenSearchDescription XML document and get the saerch URLs
 */
export class OpenSearchDescription {
  /**
   * Create an OpenSearchDescription object
   * @param {object} values The object containing the parsed description
   * @param {string} [values.shortName] The short name of the OpenSearch service
   * @param {string} [values.description] The description of the service
   * @param {string} [values.tags] The associated tags of the service
   * @param {string} [values.contact] The contact information of the service
   * @param {OpenSearchUrl[]} [values.urls] The parsed URLs of the service
   * @param {string} [values.longName] The long name of the service
   * @param {object[]} [values.images] The associated images of the service
   * @param {object[]} [values.queries] Prepared queries for the service
   * @param {string} [values.developer] The developer information of the service
   * @param {string} [values.attribution] The attribution for the service
   * @param {string} [values.syndicationRight] Syndication rights for the service
   * @param {string} [values.adultContent] Information about the adult content of the service
   * @param {string} [values.language] The language settings for the service
   * @param {string} [values.outputEncoding] The output encoding
   * @param {string} [values.inputEncoding] The input encoding
   */
  constructor(values) {
    this.shortName = values.shortName;
    this.description = values.description;
    this.tags = values.tags;
    this.contact = values.contact;
    this.urls = values.urls;
    this.longName = values.longName;
    this.images = values.images;
    this.queries = values.queries;
    this.developer = values.developer;
    this.attribution = values.attribution;
    this.syndicationRight = values.syndicationRight;
    this.adultContent = values.adultContent;
    this.language = values.language;
    this.outputEncoding = values.outputEncoding;
    this.inputEncoding = values.inputEncoding;
  }

  /**
   * Get the {@link OpenSearchUrl} for the given parameters, mime type and HTTP
   * method. Return the first matching URL or null.
   * @param {object} [parameters=null] An object containing search parameters
   * @param {string} [type=null] The mime-type for the URL
   * @param {string} [method='GET'] The preferred HTTP method of the URL
   * @returns {OpenSearchUrl|null}
   */
  getUrl(...args) {
    const urls = this.getUrls(...args);
    if (urls.length) {
      return urls[0];
    }
    return null;
  }

  /**
   * Get an array of {@link OpenSearchUrl} for the given parameters, mime type and HTTP
   * method.
   * @param {object} [parameters=null] An object containing search parameters
   * @param {string|Array} [type=null] The mime-type for the URL
   * @param {string|Array} [method=null] The preferred HTTP method of the URL
   * @returns {OpenSearchUrl[]}
   */
  getUrls(parameters = null, type = null, method = null) {
    let urls = this.urls.filter(url => find(url.relations, rel => rel === 'results'));

    if (type) {
      urls = urls.filter(
        url => (Array.isArray(type) ? type.indexOf(url.type) > -1 : url.type === type)
      );
    }
    if (method) {
      urls = urls.filter(
        url => (Array.isArray(method) ? method.indexOf(url.method) > -1 : url.method === method)
      );
    }

    if (parameters) {
      return urls.filter(
        url => url.isCompatible(parameters)
      );
    }
    return urls;
  }

  /**
   * Parse an OpenSearch Description XML Document.
   * @param {string} xml The XML String to parse.
   * @returns {OpenSearchDescription} The parsed description document
   */
  static fromXml(xml) {
    const xmlDoc = parseXml(xml).documentElement;

    const values = {
      shortName: getText(xmlDoc, 'os', 'ShortName'),
      description: getText(xmlDoc, 'os', 'Description'),
      tags: getText(xmlDoc, 'os', 'Tags'),
      contact: getText(xmlDoc, 'os', 'Contact'),
      urls: getElements(xmlDoc, 'os', 'Url').map(
        node => OpenSearchUrl.fromNode(node)
      ),
      longName: getText(xmlDoc, 'os', 'LongName'),
      images: getElements(xmlDoc, 'os', 'Image').map(node => ({
        height: parseInt(node.getAttribute('height'), 10),
        width: parseInt(node.getAttribute('width'), 10),
        type: node.getAttribute('type'),
        url: node.textContent,
      })),
      queries: getElements(xmlDoc, 'os', 'Query').map((node) => {
        const query = { role: node.getAttribute('role') };
        for (let i = 0; i < node.attributes.length; ++i) {
          const attribute = node.attributes[i];
          query[attribute.name] = attribute.value;
        }
        return query;
      }),
      developer: getText(xmlDoc, 'os', 'Developer'),
      attribution: getText(xmlDoc, 'os', 'Attribution'),
      syndicationRight: getText(xmlDoc, 'os', 'SyndicationRight'),
      adultContent: getText(xmlDoc, 'os', 'AdultContent'),
      language: getText(xmlDoc, 'os', 'Language'),
      outputEncoding: getText(xmlDoc, 'os', 'OutputEncoding'),
      inputEncoding: getText(xmlDoc, 'os', 'InputEncoding'),
    };
    return new OpenSearchDescription(values);
  }

  /**
   * Serialize the OpenSearch description to a simple object.
   * @returns {object} The serialized description
   */
  serialize() {
    return {
      shortName: this.shortName,
      description: this.description,
      tags: this.tags,
      contact: this.contact,
      urls: this.urls.map(url => url.serialize()),
      longName: this.longName,
      images: this.images,
      queries: this.queries,
      developer: this.developer,
      attribution: this.attribution,
      syndicationRight: this.syndicationRight,
      adultContent: this.adultContent,
      language: this.language,
      outputEncoding: this.outputEncoding,
      inputEncoding: this.inputEncoding,
    };
  }

  /**
   * Deserialize an OpenSearch description from an object.
   * @param {object} values The serialized description
   * @returns {OpenSearchDescription} The deserialized description
   */
  static deserialize(values) {
    return new OpenSearchDescription(assign({}, values, {
      urls: values.urls.map(urlDesc => OpenSearchUrl.deserialize(urlDesc)),
    }));
  }
}