Skip to content
This repository was archived by the owner on May 5, 2021. It is now read-only.

Commit 470fc4b

Browse files
Gorashdmo-odoo
authored andcommitted
[IMP] Renderer: add Renderer for modifiers.
1 parent 9229965 commit 470fc4b

File tree

12 files changed

+244
-68
lines changed

12 files changed

+244
-68
lines changed

packages/core/src/Modifier.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import { Constructor } from '../../utils/src/utils';
22
import { VNode } from './VNodes/VNode';
33

4+
export type ModifierTypeguard<T extends Modifier> = (
5+
modifier: Modifier,
6+
batch: VNode[],
7+
) => modifier is T;
8+
export type ModifierPredicate<T = Modifier | boolean> = T extends Modifier
9+
? Constructor<T> | ModifierTypeguard<T>
10+
: (modifier: Modifier, batch: VNode[]) => boolean;
11+
412
interface ModifierConstructor {
513
new <T extends Constructor<Modifier>>(...args: ConstructorParameters<T>): this;
614
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { AbstractModifierRenderer } from '../../plugin-renderer/src/AbstractModifierRenderer';
2+
import { Modifier } from '../../core/src/Modifier';
3+
import { HtmlDomRenderingEngine } from './HtmlDomRenderingEngine';
4+
5+
export class DefaultHtmlDomModifierRenderer extends AbstractModifierRenderer<Node[]> {
6+
static id = 'dom/html';
7+
engine: HtmlDomRenderingEngine;
8+
9+
/**
10+
* Default rendering for Format.
11+
*
12+
* @param modifier
13+
* @param contents
14+
*/
15+
async render(modifier: Modifier, contents: Node[][]): Promise<Node[]> {
16+
const flatten: Node[] = [];
17+
for (const nodes of contents) {
18+
flatten.push(...nodes);
19+
}
20+
return flatten;
21+
}
22+
}

packages/plugin-html/src/HtmlDomRenderingEngine.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { RenderingEngine } from '../../plugin-renderer/src/RenderingEngine';
22
import { DefaultHtmlDomRenderer } from './DefaultHtmlDomRenderer';
3+
import { DefaultHtmlDomModifierRenderer } from './DefaultHtmlDomModifierRenderer';
34
import { VNode } from '../../core/src/VNodes/VNode';
45
import { Renderer } from '../../plugin-renderer/src/Renderer';
56
import { DomObjectRenderingEngine } from '../../plugin-renderer-dom-object/src/DomObjectRenderingEngine';
67

78
export class HtmlDomRenderingEngine extends RenderingEngine<Node[]> {
89
static id = 'dom/html';
910
static readonly defaultRenderer = DefaultHtmlDomRenderer;
11+
static readonly defaultModifierRenderer = DefaultHtmlDomModifierRenderer;
1012

1113
/**
1214
* Render the given node.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { AbstractModifierRenderer } from '../../plugin-renderer/src/AbstractModifierRenderer';
2+
import { Modifier } from '../../core/src/Modifier';
3+
import { DomObjectRenderingEngine, DomObject } from './DomObjectRenderingEngine';
4+
5+
export class DefaultDomObjectModifierRenderer extends AbstractModifierRenderer<DomObject> {
6+
static id = 'dom/object';
7+
engine: DomObjectRenderingEngine;
8+
9+
/**
10+
* Default rendering for Modifier.
11+
*
12+
* @param modifier
13+
* @param contents
14+
*/
15+
async render(modifier: Modifier, contents: DomObject[]): Promise<DomObject> {
16+
if (contents.length === 1) {
17+
return contents[0];
18+
} else {
19+
return { children: contents };
20+
}
21+
}
22+
}

packages/plugin-renderer-dom-object/src/DomObjectRenderer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import { Parser } from '../../plugin-parser/src/Parser';
44
import { Renderer } from '../../plugin-renderer/src/Renderer';
55
import { Xml } from '../../plugin-xml/src/Xml';
66
import { DomObjectRenderingEngine } from './DomObjectRenderingEngine';
7+
import { FormatDomObjectModifierRenderer } from './FormatDomObjectModifierRenderer';
78

89
export class DomObjectRenderer<T extends JWPluginConfig = JWPluginConfig> extends JWPlugin<T> {
910
static dependencies = [Parser, Renderer, Xml];
1011
readonly loadables: Loadables<Parser & Renderer> = {
1112
renderingEngines: [DomObjectRenderingEngine],
13+
renderers: [FormatDomObjectModifierRenderer],
1214
};
1315
}

packages/plugin-renderer-dom-object/src/DomObjectRenderingEngine.ts

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import { RenderingEngine, Renderer } from '../../plugin-renderer/src/RenderingEngine';
1+
import { RenderingEngine, RenderingIdentifier } from '../../plugin-renderer/src/RenderingEngine';
22
import { DefaultDomObjectRenderer } from './DefaultDomObjectRenderer';
3+
import { DefaultDomObjectModifierRenderer } from './DefaultDomObjectModifierRenderer';
34
import { VNode } from '../../core/src/VNodes/VNode';
45
import { AtomicNode } from '../../core/src/VNodes/AtomicNode';
56
import { Attributes } from '../../plugin-xml/src/Attributes';
67
import { AbstractNode } from '../../core/src/VNodes/AbstractNode';
78
import { Format } from '../../core/src/Format';
89
import { flat } from '../../utils/src/utils';
10+
import { AbstractRenderer } from '../../plugin-renderer/src/AbstractRenderer';
911

1012
/**
1113
* Renderer a node can define the location when define the nodes attributes.
@@ -214,11 +216,12 @@ export type DomObjectNative = {
214216
};
215217
export type DomObject = DomObjectElement | DomObjectFragment | DomObjectText | DomObjectNative;
216218

217-
type RenderingBatchUnit = [VNode, Format[], Renderer<DomObject>];
219+
type RenderingBatchUnit = [VNode, Format[], AbstractRenderer<DomObject>];
218220

219221
export class DomObjectRenderingEngine extends RenderingEngine<DomObject> {
220-
static readonly id = 'dom/object';
222+
static readonly id: RenderingIdentifier = 'dom/object';
221223
static readonly defaultRenderer = DefaultDomObjectRenderer;
224+
static readonly defaultModifierRenderer = DefaultDomObjectModifierRenderer;
222225
/**
223226
* Render the attributes of the given VNode onto the given DOM Element.
224227
*
@@ -305,40 +308,14 @@ export class DomObjectRenderingEngine extends RenderingEngine<DomObject> {
305308
}
306309
}
307310
}
308-
/**
309-
* Wrap list of DomObject into a formating DomObject.
310-
*
311-
* @param renderings
312-
* @param format
313-
*/
314-
async renderFormat(renderings: DomObject[], format: Format): Promise<DomObject> {
315-
if (format) {
316-
const domObject: DomObject = {
317-
tag: format.htmlTag.toUpperCase(),
318-
attributes: {},
319-
children: renderings,
320-
};
321-
const attributes = format.modifiers.find(Attributes);
322-
if (attributes) {
323-
for (const name of attributes.keys()) {
324-
domObject.attributes[name] = attributes.get(name);
325-
}
326-
}
327-
return domObject;
328-
} else if (renderings.length === 1) {
329-
return renderings[0];
330-
} else {
331-
return { children: renderings };
332-
}
333-
}
334311
/**
335312
* Group the nodes by renderer, siblings and format.
336313
*
337314
* @override
338315
*/
339316
renderBatched(
340317
nodes: VNode[],
341-
rendered?: Renderer<DomObject>,
318+
rendered?: AbstractRenderer<DomObject>,
342319
): [VNode[], Promise<DomObject[]>][] {
343320
const renderingUnits = this._getRenderingUnits(nodes, rendered);
344321
return this._renderBatched(renderingUnits);
@@ -392,13 +369,14 @@ export class DomObjectRenderingEngine extends RenderingEngine<DomObject> {
392369
}
393370
}
394371
// Create format.
395-
const rendering = await this.renderFormat(domObjects, format);
372+
const modifierRenderer = this.getCompatibleModifierRenderer(format, nodes);
373+
const rendering = await modifierRenderer.render(format, domObjects, nodes);
396374
return flatten.map(() => rendering);
397375
});
398376
renderings.push([nodes, unitPromise]);
399377
} else {
400378
// Render each node.
401-
let currentRenderer: Renderer<DomObject>;
379+
let currentRenderer: AbstractRenderer<DomObject>;
402380
let renderingUnit: RenderingBatchUnit;
403381
const siblings: VNode[] = [];
404382
while (
@@ -433,7 +411,7 @@ export class DomObjectRenderingEngine extends RenderingEngine<DomObject> {
433411
*/
434412
private _getRenderingUnits(
435413
nodes: VNode[],
436-
rendered?: Renderer<DomObject>,
414+
rendered?: AbstractRenderer<DomObject>,
437415
): RenderingBatchUnit[] {
438416
// Consecutive char nodes are rendered in same time.
439417
const renderingUnits: RenderingBatchUnit[] = [];
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { AbstractModifierRenderer } from '../../plugin-renderer/src/AbstractModifierRenderer';
2+
import { DomObjectRenderingEngine, DomObject } from './DomObjectRenderingEngine';
3+
import { Format } from '../../core/src/Format';
4+
import { Attributes } from '../../plugin-xml/src/Attributes';
5+
6+
export class FormatDomObjectModifierRenderer extends AbstractModifierRenderer<DomObject> {
7+
static id = DomObjectRenderingEngine.id;
8+
engine: DomObjectRenderingEngine;
9+
predicate = Format;
10+
11+
/**
12+
* Rendering for Format Modifier.
13+
*
14+
* @param format
15+
* @param contents
16+
*/
17+
async render(format: Format, contents: DomObject[]): Promise<DomObject> {
18+
const domObject: DomObject = {
19+
tag: format.htmlTag.toUpperCase(),
20+
attributes: {},
21+
children: contents,
22+
};
23+
const attributes = format.modifiers.find(Attributes);
24+
if (attributes) {
25+
for (const name of attributes.keys()) {
26+
domObject.attributes[name] = attributes.get(name);
27+
}
28+
}
29+
return domObject;
30+
}
31+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { RenderingIdentifier } from './RenderingEngine';
2+
import { RenderingEngine } from './RenderingEngine';
3+
import { Modifier } from '../../core/src/Modifier';
4+
import { ModifierPredicate } from '../../core/src/Modifier';
5+
import { VNode } from '../../core/src/VNodes/VNode';
6+
7+
class SuperModifierRenderer<T> {
8+
constructor(public renderer: AbstractModifierRenderer<T>) {}
9+
/**
10+
* Render the given modifier and wrap the list of DomObject into a
11+
* formating DomObject.
12+
*
13+
* @param modifier
14+
* @param contents
15+
* @param batch
16+
*/
17+
render(modifier: Modifier, contents: T[], batch: VNode[]): Promise<T> {
18+
const nextRenderer = this.renderer.engine.getCompatibleModifierRenderer(
19+
modifier,
20+
batch,
21+
this.renderer,
22+
);
23+
return nextRenderer?.render(modifier, contents, batch);
24+
}
25+
}
26+
27+
export abstract class AbstractModifierRenderer<T> {
28+
static id: RenderingIdentifier;
29+
readonly predicate?: ModifierPredicate;
30+
readonly engine: RenderingEngine<T>;
31+
readonly super: SuperModifierRenderer<T>;
32+
constructor(engine: RenderingEngine<T>) {
33+
this.engine = engine;
34+
this.super = new SuperModifierRenderer(this);
35+
}
36+
/**
37+
* Render the given modifier and wrap the list of DomObject into a
38+
* formating DomObject.
39+
*
40+
* @param modifier
41+
* @param contents
42+
* @param batch
43+
*/
44+
abstract render(modifier: Modifier, renderings: T[], batch: VNode[]): Promise<T>;
45+
}
46+
47+
export interface AbstractModifierRenderer<T = {}> {
48+
constructor: ModifierRendererConstructor<T>;
49+
}
50+
51+
export type ModifierRendererConstructor<T = {}> = {
52+
new (engine: RenderingEngine<T>): AbstractModifierRenderer<T>;
53+
id: RenderingIdentifier;
54+
};

packages/plugin-renderer/src/AbstractRenderer.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import { Renderer, RenderingIdentifier, RendererConstructor } from './RenderingEngine';
1+
import { RenderingIdentifier } from './RenderingEngine';
22
import { RenderingEngine } from './RenderingEngine';
33
import { VNode, Predicate } from '../../core/src/VNodes/VNode';
44
import { flat } from '../../utils/src/utils';
55

6-
class SuperRenderer<T> implements Renderer<T> {
7-
static id = 'super';
8-
super: Renderer<T> = null;
6+
class SuperRenderer<T> {
97
constructor(public renderer: AbstractRenderer<T>) {}
108
/**
119
* Render the given node.
@@ -35,11 +33,11 @@ interface SuperRenderer<T = {}> {
3533
constructor: RendererConstructor<T>;
3634
}
3735

38-
export abstract class AbstractRenderer<T> implements Renderer<T> {
36+
export abstract class AbstractRenderer<T> {
3937
static id: RenderingIdentifier;
4038
readonly predicate?: Predicate;
4139
readonly engine: RenderingEngine<T>;
42-
readonly super: Renderer<T>;
40+
readonly super: SuperRenderer<T>;
4341
constructor(engine: RenderingEngine<T>) {
4442
this.engine = engine;
4543
this.super = new SuperRenderer(this);
@@ -65,3 +63,8 @@ export abstract class AbstractRenderer<T> implements Renderer<T> {
6563
export interface AbstractRenderer<T = {}> {
6664
constructor: RendererConstructor<T>;
6765
}
66+
67+
export type RendererConstructor<T = {}> = {
68+
new (engine: RenderingEngine<T>): AbstractRenderer<T>;
69+
id: RenderingIdentifier;
70+
};

packages/plugin-renderer/src/Renderer.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { JWPluginConfig, JWPlugin } from '../../core/src/JWPlugin';
22
import {
3-
RendererConstructor,
43
RenderingIdentifier,
54
RenderingEngine,
65
RenderingEngineConstructor,
76
} from './RenderingEngine';
87
import { VNode } from '../../core/src/VNodes/VNode';
8+
import { ModifierRendererConstructor } from './AbstractModifierRenderer';
9+
import { RendererConstructor } from './AbstractRenderer';
910

1011
export class Renderer<T extends JWPluginConfig = JWPluginConfig> extends JWPlugin<T> {
1112
loaders = {
@@ -22,8 +23,7 @@ export class Renderer<T extends JWPluginConfig = JWPluginConfig> extends JWPlugi
2223
// The caller might want to fallback on another rendering.
2324
return;
2425
}
25-
engine.renderings.clear();
26-
engine.locations.clear();
26+
engine.clear();
2727
if (nodes instanceof Array) {
2828
return engine.render(nodes);
2929
} else {
@@ -42,8 +42,8 @@ export class Renderer<T extends JWPluginConfig = JWPluginConfig> extends JWPlugi
4242
}
4343
}
4444

45-
loadRenderers(renderers: RendererConstructor[]): void {
46-
renderers = [...renderers].reverse();
45+
loadRenderers(renderers: RendererConstructor[] | ModifierRendererConstructor[]): void {
46+
renderers = [...renderers].reverse() as RendererConstructor[];
4747
for (const RendererClass of renderers) {
4848
for (const id in this.engines) {
4949
const renderingEngine = this.engines[id];

0 commit comments

Comments
 (0)