-
Notifications
You must be signed in to change notification settings - Fork 0
/
test2.ts
291 lines (207 loc) · 11.4 KB
/
test2.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
//-----------------------------------------------------------------------------------------------
import 'ts-mixin';
import * as ReadinessDesign from './readiness-design';
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// ++ Base Interactor Object Definitions
//-----------------------------------------------------------------------------------------------
class ReferenceItem { public id: string; }
abstract class StandardInteractor {
private _MyPage: ReferenceItem;
public get MyPage(): ReferenceItem { return this._MyPage; }
constructor(item: ReferenceItem) { this._MyPage = item; }
SomeBaseMethod() { return 'test0'; }
}
class AbstractInteractor extends StandardInteractor {
SomeGenericMethod() { return 'test1'; }
}
class TabbedInteractor extends AbstractInteractor {
SomeSpecificMethod() { return 'test2'; }
}
class SpecialTabbedInteractor extends TabbedInteractor {
SomeVerySpecificMethod() { return 'test3'; }
}
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// ++ Base XML Script Page Definitions
//-----------------------------------------------------------------------------------------------
interface IScriptPage {
ManuScriptTopic: string;
ManuScriptPageName: string;
CreateAsync(page: ReferenceItem): Promise<ScriptPageBase>;
}
//@WestWorld.usesAbstractImplementsOf(InterfacesContainer, 'IScriptPage')
class ScriptPageBase {
public ManuScript: string;
public MyItem: ReferenceItem;
constructor(item: ReferenceItem, script: string) {
this.MyItem = item;
this.ManuScript = script;
}
protected static async CreateAsyncBase(item: ReferenceItem, ManuScriptPage: IScriptPage): Promise<ScriptPageBase> {
let xml = 'some xml' //some call that gets XML data using the IScriptPage properties
return new ScriptPageBase(item, xml);
}
}
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// ++ XML Parsing Logic
//-----------------------------------------------------------------------------------------------
class xmlTranslator {
public static async GetSingleSerializedNode<T>(item: ReferenceItem, xmlDocHTML: string, query: string, type: (new () => T)): Promise<T> {
//Some XML parsing Logic
return new type();
}
}
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// ++ XML ManuScript Page Query Handling
//-----------------------------------------------------------------------------------------------
/** An interface that allows an IScriptPage implementation to perform XML related queries
* against it's cached page
*/
interface IQueryablePage {
GetSingleNode<T>(query: string, type: new () => T): Promise<T>;
}
/** A static class that handles the methods defined in IQueryablePage */
class PageQueries {
public static async GetSingleNode<T, MS extends ScriptPageBase>(item: ReferenceItem, script: MS, query: string, type: new () => T): Promise<T> {
return await xmlTranslator.GetSingleSerializedNode(item, script.ManuScript, query, type);
}
}
interface IManuScriptPageWrapper<T extends ScriptPageBase> {
IsManuScriptLoaded: boolean;
/** Returns the defined ManuScript Page associated with this tab */
GetManuScriptPage(reload?: boolean): Promise<T>
}
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// ++ Custom Mixin Decorator Handling for Interactor Inheritance
//-----------------------------------------------------------------------------------------------
const __ = <never>null;
type _ = typeof __;
/** Extending from this class allows the 'InheritInteractor' class decorator to be
* used, to mixin a ManuScript implementation along with an Interactor class
*/
abstract class BoilerPlateCtor {
/**
* @param item Reference to the Page in use
* @param manuScriptFactory The static IScriptPage class that can create a new instance
* of the defined generic ScriptPageBase Type
*/
constructor(item: ReferenceItem, manuScriptFactory: IScriptPage) {}
}
interface IManuScriptPageBoilerPlateInterface { __ReferenceItem: ReferenceItem; _ManuScriptFactory: IScriptPage; }
type PageImplementation<T extends StandardInteractor> = PageImplementationCtor & T;
interface PageImplementationCtor { new (item: ReferenceItem, manuScriptFactory: IScriptPage); }
/** A class decorator that will perform the boilerplate constructor logic to mixin a ManuScript
* implementation along with an Interactor class. Enforces that the decorated class' contract
* implements the StandardInteractor inheritance.
*/
const InheritInteractor = <T extends StandardInteractor>(type: new (item: ReferenceItem) => T) => {
return (<U extends T>(orig: new (item: ReferenceItem, manuScriptFactory: IScriptPage) => BoilerPlateCtor & U) => {
return class extends (type as new (item: ReferenceItem) => any) implements IManuScriptPageBoilerPlateInterface {
__ReferenceItem: ReferenceItem;
_ManuScriptFactory: IScriptPage;
constructor(item: ReferenceItem, manuScriptFactory: IScriptPage) {
super(item);
this.__ReferenceItem = item;
this._ManuScriptFactory = manuScriptFactory;
}
} as PageImplementation<T>;
});
};
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// ++ Base ManuScript Page Mapping Wrapper w/ Readiness Design Pattern
//-----------------------------------------------------------------------------------------------
/** Public Interface for IManuScriptPageMapping mixin */
interface ManuScriptPageMapping<T extends ScriptPageBase> extends IManuScriptPageWrapper<T>, IQueryablePage {}
abstract class IManuScriptPageMapping<T extends ScriptPageBase>
implements IManuScriptPageWrapper<T>, IQueryablePage, IManuScriptPageBoilerPlateInterface {
private _ManuScriptPage: T;
public _ManuScriptFactory: IScriptPage;
public __ReferenceItem: ReferenceItem;
public IsManuScriptLoaded: boolean = false;
constructor(item: ReferenceItem, manuScriptFactory: IScriptPage) {
this.__ReferenceItem = item;
this._ManuScriptFactory = manuScriptFactory;
}
public get MyPage(): ReferenceItem {
return this.__ReferenceItem;
}
@ReadinessDesign.init //(Readiness Design Pattern Decorator)
protected async LoadManuScript(): Promise<void> {
this._ManuScriptPage = (await this._ManuScriptFactory.CreateAsync(this.MyPage)) as T;
this.IsManuScriptLoaded = true;
}
@ReadinessDesign.waitOnInit //(Readiness Design Pattern Decorator)
public async GetManuScriptPage(reload: boolean = false): Promise<T> {
if (reload) { await this.LoadManuScript(); }
return this._ManuScriptPage;
}
@ReadinessDesign.waitOnInit //(Readiness Design Pattern Decorator)
public async GetSingleNode<T>(query: string, type: new () => T): Promise<T> {
return await PageQueries.GetSingleNode(this.MyPage, this._ManuScriptPage, query, type);
}
}
/** Abstract IManuScriptPageMapping constructor -> base constructor */
const _IManuScriptPageMapping_ = <unknown>IManuScriptPageMapping as new (...args) => ManuScriptPageMapping<_>;
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// ++ Types of ManuScript Page Wrappers for different Page Abstractions
//-----------------------------------------------------------------------------------------------
@Mixins.tmixin(_IManuScriptPageMapping_)
@InheritInteractor(TabbedInteractor)
export class TabbedManuScriptPageInteractor<T extends ScriptPageBase> extends BoilerPlateCtor {}
export interface TabbedManuScriptPageInteractor<T extends ScriptPageBase> extends ManuScriptPageMapping<T>, TabbedInteractor {}
@Mixins.tmixin(_IManuScriptPageMapping_)
@InheritInteractor(SpecialTabbedInteractor)
export class SpecialTabbedManuScriptPageInteractor<T extends ScriptPageBase> extends BoilerPlateCtor {}
export interface SpecialTabbedManuScriptPageInteractor<T extends ScriptPageBase> extends ManuScriptPageMapping<T>, SpecialTabbedInteractor {}
@Mixins.tmixin(_IManuScriptPageMapping_)
@InheritInteractor(AbstractInteractor)
export class AbstractManuScriptPageInteractor<T extends ScriptPageBase> extends BoilerPlateCtor {}
export interface AbstractManuScriptPageInteractor<T extends ScriptPageBase> extends ManuScriptPageMapping<T>, AbstractInteractor {}
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// ++ Types of ManuScript Page Implementations
//-----------------------------------------------------------------------------------------------
//@WestWorld.staticImplements<IScriptPage>(IScriptPage)
export class MsPageSomethingSpecific extends ScriptPageBase {
public static ManuScriptTopic: string = 'someConst';
public static ManuScriptPageName: string = 'someConst';
constructor(item: ScriptPageBase) {
super(item.MyItem, item.ManuScript);
}
public static async CreateAsync(item: ReferenceItem): Promise<MsPageSomethingSpecific> {
return new this(await this.CreateAsyncBase(item, this))
}
public async GetSomeValue(someArg): Promise<string> {
return 'someValue';
}
}
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// ++ Types of Mixed Page/Interactor Implementations
//-----------------------------------------------------------------------------------------------
export class SomeSpecificPageInteractor extends SpecialTabbedManuScriptPageInteractor<MsPageSomethingSpecific> {
constructor(item: ReferenceItem) {
super(item, MsPageSomethingSpecific);
}
}
//-----------------------------------------------------------------------------------------------
class SomeXmlStruct { someProp: string = 'someDefaultValue'; }
const Test = async () => {
const item = { id: 'someId' } as ReferenceItem;
const interactor = new SomeSpecificPageInteractor(item);
console.log(interactor.MyPage); // { id: 'someId' }
console.log(interactor.SomeVerySpecificMethod()); // test3
console.log(interactor.SomeGenericMethod()); // test1
console.log(interactor.IsManuScriptLoaded); // undefined
console.log(await interactor.GetSingleNode('some xpath query', SomeXmlStruct)); // SomeXmlStruct { someProp: 'someDefaultValue' }
console.log(interactor.IsManuScriptLoaded); // true
const script = await interactor.GetManuScriptPage();
console.log(await script.GetSomeValue('someArg')); // someValue
};
Test();