aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Schicke <tyler_schicke@brown.edu>2019-06-05 22:42:43 -0400
committerTyler Schicke <tyler_schicke@brown.edu>2019-06-05 22:42:43 -0400
commit404dcc71558d8de69369aa499227e5168091351d (patch)
tree05509329005fb08cecfb072ba063391bc6ab8a44
parent2ce189fdf66a0f01b38d28c73c8f6f1247933b3d (diff)
Can now pass list to schema function to get list of that type
Mapped type of a schema can be another schema Added tests for schemas Other minor fixes
-rw-r--r--package.json1
-rw-r--r--src/client/views/MainOverlayTextBox.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx2
-rw-r--r--src/new_fields/Schema.ts34
-rw-r--r--src/new_fields/Types.ts8
-rw-r--r--test/test.ts127
6 files changed, 163 insertions, 11 deletions
diff --git a/package.json b/package.json
index df0767b50..438572b57 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
"css-loader": "^2.1.1",
"file-loader": "^3.0.1",
"fork-ts-checker-webpack-plugin": "^1.0.2",
+ "jsdom": "^15.1.1",
"mocha": "^5.2.0",
"sass-loader": "^7.1.0",
"scss-loader": "0.0.1",
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 24327b995..d1224febe 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -102,6 +102,6 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
</div>
</ div>;
}
- else return (null); Z
+ else return (null);
}
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 81ca4c29a..c699b3437 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -92,7 +92,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
this.pasteTable(ns, x, y);
}
});
- } else {
+ } else if (!e.ctrlKey) {
let newBox = Docs.TextDocument({ width: 200, height: 100, x: x, y: y, title: "-typed text-" });
this.props.addLiveTextDocument(newBox);
}
diff --git a/src/new_fields/Schema.ts b/src/new_fields/Schema.ts
index 250f3c975..40ffaecd5 100644
--- a/src/new_fields/Schema.ts
+++ b/src/new_fields/Schema.ts
@@ -1,5 +1,7 @@
import { Interface, ToInterface, Cast, ToConstructor, HasTail, Head, Tail, ListSpec, ToType, DefaultFieldConstructor } from "./Types";
import { Doc, Field } from "./Doc";
+import { ObjectField } from "./ObjectField";
+import { RefField } from "./RefField";
type AllToInterface<T extends Interface[]> = {
1: ToInterface<Head<T>> & AllToInterface<Tail<T>>,
@@ -10,10 +12,16 @@ export const emptySchema = createSchema({});
export const Document = makeInterface(emptySchema);
export type Document = makeInterface<[typeof emptySchema]>;
+export interface InterfaceFunc<T extends Interface[]> {
+ (docs: Doc[]): makeInterface<T>[];
+ (): makeInterface<T>;
+ (doc: Doc): makeInterface<T>;
+}
+
export type makeInterface<T extends Interface[]> = AllToInterface<T> & Doc & { proto: Doc | undefined };
// export function makeInterface<T extends Interface[], U extends Doc>(schemas: T): (doc: U) => All<T, U>;
// export function makeInterface<T extends Interface, U extends Doc>(schema: T): (doc: U) => makeInterface<T, U>;
-export function makeInterface<T extends Interface[]>(...schemas: T): (doc?: Doc) => makeInterface<T> {
+export function makeInterface<T extends Interface[]>(...schemas: T): InterfaceFunc<T> {
let schema: Interface = {};
for (const s of schemas) {
for (const key in s) {
@@ -25,10 +33,19 @@ export function makeInterface<T extends Interface[]>(...schemas: T): (doc?: Doc)
const field = receiver.doc[prop];
if (prop in schema) {
const desc = (schema as any)[prop];
- if (typeof desc === "object" && "defaultVal" in desc && "type" in desc) {
+ if (typeof desc === "object" && "defaultVal" in desc && "type" in desc) {//defaultSpec
return Cast(field, desc.type, desc.defaultVal);
+ } else if (typeof desc === "function" && !ObjectField.isPrototypeOf(desc) && !RefField.isPrototypeOf(desc)) {
+ const doc = Cast(field, Doc);
+ if (doc === undefined) {
+ return undefined;
+ } else if (doc instanceof Doc) {
+ return desc(doc);
+ } else {
+ return doc.then(doc => doc && desc(doc));
+ }
} else {
- return Cast(field, (schema as any)[prop]);
+ return Cast(field, desc);
}
}
return field;
@@ -38,14 +55,21 @@ export function makeInterface<T extends Interface[]>(...schemas: T): (doc?: Doc)
return true;
}
});
- return function (doc?: Doc) {
- doc = doc || new Doc;
+ const fn = (doc: Doc) => {
if (!(doc instanceof Doc)) {
throw new Error("Currently wrapping a schema in another schema isn't supported");
}
const obj = Object.create(proto, { doc: { value: doc, writable: false } });
return obj;
};
+ return function (doc?: Doc | Doc[]) {
+ doc = doc || new Doc;
+ if (doc instanceof Doc) {
+ return fn(doc);
+ } else {
+ return doc.map(fn);
+ }
+ };
}
export type makeStrictInterface<T extends Interface> = Partial<ToInterface<T>>;
diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts
index c04dd5e6d..8dd893aa4 100644
--- a/src/new_fields/Types.ts
+++ b/src/new_fields/Types.ts
@@ -2,7 +2,7 @@ import { Field, Opt, FieldResult, Doc } from "./Doc";
import { List } from "./List";
import { RefField } from "./RefField";
-export type ToType<T extends ToConstructor<Field> | ListSpec<Field> | DefaultFieldConstructor<Field>> =
+export type ToType<T extends InterfaceValue> =
T extends "string" ? string :
T extends "number" ? number :
T extends "boolean" ? boolean :
@@ -10,7 +10,8 @@ export type ToType<T extends ToConstructor<Field> | ListSpec<Field> | DefaultFie
// T extends { new(...args: any[]): infer R } ? (R | Promise<R>) : never;
T extends DefaultFieldConstructor<infer _U> ? never :
T extends { new(...args: any[]): List<Field> } ? never :
- T extends { new(...args: any[]): infer R } ? R : never;
+ T extends { new(...args: any[]): infer R } ? R :
+ T extends (doc?: Doc) => infer R ? R : never;
export type ToConstructor<T extends Field> =
T extends string ? "string" :
@@ -38,9 +39,10 @@ export type Tail<T extends any[]> =
((...t: T) => any) extends ((_: any, ...tail: infer TT) => any) ? TT : [];
export type HasTail<T extends any[]> = T extends ([] | [any]) ? false : true;
+export type InterfaceValue = ToConstructor<Field> | ListSpec<Field> | DefaultFieldConstructor<Field> | ((doc?: Doc) => any);
//TODO Allow you to optionally specify default values for schemas, which should then make that field not be partial
export interface Interface {
- [key: string]: ToConstructor<Field> | ListSpec<Field> | DefaultFieldConstructor<Field>;
+ [key: string]: InterfaceValue;
// [key: string]: ToConstructor<Field> | ListSpec<Field[]>;
}
diff --git a/test/test.ts b/test/test.ts
index 91dc43379..a7d453af3 100644
--- a/test/test.ts
+++ b/test/test.ts
@@ -1,9 +1,17 @@
import { expect } from 'chai';
import 'mocha';
+const { JSDOM } = require('jsdom');
+const dom = new JSDOM("", {
+ url: "http://localhost:1050"
+});
+(global as any).window = dom.window;
+
+
import { autorun, reaction } from "mobx";
import { Doc } from '../src/new_fields/Doc';
import { Cast } from '../src/new_fields/Types';
-
+import { createSchema, makeInterface, defaultSpec } from '../src/new_fields/Schema';
+import { ImageField } from '../src/new_fields/URLField';
describe("Document", () => {
it('should hold fields', () => {
let key = "Test";
@@ -33,3 +41,120 @@ describe("Document", () => {
expect(ran).to.equal(true);
});
});
+
+const testSchema1 = createSchema({
+ a: "number",
+ b: "string",
+ c: "boolean",
+ d: ImageField,
+ e: Doc
+});
+
+type TestDoc = makeInterface<[typeof testSchema1]>;
+const TestDoc = makeInterface(testSchema1);
+
+const testSchema2 = createSchema({
+ a: defaultSpec("boolean", true),
+ b: defaultSpec("number", 5),
+ c: defaultSpec("string", "hello world")
+});
+
+type TestDoc2 = makeInterface<[typeof testSchema2]>;
+const TestDoc2 = makeInterface(testSchema2);
+
+const testSchema3 = createSchema({
+ a: TestDoc2
+});
+
+type TestDoc3 = makeInterface<[typeof testSchema3]>;
+const TestDoc3 = makeInterface(testSchema3);
+
+describe("Schema", () => {
+ it("should do the right thing 1", () => {
+ const test1 = new Doc;
+ const test2 = new Doc;
+ const ifield = new ImageField(new URL("http://google.com"));
+ test1.a = 5;
+ test1.b = "hello";
+ test1.c = true;
+ test1.d = ifield;
+ test1.e = test2;
+ const doc = TestDoc(test1);
+ expect(doc.a).to.equal(5);
+ expect(doc.b).to.equal("hello");
+ expect(doc.c).to.equal(true);
+ expect(doc.d).to.equal(ifield);
+ expect(doc.e).to.equal(test2);
+ });
+
+ it("should do the right thing 2", () => {
+ const test1 = new Doc;
+ const test2 = new Doc;
+ const ifield = new ImageField(new URL("http://google.com"));
+ test1.a = "hello";
+ test1.b = 5;
+ test1.c = test2;
+ test1.d = true;
+ test1.e = ifield;
+ const doc = TestDoc(test1);
+ expect(doc.a).to.equal(undefined);
+ expect(doc.b).to.equal(undefined);
+ expect(doc.c).to.equal(undefined);
+ expect(doc.d).to.equal(undefined);
+ expect(doc.e).to.equal(undefined);
+ });
+
+ it("should do the right thing 2", () => {
+ const test1 = new Doc;
+ const test2 = new Doc;
+ const ifield = new ImageField(new URL("http://google.com"));
+ test1.a = "hello";
+ test1.b = 5;
+ test1.c = test2;
+ test1.d = true;
+ test1.e = ifield;
+ const doc = TestDoc(test1);
+ expect(doc.a).to.equal(undefined);
+ expect(doc.b).to.equal(undefined);
+ expect(doc.c).to.equal(undefined);
+ expect(doc.d).to.equal(undefined);
+ expect(doc.e).to.equal(undefined);
+ });
+
+ it("should do the right thing 3", () => {
+ const doc = TestDoc2();
+ expect(doc.a).to.equal(true);
+ expect(doc.b).to.equal(5);
+ expect(doc.c).to.equal("hello world");
+
+ const d2 = new Doc;
+ d2.a = false;
+ d2.b = 4;
+ d2.c = "goodbye";
+ const doc2 = TestDoc2(d2);
+ expect(doc2.a).to.equal(false);
+ expect(doc2.b).to.equal(4);
+ expect(doc2.c).to.equal("goodbye");
+
+ const d3 = new Doc;
+ d3.a = "hello";
+ d3.b = false;
+ d3.c = 5;
+ const doc3 = TestDoc2(d3);
+ expect(doc3.a).to.equal(true);
+ expect(doc3.b).to.equal(5);
+ expect(doc3.c).to.equal("hello world");
+ });
+
+ it("should do the right thing 4", async () => {
+ const test1 = new Doc;
+ const test2 = new Doc;
+ const doc = TestDoc3(test1);
+ expect(doc.a).to.equal(undefined);
+ test1.a = test2;
+ const doc2 = doc.a as TestDoc2;//(await doc.a)!;
+ expect(doc2.a).to.equal(true);
+ expect(doc2.b).to.equal(5);
+ expect(doc2.c).to.equal("hello world");
+ });
+});