UNPKG

@stordata/vsphere-soapify

Version:

A NodeJS abstraction layer for the vSphere SOAP API

142 lines (108 loc) 4.02 kB
'use strict'; const _ = require('lodash'), debug = require('debug')('vsphere-soapify'), { data, managed } = require('./sdk'); module.exports = class Parser { constructor(client) { this.client = client; } parse(object, defaultType = 'xsd:string') { if (object === undefined || object === null) { return object; } const rawType = this.extractType(object, defaultType), [, arrayOf,, type] = /^(ArrayOf)?(xsd:)?(.+)/.exec(rawType); /** * "ArrayOf" types are handled either: * - With a dedicated parser if one exists, in this case all parsing is done by the parser itself * - By parsing every array item using the correct parser (recurses through the `parse` function) */ if (arrayOf) { const parser = `parse${rawType}`, array = extractArray(object, type); return parser in this ? this[parser](array) : array.map(item => this.parse(item, type)); } const Type = `${type.charAt(0).toUpperCase()}${type.substring(1)}`, parser = `parse${Type}`; // A dedicated parser exists for this type, use it if (parser in this) { return this[parser](object); } // We want a complex type, check if it is mapped in the library and use it if (Type in data) { return new data[Type](this.client, object); } // The complex type is not mapped, check if we have a default type and it is mapped, then use it if (defaultType in data) { return new data[defaultType](this.client, object); } const str = this.parseString(object); // This will parse all Enumerated types as string if (!str) { debug('Parser failed to handle %j with detected type %s and default type %s. Returning the raw object', object, Type, defaultType); } return str || object; // Returns the object as-is if we failed } extractType(object, defaultType = data.DynamicData) { const type = typeof defaultType === 'string' ? defaultType : defaultType.name; if (typeof object !== 'object' || !object.attributes) { return type; } return object.attributes['xsi:type'] || object.attributes['XMLSchema-instance:type'] || type; } parseString(val) { return typeof val === 'string' ? val : val.$value; } parseBoolean(val) { return typeof val === 'boolean' ? val : (val.$value || val) === 'true'; } parseByte(val) { return this.parseLong(val); } parseShort(val) { return this.parseLong(val); } parseInt(val) { return this.parseLong(val); } parseLong(val) { return typeof val === 'number' ? val : Number(val.$value || val); } parseDateTime(val) { return val instanceof Date ? val : new Date(val.$value || val); } parseArrayOfKeyAnyValue(array) { return array.reduce((result, kv) => ({ ...result, [kv.key]: this.parse(kv.value) }), {}); } parseArrayOfOptionValue(array) { return this.parseArrayOfKeyAnyValue(array); } parseManagedObjectReference(val, propSet) { const { $value, attributes } = val, type = attributes && 'type' in attributes && attributes.type, Class = type && type in managed ? managed[type] : managed.ManagedEntity; return new Class(this.client, $value, propSet); } parseObjectContent(val) { return this.parseManagedObjectReference(val.obj, val.propSet); } parseDecimalWorldWideName(val) { return BigInt(val) // You know, for 64 bits .toString(16) // Because VMWare sends the WWN in decimal .toUpperCase() // You know, for matching UCS ones .replace(/(..)(..)(..)(..)(..)(..)(..)/, '$1:$2:$3:$4:$5:$6:$7:'); // Ultra-advanced, next-gen, uber-powered RegEx wizardry } }; // function extractArray(object, type) { if (Array.isArray(object)) { return object; } if (type && typeof object === 'object') { for (const candidate of [type, type.toLowerCase()]) { if (candidate in object) { return _.castArray(object[candidate]); } } } return []; }