UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

98 lines (73 loc) 3.06 kB
/** * * @param {Function} Klass * @param {Map<Function, string>} classNames * @param {number} [max_depth] prevents infinite recursion * @returns {*} */ function resolve_class_name(Klass, classNames, max_depth = 64) { let typeName = classNames.get(Klass); if (typeName === undefined && Klass.hasOwnProperty("typeName")) { // try fallback to "typeName" field on constructor typeName = Klass.typeName; } if (typeName === undefined && max_depth > 0) { // try walking up prototype chain const proto = Object.getPrototypeOf(Klass); if (proto !== null && typeof proto === "object") { return resolve_class_name(proto, classNames, max_depth - 1); } } return typeName; } /** * @template T * @param {T} source * @param {Map<string, function(v:Object):Object>} serializers * @param {Map<*,string>} classNames * @param {boolean} [constructorNameFallback] */ export function abstractJSONSerializer(source, serializers, classNames, constructorNameFallback = true) { if (source === null || typeof source !== "object") { // primitive type return source; } // parameter is an object // extract type name const Klass = source.constructor; let typeName = resolve_class_name(Klass, classNames); if (typeName === undefined && constructorNameFallback) { typeName = Klass.name; console.warn(`No type name could be resolved, using constructor name '${typeName}' as a fallback.`); const matching_class_entries = []; classNames.forEach((value, key) => { if (value === typeName) { matching_class_entries.push(key); } }); if (matching_class_entries.length > 0) { console.error( `Found a class that resolved to name ${typeName}. className registry might be corrupted, possible reason is multiple versions of the same class being imported.`, "offending object:", source, "matching class name entries:", matching_class_entries, "Note that constructor of offending object does not match any of these classes (!==)" ); } } if (typeName === undefined) { throw new Error(`Failed to resolve type name. No name found in classNames registry and no .typeName field on the constructor {name: '${Klass.name}}'`); } let serializer = serializers.get(typeName); let serializerContext = undefined; if (serializer === undefined) { serializer = source.toJSON; serializerContext = source; } if (serializer === undefined) { throw new Error(`Failed to resolve serializer for object type '${typeName}'. No serializer found in serializers registry and no .toJSON method on object itself`); } return { type: typeName, data: serializer.call(serializerContext, source) }; }