Skip to content

Commit d1e3122

Browse files
committed
Added functionality to filter for multiple types at once in lookup(), used by lookupTypeOrEnum(), fixes #740
1 parent fef924e commit d1e3122

File tree

3 files changed

+48
-31
lines changed

3 files changed

+48
-31
lines changed

Diff for: src/field.js

+3-5
Original file line numberDiff line numberDiff line change
@@ -245,13 +245,11 @@ Field.prototype.resolve = function resolve() {
245245
if (!Type)
246246
Type = require("./type");
247247

248-
var scope = this.declaringField ? this.declaringField.parent : this.parent;
249-
if (this.resolvedType = scope.lookup(this.type, Type))
248+
this.resolvedType = (this.declaringField ? this.declaringField.parent : this.parent).lookupTypeOrEnum(this.type);
249+
if (this.resolvedType instanceof Type)
250250
this.typeDefault = null;
251-
else if (this.resolvedType = scope.lookup(this.type, Enum))
251+
else // instanceof Enum
252252
this.typeDefault = this.resolvedType.values[Object.keys(this.resolvedType.values)[0]]; // first defined
253-
else
254-
throw Error("unresolvable field type: " + this.type + " in " + scope);
255253
}
256254

257255
// use explicitly set default value if present

Diff for: src/namespace.js

