Skip to content
This repository has been archived by the owner on Nov 28, 2019. It is now read-only.

Commit

Permalink
feat: created collectSchema which recursively can create schema from …
Browse files Browse the repository at this point in the history
…MessageClass
  • Loading branch information
elderapo committed Feb 16, 2019
1 parent 1e72acc commit 5258543
Show file tree
Hide file tree
Showing 5 changed files with 757 additions and 0 deletions.
106 changes: 106 additions & 0 deletions src/collectSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { getMetadataObject, hasMetadataObject } from "./metadataHelpers";
import { IFieldInfo, IFieldOptions, ProtobufLiteMetadata } from "./ProtobufLiteMetadata";
import { getPrototypeChain, Omit } from "./utils";

export type FieldInfoWithoutPropertyKey = Omit<IFieldInfo, "propertyKey">;

export interface ISchema {
refs: FieldInfoWithoutPropertyKey[][];
fieldsInfo: FieldInfoWithoutPropertyKey[];
}

export const collectSchema = (MessageClass: Function): ISchema => {
/* istanbul ignore next line */
if (!hasMetadataObject(MessageClass)) {
throw new Error(`MessageClass doesn't have protobuf lite metadata assosiated!`);
}

const metadata = getMetadataObject(MessageClass);

const schema: ISchema = {
refs: [],
fieldsInfo: []
};

const mapField = (fieldInfo: IFieldInfo): FieldInfoWithoutPropertyKey => {
if (childTypesByClassName.has(fieldInfo.prototype)) {
const fieldOptions = childTypesByClassName.get(fieldInfo.prototype) as IFieldOptions;
const indexRef = indexedChildTypes.indexOf(fieldOptions);

return { prototype: `__ref__${indexRef}__`, rule: fieldInfo.rule };
}

return { prototype: fieldInfo.prototype, rule: fieldInfo.rule };
};

const childTypesByClassName = new Map<string, IFieldOptions>();
const indexedChildTypes: IFieldOptions[] = [];

const collectChildTypes = (childTypes: IFieldOptions[]) => {
for (let item of childTypes) {
const metadata = getMetadataObject(item.MessageClass);

if (!childTypesByClassName.has(metadata.getMessageClassName())) {
childTypesByClassName.set(metadata.getMessageClassName(), item);
indexedChildTypes.push(item);

if (metadata.getChildTypes()) {
collectChildTypes(metadata.getChildTypes());
}
}
}
};

collectChildTypes(metadata.getChildTypes());

const alreadyCollectedChildTypes = new Map<ProtobufLiteMetadata, boolean>();

const handleChildTypes = (childTypes: IFieldOptions[]) => {
for (let item of childTypes) {
const metadata = getMetadataObject(item.MessageClass);

if (alreadyCollectedChildTypes.has(metadata)) {
continue;
}
alreadyCollectedChildTypes.set(metadata, true);

schema.refs.push(metadata.getFieldsInfo().map(mapField));

if (metadata.getChildTypes()) {
handleChildTypes(metadata.getChildTypes());
}
}
};

handleChildTypes(metadata.getChildTypes());

// const MessageClass = metadata.getMessageClass();
const prototypes = getPrototypeChain(MessageClass)
.reverse()
.filter(p => p !== MessageClass.prototype);

const alreadyUsedPropertyKeys: Map<string, boolean> = new Map();

const addFields = (fields: IFieldInfo[]) => {
for (let field of fields) {
if (alreadyUsedPropertyKeys.has(field.propertyKey)) {
throw new Error(`Parent class field was most likely overwrited by child class!`);
}

schema.fieldsInfo.push(mapField(field));

alreadyUsedPropertyKeys.set(field.propertyKey, true);
}
};

for (let prototype of prototypes) {
const mt = getMetadataObject(prototype.constructor);
const fields = mt.getFieldsInfo();

addFields(fields);
}

addFields(metadata.getFieldsInfo());

return schema;
};
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./collectSchema";
export * from "./encoderDecoderFunctions";
export * from "./ProtobufLiteProperty";
2 changes: 2 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

export interface Constructable<T> {
new (): T;
}
Expand Down
Loading

0 comments on commit 5258543

Please sign in to comment.