| @@ -1,106 +1,111 | |||
|
|
1 | 1 | export interface Constructor<T = {}> { |
|
|
2 |
new |
|
|
|
2 | new(...args: any[]): T; | |
|
|
3 | 3 | prototype: T; |
|
|
4 | 4 | } |
|
|
5 | 5 | |
|
|
6 | 6 | export type Factory<T = {}> = (...args: any[]) => T; |
|
|
7 | 7 | |
|
|
8 | 8 | export type Predicate<T = any> = (x: T) => boolean; |
|
|
9 | 9 | |
|
|
10 | 10 | export interface MapOf<T> { |
|
|
11 | 11 | [key: string]: T; |
|
|
12 | 12 | } |
|
|
13 | 13 | |
|
|
14 | 14 | export interface IDestroyable { |
|
|
15 | 15 | destroy(): void; |
|
|
16 | 16 | } |
|
|
17 | 17 | |
|
|
18 | 18 | export interface IRemovable { |
|
|
19 | 19 | remove(): void; |
|
|
20 | 20 | } |
|
|
21 | 21 | |
|
|
22 | 22 | export interface ICancellation { |
|
|
23 | 23 | throwIfRequested(): void; |
|
|
24 | 24 | isRequested(): boolean; |
|
|
25 | 25 | isSupported(): boolean; |
|
|
26 | 26 | register(cb: (e: any) => void): IDestroyable; |
|
|
27 | 27 | } |
|
|
28 | 28 | |
|
|
29 | 29 | /** |
|
|
30 | 30 | * Интерфейс поддерживающий асинхронную активацию |
|
|
31 | 31 | */ |
|
|
32 | 32 | export interface IActivatable { |
|
|
33 | 33 | /** |
|
|
34 | 34 | * @returns Boolean indicates the current state |
|
|
35 | 35 | */ |
|
|
36 | 36 | isActive(): boolean; |
|
|
37 | 37 | |
|
|
38 | 38 | /** |
|
|
39 | 39 | * Starts the component activation |
|
|
40 | 40 | * @param ct cancellation token for this operation |
|
|
41 | 41 | */ |
|
|
42 | 42 | activate(ct?: ICancellation): Promise<void>; |
|
|
43 | 43 | |
|
|
44 | 44 | /** |
|
|
45 | 45 | * Starts the component deactivation |
|
|
46 | 46 | * @param ct cancellation token for this operation |
|
|
47 | 47 | */ |
|
|
48 | 48 | deactivate(ct?: ICancellation): Promise<void>; |
|
|
49 | 49 | |
|
|
50 | 50 | /** |
|
|
51 | 51 | * Sets the activation controller for this component |
|
|
52 | 52 | * @param controller The activation controller |
|
|
53 | 53 | * |
|
|
54 | 54 | * Activation controller checks whether this component |
|
|
55 | 55 | * can be activated and manages the active state of the |
|
|
56 | 56 | * component |
|
|
57 | 57 | */ |
|
|
58 | 58 | setActivationController(controller: IActivationController); |
|
|
59 | 59 | |
|
|
60 | 60 | /** |
|
|
61 | 61 | * Gets the current activation controller for this component |
|
|
62 | 62 | */ |
|
|
63 | 63 | getActivationController(): IActivationController; |
|
|
64 | 64 | } |
|
|
65 | 65 | |
|
|
66 | 66 | export interface IActivationController { |
|
|
67 | 67 | activating(component: IActivatable, ct?: ICancellation): Promise<void>; |
|
|
68 | 68 | |
|
|
69 | 69 | activated(component: IActivatable, ct?: ICancellation): Promise<void>; |
|
|
70 | 70 | |
|
|
71 | 71 | deactivating(component: IActivatable, ct?: ICancellation): Promise<void>; |
|
|
72 | 72 | |
|
|
73 | 73 | deactivated(component: IActivatable, ct?: ICancellation): Promise<void>; |
|
|
74 | 74 | |
|
|
75 | 75 | deactivate(ct?: ICancellation): Promise<void>; |
|
|
76 | 76 | |
|
|
77 | 77 | activate(component: IActivatable, ct?: ICancellation): Promise<void>; |
|
|
78 | 78 | |
|
|
79 | 79 | getActive(): IActivatable; |
|
|
80 | 80 | } |
|
|
81 | 81 | |
|
|
82 | 82 | export interface IAsyncComponent { |
|
|
83 | 83 | getCompletion(): Promise<void>; |
|
|
84 | 84 | } |
|
|
85 | 85 | |
|
|
86 | 86 | export interface ICancellable { |
|
|
87 | 87 | cancel(reason?: any): void; |
|
|
88 | 88 | } |
|
|
89 | 89 | |
|
|
90 | 90 | export interface IObservable<T> { |
|
|
91 | 91 | on(next: (x: T) => void, error?: (e: any) => void, complete?: () => void): IDestroyable; |
|
|
92 | 92 | next(ct?: ICancellation): Promise<T>; |
|
|
93 | 93 | } |
|
|
94 | 94 | |
|
|
95 | 95 | export interface IObserver<T> { |
|
|
96 | 96 | next(event: T): void; |
|
|
97 | 97 | |
|
|
98 | 98 | error(e: any): void; |
|
|
99 | 99 | |
|
|
100 | 100 | complete(): void; |
|
|
101 | 101 | } |
|
|
102 | 102 | |
|
|
103 | 103 | export interface TextWriter { |
|
|
104 | formatter; | |
|
|
105 |
Write( |
|
|
|
104 | Write(obj: any): void; | |
|
|
105 | Write(format: string, ...args: any[]): void; | |
|
|
106 | ||
|
|
107 | WriteLine(obj: any): void; | |
|
|
108 | WriteLine(format: string, ...args: any[]): void; | |
|
|
109 | ||
|
|
110 | WriteValue(value: any, spec?: string): void; | |
|
|
106 | 111 | } |
| @@ -1,65 +1,101 | |||
|
|
1 | 1 | import { FormatScanner, TokeType } from "./FormatScanner"; |
|
|
2 | import { isNullOrEmptyString } from "../safe"; | |
|
|
3 | import { TextWriter } from "../interfaces"; | |
|
|
2 | 4 | |
|
|
3 | 5 | export class FormatCompiler { |
|
|
6 | _scanner: FormatScanner; | |
|
|
4 | 7 | |
|
|
5 | visitText(scanner: FormatScanner) { | |
|
|
6 | while (scanner.next()) { | |
|
|
7 | if (scanner.getTokenType() === TokeType.CurlOpen) | |
|
|
8 | this.visitCurlOpen(scanner); | |
|
|
8 | _parts: []; | |
|
|
9 | ||
|
|
10 | compile() { | |
|
|
11 | return (writer: TextWriter, args: any) => { | |
|
|
12 | this._parts.forEach(x => writer.WriteValue(x)) | |
|
|
13 | }; | |
|
|
14 | } | |
|
|
15 | ||
|
|
16 | visitText() { | |
|
|
17 | while (this._scanner.next()) { | |
|
|
18 | switch (this._scanner.getTokenType()) { | |
|
|
19 | case TokeType.CurlOpen: | |
|
|
20 | this.visitCurlOpen(); | |
|
|
21 | break; | |
|
|
22 | case TokeType.CurlClose: | |
|
|
23 | this.visitCurlClose(); | |
|
|
24 | break; | |
|
|
25 | default: | |
|
|
26 | this.pushText(this._scanner.getTokenValue()); | |
|
|
27 | } | |
|
|
28 | if (this._scanner.getTokenType() === TokeType.CurlOpen) | |
|
|
29 | this.visitCurlOpen(); | |
|
|
9 | 30 | } |
|
|
10 | 31 | } |
|
|
11 | 32 | |
|
|
12 | visitCurlOpen(scanner: FormatScanner) { | |
|
|
13 |
if (scanner.next()) |
|
|
|
14 | if (scanner.getTokenType() === TokeType.CurlOpen) | |
|
|
33 | visitCurlClose() { | |
|
|
34 | if (!this._scanner.next()) | |
|
|
35 | this.dieUnexpectedEnd("}"); | |
|
|
36 | if (this._scanner.getTokenType() !== TokeType.CurlClose) | |
|
|
37 | this.dieUnexpectedToken("}"); | |
|
|
38 | this.pushText("}"); | |
|
|
39 | } | |
|
|
40 | ||
|
|
41 | visitCurlOpen() { | |
|
|
42 | if (this._scanner.next()) { | |
|
|
43 | if (this._scanner.getTokenType() === TokeType.CurlOpen) | |
|
|
15 | 44 | this.pushText("{"); |
|
|
16 | 45 | else |
|
|
17 |
this.visitTemplateSubst( |
|
|
|
18 | ||
|
|
46 | this.visitTemplateSubst(); | |
|
|
19 | 47 | } |
|
|
20 | 48 | } |
|
|
21 | 49 | |
|
|
22 |
visitTemplateSubst( |
|
|
|
23 | if (scanner.getTokenType() !== TokeType.Text) | |
|
|
24 |
this.dieUnexpectedToken( |
|
|
|
50 | visitTemplateSubst() { | |
|
|
51 | if (this._scanner.getTokenType() !== TokeType.Text) | |
|
|
52 | this.dieUnexpectedToken("TEXT"); | |
|
|
25 | 53 | |
|
|
26 | const fieldName = scanner.getTokenValue(); | |
|
|
27 | let filedFormat: string; | |
|
|
28 | if (this.readColon(scanner)) { | |
|
|
29 | filedFormat = this.readFieldFormat(scanner); | |
|
|
30 | } else { | |
|
|
31 | if (scanner.getTokenType() !== TokeType.CurlClose) | |
|
|
32 | this.dieUnexpectedToken(scanner); | |
|
|
33 | } | |
|
|
54 | const fieldName = this._scanner.getTokenValue(); | |
|
|
55 | const filedFormat = this.readColon() && this.readFieldFormat(); | |
|
|
34 | 56 | |
|
|
35 | 57 | this.pushSubst(fieldName, filedFormat); |
|
|
36 | 58 | } |
|
|
37 | 59 | |
|
|
38 | pushSubst(fieldName: string, filedFormat: string) { | |
|
|
39 | throw new Error("Method not implemented."); | |
|
|
60 | readFieldFormat() { | |
|
|
61 | const parts = new Array<string>(); | |
|
|
62 | while (this._scanner.next()) { | |
|
|
63 | if (this._scanner.getTokenType() === TokeType.CurlClose) { | |
|
|
64 | return parts.join(""); | |
|
|
65 | } else { | |
|
|
66 | parts.push(this._scanner.getTokenValue()); | |
|
|
67 | } | |
|
|
68 | } | |
|
|
69 | ||
|
|
70 | this.dieUnexpectedEnd("}"); | |
|
|
40 | 71 | } |
|
|
41 | 72 | |
|
|
42 | readFieldFormat(scanner: FormatScanner): string { | |
|
|
43 | throw new Error("Method not implemented."); | |
|
|
73 | readColon() { | |
|
|
74 | if (!this._scanner.next()) | |
|
|
75 | this.dieUnexpectedEnd(); | |
|
|
76 | if (this._scanner.getTokenType() !== TokeType.Colon) | |
|
|
77 | return false; | |
|
|
78 | if (!this._scanner.next()) | |
|
|
79 | this.dieUnexpectedEnd(); | |
|
|
80 | return true; | |
|
|
44 | 81 | } |
|
|
45 | 82 | |
|
|
46 | readColon(scanner: FormatScanner) { | |
|
|
47 | if (!scanner.next()) | |
|
|
48 | this.dieUnexpectedEnd(); | |
|
|
49 | if (scanner.getTokenType() !== TokeType.Colon) | |
|
|
50 | return false; | |
|
|
83 | pushSubst(fieldName: string, filedFormat: string) { | |
|
|
51 | 84 | |
|
|
52 | 85 | } |
|
|
53 | 86 | |
|
|
54 | 87 | pushText(text: string) { |
|
|
55 | 88 | |
|
|
56 | 89 | } |
|
|
57 | 90 | |
|
|
58 |
dieUnexpectedToken( |
|
|
|
59 | throw new Error(`Unexpected token ${scanner.getTokenValue()}`); | |
|
|
91 | dieUnexpectedToken(expected?: string) { | |
|
|
92 | throw new Error(isNullOrEmptyString(expected) ? | |
|
|
93 | `Unexpected token ${this._scanner.getTokenValue()}` : | |
|
|
94 | `Unexpected token ${this._scanner.getTokenValue()}, expected ${expected}` | |
|
|
95 | ); | |
|
|
60 | 96 | } |
|
|
61 | 97 | |
|
|
62 | dieUnexpectedEnd() { | |
|
|
63 | throw new Error("Unexpected end of string"); | |
|
|
98 | dieUnexpectedEnd(expected?: string) { | |
|
|
99 | throw new Error(isNullOrEmptyString(expected) ? "Unexpected end of the string" : `Unexpected end of the string, expected ${expected}`); | |
|
|
64 | 100 | } |
|
|
65 | 101 | } |
| @@ -1,18 +1,18 | |||
|
|
1 | 1 | export class StringBuilder { |
|
|
2 | 2 | private _data: string[]; |
|
|
3 | 3 | private _newLine = "\n"; |
|
|
4 | 4 | |
|
|
5 | 5 | Write(obj: any); |
|
|
6 | 6 | Write(format: string, ...args: any[]) { |
|
|
7 | 7 | |
|
|
8 | 8 | } |
|
|
9 | 9 | |
|
|
10 | 10 | WriteLine(obj: any); |
|
|
11 | 11 | WriteLine(format: string, ...args: any[]) { |
|
|
12 | ||
|
|
12 | ||
|
|
13 | 13 | } |
|
|
14 | 14 | |
|
|
15 | 15 | WriteValue(value: any, spec?: string) { |
|
|
16 | 16 | |
|
|
17 | 17 | } |
|
|
18 | 18 | } |
General Comments 0
You need to be logged in to leave comments.
Login now