+40-25
Original file line numberDiff line numberDiff line change
@@ -277,17 +277,18 @@ Namespace.prototype.resolveAll = function resolveAll() {
277277
/**
278278
* Looks up the reflection object at the specified path, relative to this namespace.
279279
* @param {string|string[]} path Path to look up
280-
* @param {function(new: ReflectionObject)} filterType Filter type, one of `protobuf.Type`, `protobuf.Enum`, `protobuf.Service` etc.
280+
* @param {function(new: ReflectionObject)|Array.<function(new: ReflectionObject)>} filterTypes Filter types, any combination of `protobuf.Type`, `protobuf.Enum`, `protobuf.Service` etc.
281281
* @param {boolean} [parentAlreadyChecked=false] If known, whether the parent has already been checked
282282
* @returns {?ReflectionObject} Looked up object or `null` if none could be found
283283
*/
284-
Namespace.prototype.lookup = function lookup(path, filterType, parentAlreadyChecked) {
284+
Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChecked) {
285285

286286
/* istanbul ignore if */
287-
if (typeof filterType === "boolean") {
288-
parentAlreadyChecked = filterType;
289-
filterType = undefined;
290-
}
287+
if (typeof filterTypes === "boolean") {
288+
parentAlreadyChecked = filterTypes;
289+
filterTypes = undefined;
290+
} else if (filterTypes && !Array.isArray(filterTypes))
291+
filterTypes = [ filterTypes ];
291292

292293
if (util.isString(path) && path.length) {
293294
if (path === ".")
@@ -298,20 +299,20 @@ Namespace.prototype.lookup = function lookup(path, filterType, parentAlreadyChec
298299

299300
// Start at root if path is absolute
300301
if (path[0] === "")
301-
return this.root.lookup(path.slice(1), filterType);
302+
return this.root.lookup(path.slice(1), filterTypes);
302303
// Test if the first part matches any nested object, and if so, traverse if path contains more
303304
var found = this.get(path[0]);
304305
if (found) {
305306
if (path.length === 1) {
306-
if (!filterType || found instanceof filterType)
307+
if (!filterTypes || filterTypes.indexOf(found.constructor) > -1)
307308
return found;
308-
} else if (found instanceof Namespace && (found = found.lookup(path.slice(1), filterType, true)))
309+
} else if (found instanceof Namespace && (found = found.lookup(path.slice(1), filterTypes, true)))
309310
return found;
310311
}
311312
// If there hasn't been a match, try again at the parent
312313
if (this.parent === null || parentAlreadyChecked)
313314
return null;
314-
return this.parent.lookup(path, filterType);
315+
return this.parent.lookup(path, filterTypes);
315316
};
316317

317318
/**
@@ -333,38 +334,52 @@ Namespace.prototype.lookup = function lookup(path, filterType, parentAlreadyChec
333334
* @throws {Error} If `path` does not point to a type
334335
*/
335336
Namespace.prototype.lookupType = function lookupType(path) {
336-
var found = this.lookup(path, Type);
337+
var found = this.lookup(path, [ Type ]);
337338
if (!found)
338339
throw Error("no such type");
339340
return found;
340341
};
341342

342343
/**
343-
* Looks up the {@link Service|service} at the specified path, relative to this namespace.
344+
* Looks up the values of the {@link Enum|enum} at the specified path, relative to this namespace.
345+
* Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it returns the enum's values directly and throws instead of returning `null`.
346+
* @param {string|string[]} path Path to look up
347+
* @returns {Object.<string,number>} Enum values
348+
* @throws {Error} If `path` does not point to an enum
349+
*/
350+
Namespace.prototype.lookupEnum = function lookupEnum(path) {
351+
var found = this.lookup(path, [ Enum ]);
352+
if (!found)
353+
throw Error("no such enum");
354+
return found.values;
355+
};
356+
357+
/**
358+
* Looks up the {@link Type|type} or {@link Enum|enum} at the specified path, relative to this namespace.
344359
* Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
345360
* @param {string|string[]} path Path to look up
346-
* @returns {Service} Looked up service
347-
* @throws {Error} If `path` does not point to a service
361+
* @returns {Type} Looked up type or enum
362+
* @throws {Error} If `path` does not point to a type or enum
348363
*/
349-
Namespace.prototype.lookupService = function lookupService(path) {
350-
var found = this.lookup(path, Service);
364+
Namespace.prototype.lookupTypeOrEnum = function lookupTypeOrEnum(path) {
365+
var found = this.lookup(path, [ Type, Enum ]);
351366
if (!found)
352-
throw Error("no such service");
367+
throw Error("no such type or enum");
353368
return found;
354369
};
355370

356371
/**
357-
* Looks up the values of the {@link Enum|enum} at the specified path, relative to this namespace.
358-
* Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it returns the enum's values directly and throws instead of returning `null`.
372+
* Looks up the {@link Service|service} at the specified path, relative to this namespace.
373+
* Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
359374
* @param {string|string[]} path Path to look up
360-
* @returns {Object.<string,number>} Enum values
361-
* @throws {Error} If `path` does not point to an enum
375+
* @returns {Service} Looked up service
376+
* @throws {Error} If `path` does not point to a service
362377
*/
363-
Namespace.prototype.lookupEnum = function lookupEnum(path) {
364-
var found = this.lookup(path, Enum);
378+
Namespace.prototype.lookupService = function lookupService(path) {
379+
var found = this.lookup(path, [ Service ]);
365380
if (!found)
366-
throw Error("no such enum");
367-
return found.values;
381+
throw Error("no such service");
382+
return found;
368383
};
369384

370385
Namespace._configure = function(Type_, Service_) {

Diff for: tests/api_namespace.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ enum Enm {\
1212
ONE = 1;\
1313
TWO = 2;\
1414
}\
15-
message Msg {}\
15+
message Msg {\
16+
message Enm {}\
17+
}\
1618
service Svc {}";
1719

1820
tape.test("reflected namespaces", function(test) {
@@ -34,6 +36,8 @@ tape.test("reflected namespaces", function(test) {
3436

3537
test.ok(ns.lookupType("Msg"), "should lookup types");
3638

39+
test.equal(ns.get("Msg").lookupTypeOrEnum("Enm"), ns.lookup(".ns.Msg.Enm"), "should lookup the nearest type or enum");
40+
3741
test.throws(function() {
3842
ns.lookupType("Enm");
3943
}, Error, "should throw when looking up an enum as a type");

0 commit comments

Comments
 (0)