var Reporter = require('../base').Reporter; var EncoderBuffer = require('../base').EncoderBuffer; var DecoderBuffer = require('../base').DecoderBuffer; var assert = require('minimalistic-assert'); // Supported tags var tags = [ 'seq', 'seqof', 'set', 'setof', 'objid', 'bool', 'gentime', 'utctime', 'null_', 'enum', 'int', 'bitstr', 'bmpstr', 'charstr', 'genstr', 'graphstr', 'ia5str', 'iso646str', 'numstr', 'octstr', 'printstr', 't61str', 'unistr', 'utf8str', 'videostr' ]; // Public methods list var methods = [ 'key', 'obj', 'use', 'optional', 'explicit', 'implicit', 'def', 'choice', 'any', 'contains' ].concat(tags); // Overrided methods list var overrided = [ '_peekTag', '_decodeTag', '_use', '_decodeStr', '_decodeObjid', '_decodeTime', '_decodeNull', '_decodeInt', '_decodeBool', '_decodeList', '_encodeComposite', '_encodeStr', '_encodeObjid', '_encodeTime', '_encodeNull', '_encodeInt', '_encodeBool' ]; function Node(enc, parent) { var state = {}; this._baseState = state; state.enc = enc; state.parent = parent || null; state.children = null; // State state.tag = null; state.args = null; state.reverseArgs = null; state.choice = null; state.optional = false; state.any = false; state.obj = false; state.use = null; state.useDecoder = null; state.key = null; state['default'] = null; state.explicit = null; state.implicit = null; state.contains = null; // Should create new instance on each method if (!state.parent) { state.children = []; this._wrap(); } } module.exports = Node; var stateProps = [ 'enc', 'parent', 'children', 'tag', 'args', 'reverseArgs', 'choice', 'optional', 'any', 'obj', 'use', 'alteredUse', 'key', 'default', 'explicit', 'implicit' ]; Node.prototype.clone = function clone() { var state = this._baseState; var cstate = {}; stateProps.forEach(function(prop) { cstate[prop] = state[prop]; }); var res = new this.constructor(cstate.parent); res._baseState = cstate; return res; }; Node.prototype._wrap = function wrap() { var state = this._baseState; methods.forEach(function(method) { this[method] = function _wrappedMethod() { var clone = new this.constructor(this); state.children.push(clone); return clone[method].apply(clone, arguments); }; }, this); }; Node.prototype._init = function init(body) { var state = this._baseState; assert(state.parent === null); body.call(this); // Filter children state.children = state.children.filter(function(child) { return child._baseState.parent === this; }, this); assert.equal(state.children.length, 1, 'Root node can have only one child'); }; Node.prototype._useArgs = function useArgs(args) { var state = this._baseState; // Filter children and args var children = args.filter(function(arg) { return arg instanceof this.constructor; }, this); args = args.filter(function(arg) { return !(arg instanceof this.constructor); }, this); if (children.length !== 0) { assert(state.children === null); state.children = children; // Replace parent to maintain backward link children.forEach(function(child) { child._baseState.parent = this; }, this); } if (args.length !== 0) { assert(state.args === null); state.args = args; state.reverseArgs = args.map(function(arg) { if (typeof arg !== 'object' || arg.constructor !== Object) return arg; var res = {}; Object.keys(arg).forEach(function(key) { if (key == (key | 0)) key |= 0; var value = arg[key]; res[value] = key; }); return res; }); } }; // // Overrided methods // overrided.forEach(function(method) { Node.prototype[method] = function _overrided() { var state = this._baseState; throw new Error(method + ' not implemented for encoding: ' + state.enc); }; }); // // Public methods // tags.forEach(function(tag) { Node.prototype[tag] = function _tagMethod() { var state = this._baseState; var args = Array.prototype.slice.call(arguments); assert(state.tag === null); state.tag = tag; this._useArgs(args); return this; }; }); Node.prototype.use = function use(item) { var state = this._baseState; assert(state.use === null); state.use = item; return this; }; Node.prototype.optional = function optional() { var state = this._baseState; state.optional = true; return this; }; Node.prototype.def = function def(val) { var state = this._baseState; assert(state['default'] === null); state['default'] = val; state.optional = true; return this; }; Node.prototype.explicit = function explicit(num) { var state = this._baseState; assert(state.explicit === null && state.implicit === null); state.explicit = num; return this; }; Node.prototype.implicit = function implicit(num) { var state = this._baseState; assert(state.explicit === null && state.implicit === null); state.implicit = num; return this; }; Node.prototype.obj = function obj() { var state = this._baseState; var args = Array.prototype.slice.call(arguments); state.obj = true; if (args.length !== 0) this._useArgs(args); return this; }; Node.prototype.key = function key(newKey) { var state = this._baseState; assert(state.key === null); state.key = newKey; return this; }; Node.prototype.any = function any() { var state = this._baseState; state.any = true; return this; }; Node.prototype.choice = function choice(obj) { var state = this._baseState; assert(state.choice === null); state.choice = obj; this._useArgs(Object.keys(obj).map(function(key) { return obj[key]; })); return this; }; Node.prototype.contains = function contains(item) { var state = this._baseState; assert(state.use === null); state.contains = item; return this; }; // // Decoding // Node.prototype._decode = function decode(input) { var state = this._baseState; // Decode root node if (state.parent === null) return input.wrapResult(state.children[0]._decode(input)); var result = state['default']; var present = true; var prevKey; if (state.key !== null) prevKey = input.enterKey(state.key); // Check if tag is there if (state.optional) { var tag = null; if (state.explicit !== null) tag = state.explicit; else if (state.implicit !== null) tag = state.implicit; else if (state.tag !== null) tag = state.tag; if (tag === null && !state.any) { // Trial and Error var save = input.save(); try { if (state.choice === null) this._decodeGeneric(state.tag, input); else this._decodeChoice(input); present = true; } catch (e) { present = false; } input.restore(save); } else { present = this._peekTag(input, tag, state.any); if (input.isError(present)) return present; } } // Push object on stack var prevObj; if (state.obj && present) prevObj = input.enterObject(); if (present) { // Unwrap explicit values if (state.explicit !== null) { var explicit = this._decodeTag(input, state.explicit); if (input.isError(explicit)) return explicit; input = explicit; } // Unwrap implicit and normal values if (state.use === null && state.choice === null) { if (state.any) var save = input.save(); var body = this._decodeTag( input, state.implicit !== null ? state.implicit : state.tag, state.any ); if (input.isError(body)) return body; if (state.any) result = input.raw(save); else input = body; } // Select proper method for tag if (state.any) result = result; else if (state.choice === null) result = this._decodeGeneric(state.tag, input); else result = this._decodeChoice(input); if (input.isError(result)) return result; // Decode children if (!state.any && state.choice === null && state.children !== null) { state.children.forEach(function decodeChildren(child) { // NOTE: We are ignoring errors here, to let parser continue with other // parts of encoded data child._decode(input); }); } // Decode contained/encoded by schema, only in bit or octet strings if (state.contains && (state.tag === 'octstr' || state.tag === 'bitstr')) { var data = new DecoderBuffer(result); result = this._getUse(state.contains, input._reporterState.obj)._decode(data); } } // Pop object if (state.obj && present) result = input.leaveObject(prevObj); // Set key if (state.key !== null && (result !== null || present === true)) input.leaveKey(prevKey, state.key, result); return result; }; Node.prototype._decodeGeneric = function decodeGeneric(tag, input) { var state = this._baseState; if (tag === 'seq' || tag === 'set') return null; if (tag === 'seqof' || tag === 'setof') return this._decodeList(input, tag, state.args[0]); else if (/str$/.test(tag)) return this._decodeStr(input, tag); else if (tag === 'objid' && state.args) return this._decodeObjid(input, state.args[0], state.args[1]); else if (tag === 'objid') return this._decodeObjid(input, null, null); else if (tag === 'gentime' || tag === 'utctime') return this._decodeTime(input, tag); else if (tag === 'null_') return this._decodeNull(input); else if (tag === 'bool') return this._decodeBool(input); else if (tag === 'int' || tag === 'enum') return this._decodeInt(input, state.args && state.args[0]); else if (state.use !== null) return this._getUse(state.use, input._reporterState.obj)._decode(input); else return input.error('unknown tag: ' + tag); return null; }; Node.prototype._getUse = function _getUse(entity, obj) { var state = this._baseState; // Create altered use decoder if implicit is set state.useDecoder = this._use(entity, obj); assert(state.useDecoder._baseState.parent === null); state.useDecoder = state.useDecoder._baseState.children[0]; if (state.implicit !== state.useDecoder._baseState.implicit) { state.useDecoder = state.useDecoder.clone(); state.useDecoder._baseState.implicit = state.implicit; } return state.useDecoder; }; Node.prototype._decodeChoice = function decodeChoice(input) { var state = this._baseState; var result = null; var match = false; Object.keys(state.choice).some(function(key) { var save = input.save(); var node = state.choice[key]; try { var value = node._decode(input); if (input.isError(value)) return false; result = { type: key, value: value }; match = true; } catch (e) { input.restore(save); return false; } return true; }, this); if (!match) return input.error('Choice not matched'); return result; }; // // Encoding // Node.prototype._createEncoderBuffer = function createEncoderBuffer(data) { return new EncoderBuffer(data, this.reporter); }; Node.prototype._encode = function encode(data, reporter, parent) { var state = this._baseState; if (state['default'] !== null && state['default'] === data) return; var result = this._encodeValue(data, reporter, parent); if (result === undefined) return; if (this._skipDefault(result, reporter, parent)) return; return result; }; Node.prototype._encodeValue = function encode(data, reporter, parent) { var state = this._baseState; // Decode root node if (state.parent === null) return state.children[0]._encode(data, reporter || new Reporter()); var result = null; var present = true; // Set reporter to share it with a child class this.reporter = reporter; // Check if data is there if (state.optional && data === undefined) { if (state['default'] !== null) data = state['default'] else return; } // For error reporting var prevKey; // Encode children first var content = null; var primitive = false; if (state.any) { // Anything that was given is translated to buffer result = this._createEncoderBuffer(data); } else if (state.choice) { result = this._encodeChoice(data, reporter); } else if (state.contains) { content = this._getUse(state.contains, parent)._encode(data, reporter); primitive = true; } else if (state.children) { content = state.children.map(function(child) { if (child._baseState.tag === 'null_') return child._encode(null, reporter, data); if (child._baseState.key === null) return reporter.error('Child should have a key'); var prevKey = reporter.enterKey(child._baseState.key); if (typeof data !== 'object') return reporter.error('Child expected, but input is not object'); var res = child._encode(data[child._baseState.key], reporter, data); reporter.leaveKey(prevKey); return res; }, this).filter(function(child) { return child; }); content = this._createEncoderBuffer(content); } else { if (state.tag === 'seqof' || state.tag === 'setof') { // TODO(indutny): this should be thrown on DSL level if (!(state.args && state.args.length === 1)) return reporter.error('Too many args for : ' + state.tag); if (!Array.isArray(data)) return reporter.error('seqof/setof, but data is not Array'); var child = this.clone(); child._baseState.implicit = null; content = this._createEncoderBuffer(data.map(function(item) { var state = this._baseState; return this._getUse(state.args[0], data)._encode(item, reporter); }, child)); } else if (state.use !== null) { result = this._getUse(state.use, parent)._encode(data, reporter); } else { content = this._encodePrimitive(state.tag, data); primitive = true; } } // Encode data itself var result; if (!state.any && state.choice === null) { var tag = state.implicit !== null ? state.implicit : state.tag; var cls = state.implicit === null ? 'universal' : 'context'; if (tag === null) { if (state.use === null) reporter.error('Tag could be ommited only for .use()'); } else { if (state.use === null) result = this._encodeComposite(tag, primitive, cls, content); } } // Wrap in explicit if (state.explicit !== null) result = this._encodeComposite(state.explicit, false, 'context', result); return result; }; Node.prototype._encodeChoice = function encodeChoice(data, reporter) { var state = this._baseState; var node = state.choice[data.type]; if (!node) { assert( false, data.type + ' not found in ' + JSON.stringify(Object.keys(state.choice))); } return node._encode(data.value, reporter); }; Node.prototype._encodePrimitive = function encodePrimitive(tag, data) { var state = this._baseState; if (/str$/.test(tag)) return this._encodeStr(data, tag); else if (tag === 'objid' && state.args) return this._encodeObjid(data, state.reverseArgs[0], state.args[1]); else if (tag === 'objid') return this._encodeObjid(data, null, null); else if (tag === 'gentime' || tag === 'utctime') return this._encodeTime(data, tag); else if (tag === 'null_') return this._encodeNull(); else if (tag === 'int' || tag === 'enum') return this._encodeInt(data, state.args && state.reverseArgs[0]); else if (tag === 'bool') return this._encodeBool(data); else throw new Error('Unsupported tag: ' + tag); }; Node.prototype._isNumstr = function isNumstr(str) { return /^[0-9 ]*$/.test(str); }; Node.prototype._isPrintstr = function isPrintstr(str) { return /^[A-Za-z0-9 '\(\)\+,\-\.\/:=\?]*$/.test(str); };
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 19553 | swellard | Move and rename clients | ||
//guest/perforce_software/helix-web-services/main/source/clients/2016.1.0/javascript/node_modules/asn1.js/lib/asn1/base/node.js | |||||
#1 | 18810 | tjuricek |
First-pass at JavaScript client SDK. JavaScript requires Node with Gulp to "browserfy" the library. It's the easiest way I found to use the swagger-js project; bundle up a wrapping method. There is no JavaScript reference guide. The swagger-js doesn't really document what they do very well, actually. Overall I'm not particularly impressed by swagger-js, it was hard to even figure out what the right method syntax was. We may want to invest time in doing it better. This required setting CORS response headers, which are currently defaulted to a fairly insecure setting. |