From 3465286454763329b956ec72e1c1500fb49b04c6 Mon Sep 17 00:00:00 2001 From: Anthony Gubler Date: Thu, 18 Mar 2021 11:00:49 +0000 Subject: [PATCH 1/5] Enable inferring data and api from resource enabled widgets --- package-lock.json | 62 ++++- package.json | 2 +- src/core/middleware/resources.ts | 65 +++++- src/testing/renderer.ts | 4 +- tests/core/unit/middleware/inert.ts | 3 +- tests/core/unit/middleware/resources.tsx | 276 ++++++++++++++++++++++- 6 files changed, 403 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index b61a876cb..ed800bd17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -121,6 +121,12 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true + }, + "typescript": { + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz", + "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==", + "dev": true } } }, @@ -168,6 +174,14 @@ "requires": { "axios": "~0.18.0", "tslib": "~1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + } } }, "@theintern/digdug": { @@ -188,6 +202,12 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", "dev": true + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true } } }, @@ -200,6 +220,14 @@ "@theintern/common": "~0.1.3", "jszip": "~3.1.5", "tslib": "~1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + } } }, "@types/babel-types": { @@ -3905,6 +3933,14 @@ "dev": true, "requires": { "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "strip-ansi": { @@ -3988,6 +4024,12 @@ "lodash": "^4.17.4", "platform": "^1.3.3" } + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true } } }, @@ -7810,6 +7852,12 @@ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "tsutils": { "version": "2.29.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", @@ -7837,6 +7885,14 @@ "dev": true, "requires": { "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "tunnel-agent": { @@ -7897,9 +7953,9 @@ "dev": true }, "typescript": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz", - "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", "dev": true }, "uglify-js": { diff --git a/package.json b/package.json index ba9292558..ca149e222 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "rimraf": "~2.6.2", "selenium-webdriver": "3.6.0", "sinon": "~4.1.3", - "typescript": "3.4.5" + "typescript": "3.5.3" }, "lint-staged": { "*.{ts,tsx,md}": [ diff --git a/src/core/middleware/resources.ts b/src/core/middleware/resources.ts index 5a1b48074..3b20bcea5 100644 --- a/src/core/middleware/resources.ts +++ b/src/core/middleware/resources.ts @@ -3,6 +3,7 @@ import Map from '../../shim/Map'; import { create, invalidator, diffProperty, destroy } from '../vdom'; import icache from './icache'; import { auto } from '../diff'; +import { DefaultChildrenWNodeFactory, WNodeFactory, OptionalWNodeFactory, WNodeFactoryTypes } from '../interfaces'; export interface ReadQuery { [index: string]: any; @@ -239,6 +240,67 @@ export function defaultFilter(query: ReadQuery, item: any, type: string = 'conta return true; } +export type WidgetFactory = + | DefaultChildrenWNodeFactory + | WNodeFactory + | OptionalWNodeFactory; + +// move this back to inline mayba +export function createResourceTemplate< + P extends WidgetFactory, + T extends TemplateFactory< + P extends WidgetFactory>> + ? D + : P extends WidgetFactory>> ? D : void, + any, + P extends WidgetFactory>> + ? R extends CustomTemplate ? CustomTemplateApi : void + : P extends WidgetFactory>> + ? CustomTemplateApi + : void + > +>( + widget: P, + template: T +): T extends TemplateFactory + ? P extends WidgetFactory>> + ? TemplateWithOptionsFactory + : P extends WidgetFactory>> + ? TemplateWithOptionsFactory + : void + : void; +export function createResourceTemplate

>( + widget: P, + template: P extends WidgetFactory>> + ? R extends CustomTemplate ? Template & CustomTemplateApi : void + : P extends WidgetFactory>> + ? Template & CustomTemplateApi + : void +): P extends WidgetFactory>> + ? R extends CustomTemplate + ? { + template: { + template: () => Template; + templateOptions: any; + api: R; + }; + } + : void + : P extends WidgetFactory>> + ? { + template: { + template: () => Template; + templateOptions: any; + api: DefaultApi; + }; + } + : void; +export function createResourceTemplate

>( + widget: P, + idKey: P extends WidgetFactory>> ? keyof D : void +): P extends WidgetFactory>> + ? TemplateWithOptionsFactory + : void; export function createResourceTemplate( template: Template & CustomTemplateApi ): { @@ -254,7 +316,8 @@ export function createResourceTemplate( idKey: keyof RESOURCE_DATA ): TemplateWithOptionsFactory; -export function createResourceTemplate(template?: any): any { +export function createResourceTemplate(templateOrWidget: any, template?: any): any { + template = template || templateOrWidget; if (typeof template === 'function') { return (templateOptions: any) => { return { diff --git a/src/testing/renderer.ts b/src/testing/renderer.ts index 862b537e3..9474d2fe5 100644 --- a/src/testing/renderer.ts +++ b/src/testing/renderer.ts @@ -95,11 +95,11 @@ export interface DecoratorResult { nodes: T; } -function isWrappedNode(value: any): value is (WNode & { id: string }) | (WNode & { id: string }) { +function isWrappedNode(value: any): value is Wrapped { return Boolean(value && value.id && (isWNode(value) || isVNode(value))); } -function findNode>(renderResult: RenderResult, wrapped: T): VNode | WNode { +function findNode(renderResult: RenderResult, wrapped: Wrapped): VNode | WNode { renderResult = decorateNodes(renderResult).nodes; let nodes: any[] = Array.isArray(renderResult) ? [...renderResult] : [renderResult]; while (nodes.length) { diff --git a/tests/core/unit/middleware/inert.ts b/tests/core/unit/middleware/inert.ts index 56d430a7e..2086fa235 100644 --- a/tests/core/unit/middleware/inert.ts +++ b/tests/core/unit/middleware/inert.ts @@ -4,10 +4,11 @@ const { describe: jsdomDescribe } = intern.getPlugin('jsdom'); const { assert } = intern.getPlugin('chai'); import { stub } from 'sinon'; -import icacheMiddleware from '../../../../src/core/middleware/icache'; +import { createICacheMiddleware } from '../../../../src/core/middleware/icache'; import inertMiddleware from '../../../../src/core/middleware/inert'; let invalidatorStub = stub(); +const icacheMiddleware = createICacheMiddleware(); jsdomDescribe('inert middleware', () => { let icache = icacheMiddleware().callback({ diff --git a/tests/core/unit/middleware/resources.tsx b/tests/core/unit/middleware/resources.tsx index 2427eb675..b0b283f8c 100644 --- a/tests/core/unit/middleware/resources.tsx +++ b/tests/core/unit/middleware/resources.tsx @@ -9,7 +9,8 @@ import { createResourceMiddleware, createResourceTemplate, DefaultApi, - ReadOptionsData + ReadOptionsData, + ReadRequest } from '../../../../src/core/middleware/resources'; import icache from '../../../../src/core/middleware/icache'; import { spy } from 'sinon'; @@ -200,6 +201,196 @@ jsdomDescribe('Resources Middleware', () => { '

[{"value":"0"},{"value":"1"},{"value":"2"},{"value":"3"},{"value":"4"}]
' ); }); + + it('Should be able to infer the resource data from widget for the default template', () => { + const resource = createResourceMiddleware(); + const factory = create({ resource }); + const Widget = factory(function App({ properties, middleware: { resource } }) { + const { + resource: { template } + } = properties(); + const { + get, + createOptions, + template: { read } + } = resource.template(template); + const options = createOptions(testOptionsSetter); + const data = get(options(), { read }); + return
{JSON.stringify(data)}
; + }); + const testTemplate = createResourceTemplate(Widget, 'value'); + + const App = create({ resource: createResourceMiddleware() })(function App({ + id, + middleware: { resource } + }) { + return ; + }); + const domNode = document.createElement('div'); + const r = renderer(() => ); + r.mount({ domNode }); + assert.strictEqual( + domNode.innerHTML, + '
[{"value":"0"},{"value":"1"},{"value":"2"},{"value":"3"},{"value":"4"}]
' + ); + }); + + it('Should be able to infer the resource data from widget', () => { + const resource = createResourceMiddleware(); + const factory = create({ resource }); + const Widget = factory(function App({ properties, middleware: { resource } }) { + const { + resource: { template } + } = properties(); + const { + get, + createOptions, + template: { read } + } = resource.template(template); + const options = createOptions(testOptionsSetter); + const data = get(options(), { read }); + return
{JSON.stringify(data)}
; + }); + const testTemplate = createResourceTemplate(Widget, { + idKey: 'value', + read: (request, { put }) => { + const { offset } = request; + put({ data: [...testData].slice(offset), total: testData.length }, request); + } + }); + + const App = create({ resource: createResourceMiddleware() })(function App({ + id, + middleware: { resource } + }) { + return ; + }); + const domNode = document.createElement('div'); + const r = renderer(() => ); + r.mount({ domNode }); + assert.strictEqual( + domNode.innerHTML, + '
[{"value":"0"},{"value":"1"},{"value":"2"},{"value":"3"},{"value":"4"}]
' + ); + }); + + it('Should be able to infer the resource data from widget for custom template with options', () => { + const resource = createResourceMiddleware(); + const factory = create({ resource }); + const Widget = factory(function App({ properties, middleware: { resource } }) { + const { + resource: { template } + } = properties(); + const { + get, + createOptions, + template: { read } + } = resource.template(template); + const options = createOptions(testOptionsSetter); + const data = get(options(), { read }); + return
{JSON.stringify(data)}
; + }); + const testTemplate = createResourceTemplate(Widget, ({ data }: { data: TestData[] }) => ({ + idKey: 'value', + read: (request, { put }) => { + const { offset } = request; + put({ data: data.slice(offset), total: data.length }, request); + } + })); + + const App = create({ resource: createResourceMiddleware() })(function App({ + id, + middleware: { resource } + }) { + return ; + }); + const domNode = document.createElement('div'); + const r = renderer(() => ); + r.mount({ domNode }); + assert.strictEqual( + domNode.innerHTML, + '
[{"value":"0"},{"value":"1"},{"value":"2"},{"value":"3"},{"value":"4"}]
' + ); + }); + + it('Should be able to infer the resource data and api from widget', () => { + const resource = createResourceMiddleware void }>(); + const factory = create({ resource }); + const Widget = factory(function App({ properties, middleware: { resource } }) { + const { + resource: { template } + } = properties(); + const { + get, + createOptions, + template: { scan } + } = resource.template(template); + const options = createOptions(testOptionsSetter); + const data = get(options(), { read: scan }); + return
{JSON.stringify(data)}
; + }); + const testTemplate = createResourceTemplate(Widget, { + idKey: 'value', + scan: (request, { put }) => { + const { offset } = request; + put({ data: [...testData].slice(offset), total: testData.length }, request); + } + }); + + const App = create({ resource: createResourceMiddleware() })(function App({ + id, + middleware: { resource } + }) { + return ; + }); + const domNode = document.createElement('div'); + const r = renderer(() => ); + r.mount({ domNode }); + assert.strictEqual( + domNode.innerHTML, + '
[{"value":"0"},{"value":"1"},{"value":"2"},{"value":"3"},{"value":"4"}]
' + ); + }); + + it('Should be able to infer the resource data and api from widget for custom template with options', () => { + const resource = createResourceMiddleware void }>(); + const factory = create({ resource }); + const Widget = factory(function App({ properties, middleware: { resource } }) { + const { + resource: { template } + } = properties(); + const { + get, + createOptions, + template: { scan } + } = resource.template(template); + const options = createOptions(testOptionsSetter); + const data = get(options(), { read: scan }); + return
{JSON.stringify(data)}
; + }); + const testTemplate = createResourceTemplate(Widget, ({ data }: { data: TestData[] }) => ({ + idKey: 'value', + scan: (request, { put }) => { + const { offset } = request; + put({ data: data.slice(offset), total: data.length }, request); + } + })); + + const App = create({ resource: createResourceMiddleware() })(function App({ + id, + middleware: { resource } + }) { + return ; + }); + const domNode = document.createElement('div'); + const r = renderer(() => ); + r.mount({ domNode }); + assert.strictEqual( + domNode.innerHTML, + '
[{"value":"0"},{"value":"1"},{"value":"2"},{"value":"3"},{"value":"4"}]
' + ); + }); + it('Should support passing a template to a widget using the short hand', () => { const resource = createResourceMiddleware(); const factory = create({ resource }); @@ -2117,6 +2308,43 @@ jsdomDescribe('Resources Middleware', () => { '
[{"value":"0"},{"value":"1"},{"value":"2"},{"value":"3"},{"value":"4"}]
' ); }); + it('Should be able infer the required custom api from a widget when creating the template', () => { + const resource = createResourceMiddleware void }>(); + const factory = create({ resource }); + + const Widget = factory(function Widget({ properties, middleware: { resource } }) { + const { + resource: { template } + } = properties(); + const { + get, + createOptions, + template: { scan } + } = resource.template(template); + const options = createOptions(testOptionsSetter); + const data = get(options(), { read: scan }); + return
{JSON.stringify(data)}
; + }); + + const template = createResourceTemplate(Widget, { + idKey: 'value', + scan: (req, controls) => { + const { size, offset } = req; + let filteredData = [...testData]; + controls.put({ data: filteredData.slice(offset, offset + size), total: filteredData.length }, req); + } + }); + const App = create({ resource: createResourceMiddleware() })(function App({ middleware: { resource } }) { + return ; + }); + const domNode = document.createElement('div'); + const r = renderer(() => ); + r.mount({ domNode }); + assert.strictEqual( + domNode.innerHTML, + '
[{"value":"0"},{"value":"1"},{"value":"2"},{"value":"3"},{"value":"4"}]
' + ); + }); }); describe('Saving Resources', () => { it('should be able to use custom template apis to save resources', () => { @@ -2363,4 +2591,50 @@ jsdomDescribe('Resources Middleware', () => { assert.strictEqual(readCounter, 2); }); }); + + describe('infer data and api from widget', () => { + const resource = createResourceMiddleware<{ foo: string }>(); + const resourceWithCustomApi = createResourceMiddleware<{ foo: string }, { save: (id: string) => void }>(); + const factory = create({ resource }); + const factoryWithCustomApi = create({ resource: resourceWithCustomApi }); + const ResourceWidget = factory(() => ''); + const templateForResourceWidget = createResourceTemplate(ResourceWidget, { + idKey: 'foo', + read: (r, d) => { + r; + d; + } + }); + const defaultTemplateForResourceWidget = createResourceTemplate(ResourceWidget, 'foo'); + const templateWithOptionsForResourceWidget = createResourceTemplate( + ResourceWidget, + (options: { bar: number }) => ({ + idKey: 'foo', + read: (r, f) => {} + }) + ); + templateWithOptionsForResourceWidget({ bar: 2, id: '' }); + const ResourceWidgetWithCustomApi = factoryWithCustomApi(() => ''); + const templateForResourceWidgetWithCustomApi = createResourceTemplate(ResourceWidgetWithCustomApi, { + idKey: 'foo', + save: (i, t) => {} + }); + // Do not support default template for custom apis + // const defaultTemplateForResourceWidgetWithCustomApi = createResourceTemplate( + // ResourceWidgetWithCustomApi, + // 'foo' + // ); + const templateWithOptionsForResourceWidgetWithCustomApi = createResourceTemplate( + ResourceWidgetWithCustomApi, + (options: { bar: number }) => ({ + idKey: 'foo', + save: () => {} + }) + ); + templateWithOptionsForResourceWidgetWithCustomApi({ bar: 2, id: '' }); + templateForResourceWidget; + defaultTemplateForResourceWidget; + templateForResourceWidgetWithCustomApi; + // defaultTemplateForResourceWidgetWithCustomApi; + }); }); From c07662cbced28900d32df97e432feecc9c5da63c Mon Sep 17 00:00:00 2001 From: Anthony Gubler Date: Thu, 18 Mar 2021 11:02:07 +0000 Subject: [PATCH 2/5] remove comment --- src/core/middleware/resources.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/middleware/resources.ts b/src/core/middleware/resources.ts index 3b20bcea5..78b62e16f 100644 --- a/src/core/middleware/resources.ts +++ b/src/core/middleware/resources.ts @@ -245,7 +245,6 @@ export type WidgetFactory = | WNodeFactory | OptionalWNodeFactory; -// move this back to inline mayba export function createResourceTemplate< P extends WidgetFactory, T extends TemplateFactory< From d5f4e2b101be09caad4c5d9d74832efaee7105bd Mon Sep 17 00:00:00 2001 From: Anthony Gubler Date: Thu, 18 Mar 2021 11:03:48 +0000 Subject: [PATCH 3/5] remove testing examples --- tests/core/unit/middleware/resources.tsx | 46 ------------------------ 1 file changed, 46 deletions(-) diff --git a/tests/core/unit/middleware/resources.tsx b/tests/core/unit/middleware/resources.tsx index b0b283f8c..fef72df3f 100644 --- a/tests/core/unit/middleware/resources.tsx +++ b/tests/core/unit/middleware/resources.tsx @@ -2591,50 +2591,4 @@ jsdomDescribe('Resources Middleware', () => { assert.strictEqual(readCounter, 2); }); }); - - describe('infer data and api from widget', () => { - const resource = createResourceMiddleware<{ foo: string }>(); - const resourceWithCustomApi = createResourceMiddleware<{ foo: string }, { save: (id: string) => void }>(); - const factory = create({ resource }); - const factoryWithCustomApi = create({ resource: resourceWithCustomApi }); - const ResourceWidget = factory(() => ''); - const templateForResourceWidget = createResourceTemplate(ResourceWidget, { - idKey: 'foo', - read: (r, d) => { - r; - d; - } - }); - const defaultTemplateForResourceWidget = createResourceTemplate(ResourceWidget, 'foo'); - const templateWithOptionsForResourceWidget = createResourceTemplate( - ResourceWidget, - (options: { bar: number }) => ({ - idKey: 'foo', - read: (r, f) => {} - }) - ); - templateWithOptionsForResourceWidget({ bar: 2, id: '' }); - const ResourceWidgetWithCustomApi = factoryWithCustomApi(() => ''); - const templateForResourceWidgetWithCustomApi = createResourceTemplate(ResourceWidgetWithCustomApi, { - idKey: 'foo', - save: (i, t) => {} - }); - // Do not support default template for custom apis - // const defaultTemplateForResourceWidgetWithCustomApi = createResourceTemplate( - // ResourceWidgetWithCustomApi, - // 'foo' - // ); - const templateWithOptionsForResourceWidgetWithCustomApi = createResourceTemplate( - ResourceWidgetWithCustomApi, - (options: { bar: number }) => ({ - idKey: 'foo', - save: () => {} - }) - ); - templateWithOptionsForResourceWidgetWithCustomApi({ bar: 2, id: '' }); - templateForResourceWidget; - defaultTemplateForResourceWidget; - templateForResourceWidgetWithCustomApi; - // defaultTemplateForResourceWidgetWithCustomApi; - }); }); From f1d93a7023d41fb80ea8998a60e5f10ae2980753 Mon Sep 17 00:00:00 2001 From: Anthony Gubler Date: Thu, 18 Mar 2021 13:26:40 +0000 Subject: [PATCH 4/5] Enable inferring data and api from resource enabled widgets --- src/core/middleware/resources.ts | 82 ++++++++++++++------------------ 1 file changed, 35 insertions(+), 47 deletions(-) diff --git a/src/core/middleware/resources.ts b/src/core/middleware/resources.ts index 78b62e16f..3ac0057e6 100644 --- a/src/core/middleware/resources.ts +++ b/src/core/middleware/resources.ts @@ -245,61 +245,49 @@ export type WidgetFactory = | WNodeFactory | OptionalWNodeFactory; +export type WidgetResourceData> = W extends WidgetFactory< + WNodeFactoryTypes> +> + ? D + : void; +export type WidgetResourceApi> = W extends WidgetFactory< + WNodeFactoryTypes> +> + ? R extends CustomTemplate ? R : DefaultApi + : DefaultApi; +export type WidgetResourceTemplateApi> = W extends WidgetFactory< + WNodeFactoryTypes> +> + ? R extends CustomTemplate ? CustomTemplateApi : CustomTemplateApi + : CustomTemplateApi>; + export function createResourceTemplate< - P extends WidgetFactory, + W extends WidgetFactory, T extends TemplateFactory< - P extends WidgetFactory>> - ? D - : P extends WidgetFactory>> ? D : void, + WidgetResourceData, any, - P extends WidgetFactory>> - ? R extends CustomTemplate ? CustomTemplateApi : void - : P extends WidgetFactory>> - ? CustomTemplateApi - : void + CustomTemplateApi, WidgetResourceData> > >( - widget: P, + widget: W, template: T ): T extends TemplateFactory - ? P extends WidgetFactory>> - ? TemplateWithOptionsFactory - : P extends WidgetFactory>> - ? TemplateWithOptionsFactory - : void - : void; -export function createResourceTemplate

>( - widget: P, - template: P extends WidgetFactory>> - ? R extends CustomTemplate ? Template & CustomTemplateApi : void - : P extends WidgetFactory>> - ? Template & CustomTemplateApi - : void -): P extends WidgetFactory>> - ? R extends CustomTemplate - ? { - template: { - template: () => Template; - templateOptions: any; - api: R; - }; - } - : void - : P extends WidgetFactory>> - ? { - template: { - template: () => Template; - templateOptions: any; - api: DefaultApi; - }; - } - : void; -export function createResourceTemplate

>( - widget: P, - idKey: P extends WidgetFactory>> ? keyof D : void -): P extends WidgetFactory>> - ? TemplateWithOptionsFactory + ? TemplateWithOptionsFactory, O, WidgetResourceApi> : void; +export function createResourceTemplate>( + widget: W, + template: Template> & WidgetResourceTemplateApi +): { + template: { + template: () => Template>; + templateOptions: any; + api: WidgetResourceApi; + }; +}; +export function createResourceTemplate>( + widget: W, + idKey: keyof WidgetResourceData +): TemplateWithOptionsFactory, { data: WidgetResourceData[] }, DefaultApi>; export function createResourceTemplate( template: Template & CustomTemplateApi ): { From 1cad718ad96e927523c897d9489f2cd9137f4b47 Mon Sep 17 00:00:00 2001 From: Anthony Gubler Date: Thu, 18 Mar 2021 13:32:04 +0000 Subject: [PATCH 5/5] clean up types --- src/core/middleware/resources.ts | 8 ++++---- tests/core/unit/middleware/resources.tsx | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/middleware/resources.ts b/src/core/middleware/resources.ts index 3ac0057e6..904c8b2c5 100644 --- a/src/core/middleware/resources.ts +++ b/src/core/middleware/resources.ts @@ -240,22 +240,22 @@ export function defaultFilter(query: ReadQuery, item: any, type: string = 'conta return true; } -export type WidgetFactory = +type WidgetFactory = | DefaultChildrenWNodeFactory | WNodeFactory | OptionalWNodeFactory; -export type WidgetResourceData> = W extends WidgetFactory< +type WidgetResourceData> = W extends WidgetFactory< WNodeFactoryTypes> > ? D : void; -export type WidgetResourceApi> = W extends WidgetFactory< +type WidgetResourceApi> = W extends WidgetFactory< WNodeFactoryTypes> > ? R extends CustomTemplate ? R : DefaultApi : DefaultApi; -export type WidgetResourceTemplateApi> = W extends WidgetFactory< +type WidgetResourceTemplateApi> = W extends WidgetFactory< WNodeFactoryTypes> > ? R extends CustomTemplate ? CustomTemplateApi : CustomTemplateApi diff --git a/tests/core/unit/middleware/resources.tsx b/tests/core/unit/middleware/resources.tsx index fef72df3f..930497271 100644 --- a/tests/core/unit/middleware/resources.tsx +++ b/tests/core/unit/middleware/resources.tsx @@ -329,6 +329,7 @@ jsdomDescribe('Resources Middleware', () => { const data = get(options(), { read: scan }); return

{JSON.stringify(data)}
; }); + const testTemplate = createResourceTemplate(Widget, { idKey: 'value', scan: (request, { put }) => {