From d8e6cc2cce986ecee38d94689c22f95b5cb65e69 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Tue, 14 Jul 2020 15:05:24 -0300 Subject: [PATCH] refactor hasFilter(). add context.useFilters property. #75 --- package.json | 2 +- src/Schema.ts | 2 -- src/annotations.ts | 65 ++++++++++++------------------------------ test/DefinitionTest.ts | 27 ++++++++++++++---- 4 files changed, 40 insertions(+), 56 deletions(-) diff --git a/package.json b/package.json index 0d5196fb..6264d703 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@colyseus/schema", - "version": "1.0.0-alpha.8", + "version": "1.0.0-alpha.9", "description": "Schema-based binary serializer / de-serializer.", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/src/Schema.ts b/src/Schema.ts index b612ccc8..e199f988 100644 --- a/src/Schema.ts +++ b/src/Schema.ts @@ -392,8 +392,6 @@ export abstract class Schema { // }); // } - // value.$changes.refId = refId; - $root.addRef(refId, value); // $root.refs.set(refId, value); diff --git a/src/annotations.ts b/src/annotations.ts index 6fa99ee5..305cb281 100644 --- a/src/annotations.ts +++ b/src/annotations.ts @@ -86,6 +86,7 @@ export class SchemaDefinition { } this.filters[this.indexes[field]] = cb; + return true; } addChildrenFilter(field: string, cb: FilterChildrenCallback) { @@ -103,6 +104,7 @@ export class SchemaDefinition { } this.childFilters[index] = cb; + return true; } else { console.warn(`@filterChildren: field '${field}' can't have children. Ignoring filter.`); @@ -118,48 +120,8 @@ export class SchemaDefinition { } } -export function hasFilter( - klass: typeof Schema, - knownSchemas: Set = new Set() - // knownSchemas: WeakSet = new WeakSet() -) { - const definition = klass['_definition']; - const schema = definition.schema; - - let has = false; - - // set of schemas we already checked OR are still checking - knownSchemas.add(klass); - - for (const fieldName of Object.keys(schema)) { - // skip if a filter has been found - if (has) { break; } - - if ( - definition.filters[definition.indexes[fieldName]] || - definition.childFilters[definition.indexes[fieldName]] - ) { - has = true; - - } else if (typeof schema[fieldName] === 'function') { - const childSchema = schema[fieldName] as typeof Schema; - - if (!knownSchemas.has(childSchema)) { - has = hasFilter(childSchema, knownSchemas); - } - - } else if (typeof(Object.values(schema[fieldName])[0]) !== "string") { - // Array.isArray(schema[fieldName]) - const key = Object.keys(schema[fieldName])[0]; - const childSchema = schema[fieldName][key] as typeof Schema; - - if (!knownSchemas.has(childSchema)) { - has = hasFilter(childSchema, knownSchemas); - } - } - } - - return has; +export function hasFilter(klass: typeof Schema) { + return klass._context.useFilters; } // Colyseus integration @@ -168,6 +130,7 @@ export type Client = { sessionId: string } & any; export class Context { types: {[id: number]: typeof Schema} = {}; schemas = new Map(); + useFilters = false; has(schema: typeof Schema) { return this.schemas.has(schema); @@ -183,8 +146,7 @@ export class Context { this.schemas.set(schema, schema._typeid); } - static create() { - const context = new Context(); + static create(context: Context = new Context) { return function (definition: DefinitionType) { return type(definition, context); } @@ -308,7 +270,10 @@ export function filter(cb: FilterCallback return function (target: any, field: string) { const constructor = target.constructor as typeof Schema; const definition = constructor._definition; - definition.addFilter(field, cb); + + if (definition.addFilter(field, cb)) { + constructor._context.useFilters = true; + } } } @@ -316,7 +281,9 @@ export function filterChildren(cb: Fil return function (target: any, field: string) { const constructor = target.constructor as typeof Schema; const definition = constructor._definition; - definition.addChildrenFilter(field, cb); + if (definition.addChildrenFilter(field, cb)) { + constructor._context.useFilters = true; + } } } @@ -344,7 +311,11 @@ export function deprecated(throws: boolean = true, context: Context = globalCont } } -export function defineTypes(target: typeof Schema, fields: {[property: string]: DefinitionType}, context: Context = globalContext) { +export function defineTypes( + target: typeof Schema, + fields: { [property: string]: DefinitionType }, + context: Context = target._context || globalContext +) { for (let field in fields) { type(fields[field], context)(target.prototype, field); } diff --git a/test/DefinitionTest.ts b/test/DefinitionTest.ts index 2a3db953..c3d6870e 100644 --- a/test/DefinitionTest.ts +++ b/test/DefinitionTest.ts @@ -1,7 +1,7 @@ import * as assert from "assert"; import { Schema, type, MapSchema, filter, hasFilter, ArraySchema } from "../src"; -import { defineTypes } from "../src/annotations"; +import { defineTypes, Context } from "../src/annotations"; describe("Definition Tests", () => { @@ -52,6 +52,8 @@ describe("Definition Tests", () => { describe("hasFilter()", () => { it("should return false", () => { + const type = Context.create(); + class State extends Schema { @type("string") str: string; } @@ -60,6 +62,8 @@ describe("Definition Tests", () => { }); it("should return true", () => { + const type = Context.create(); + class State extends Schema { @filter(function (client, value, root) { return true; @@ -71,6 +75,8 @@ describe("Definition Tests", () => { }); it("should be able to navigate on recursive structures", () => { + const type = Context.create(); + class Container extends Schema { @type("string") name: string; @@ -87,7 +93,10 @@ describe("Definition Tests", () => { assert.equal(false, fun()); }); - it("should be able to navigate on more complex recursive structures", () => { + it("should be able to navigate on more complex recursive array structures", () => { + const context = new Context(); + const type = Context.create(context); + class ContainerA extends Schema { @type("string") contAName: string; } @@ -102,7 +111,7 @@ describe("Definition Tests", () => { defineTypes(cont, { containersA: [ContainerA], containersB: [ContainerB], - }); + }, context); }); const fun = () => hasFilter(State); @@ -111,7 +120,9 @@ describe("Definition Tests", () => { assert.equal(false, fun()); }); - it("should find filter on more complex recursive structures - array", () => { + it("should find filter on more complex recursive map structures", () => { + const type = Context.create(); + class ContainerA extends Schema { @type("string") contAName: string; } @@ -126,8 +137,8 @@ describe("Definition Tests", () => { const allContainers = [State, ContainerA, ContainerB]; allContainers.forEach((cont) => { defineTypes(cont, { - containersA: [ContainerA], - containersB: [ContainerB], + containersA: { map: ContainerA }, + containersB: { map: ContainerB }, }); }); @@ -135,6 +146,8 @@ describe("Definition Tests", () => { }); it("should find filter on more complex recursive structures - map", () => { + const type = Context.create(); + class ContainerA extends Schema { @type("string") contAName: string; } @@ -158,6 +171,8 @@ describe("Definition Tests", () => { }); it("should be able to navigate on maps and arrays of primitive types", () => { + const type = Context.create(); + class State extends Schema { @type(["string"]) stringArr: MapSchema; @type(["number"]) numberArr: MapSchema;