##// END OF EJS Templates
ported string format traits to typescript
cin -
r55:4eaaaa5c1cf3 di-typescript
parent child
Show More
@@ -0,0 +1,8
1 import * as module from "module";
2 import { TraceSource } from "../log/TraceSource";
3
4 const logger = TraceSource.get(module.id);
5
6 logger.warn("The module is deprecated, use StringFormat.compile() method directly");
7
8 export { compile } from "./StringFormat";
@@ -0,0 +1,47
1 import { format as dojoFormatNumber } from "dojo/number";
2 import { format as dojoFormatDate } from "dojo/date/locale";
3 import { Formatter } from "./StringFormat";
4
5 import { isNumber } from "../safe";
6
7 interface NumberFormatOptions {
8 round?: number;
9 pattern?: string;
10 }
11
12 function convertNumber(value: any, pattern: string) {
13 if (isNumber(value)) {
14 const nopt = {} as NumberFormatOptions;
15 if (pattern.indexOf("!") === 0) {
16 nopt.round = -1;
17 pattern = pattern.substr(1);
18 }
19 nopt.pattern = pattern;
20
21 return dojoFormatNumber(value, nopt);
22 }
23 }
24
25 function convertDate(value: any, pattern: string) {
26 if (value instanceof Date) {
27 const m = pattern.match(/^(\w+)-(\w+)$/);
28 if (m)
29 return dojoFormatDate(value, {
30 selector: m[2],
31 formatLength: m[1]
32 });
33 else if (pattern === "iso")
34 return value.toISOString();
35 else
36 return dojoFormatDate(value, {
37 selector: "date",
38 datePattern: pattern
39 });
40 }
41 }
42
43 const _formatter = new Formatter([convertNumber, convertDate]);
44
45 export = function format(msg: string, ...args: any[]) {
46 return _formatter.format.apply(msg, ...args);
47 };
@@ -0,0 +1,173
1 import { isPrimitive, isNull, each } from "../safe";
2 import { MapOf } from "../interfaces";
3
4 type SubstFn = (name: string, format?: string) => string;
5 type TemplateFn = (subst: SubstFn) => string;
6 type ConvertFn = (value: any, format?: string) => string;
7
8 const map = {
9 "\\{": "&curlopen;",
10 "\\}": "&curlclose;",
11 "&": "&",
12 "\\:": ":"
13 };
14
15 const rev = {
16 curlopen: "{",
17 curlclose: "}",
18 amp: "&",
19 colon: ":"
20 };
21
22 function espaceString(s: string) {
23 if (!s)
24 return s;
25 return "'" + s.replace(/('|\\)/g, "\\$1").replace("\n", "\\n") + "'";
26 }
27
28 function encode(s: string) {
29 if (!s)
30 return s;
31 return s.replace(/\\{|\\}|&|\\:|\n/g, m => map[m] || m);
32 }
33
34 function decode(s: string) {
35 if (!s)
36 return s;
37 return s.replace(/&(\w+);/g, (m, $1) => rev[$1] || m);
38 }
39
40 function subst(s: string) {
41 const i = s.indexOf(":");
42 let name: string;
43 let pattern: string;
44 if (i >= 0) {
45 name = s.substr(0, i);
46 pattern = s.substr(i + 1);
47 } else {
48 name = s;
49 }
50
51 if (pattern)
52 return [
53 espaceString(decode(name)),
54 espaceString(decode(pattern))];
55 else
56 return [espaceString(decode(name))];
57 }
58
59 function _compile(str: string) {
60 if (!str)
61 return () => void 0;
62
63 const chunks = encode(str).split("{");
64 let chunk: string;
65
66 const code = ["var result=[];"];
67
68 for (let i = 0; i < chunks.length; i++) {
69 chunk = chunks[i];
70
71 if (i === 0) {
72 if (chunk)
73 code.push("result.push(" + espaceString(decode(chunk)) +
74 ");");
75 } else {
76 const len = chunk.indexOf("}");
77 if (len < 0)
78 throw new Error("Unbalanced substitution #" + i);
79
80 code.push("result.push(subst(" +
81 subst(chunk.substr(0, len)).join(",") + "));");
82 if (chunk.length > len + 1)
83 code.push("result.push(" +
84 espaceString(decode(chunk.substr(len + 1))) + ");");
85 }
86 }
87
88 code.push("return result.join('');");
89
90 // the code for this function is generated from the template
91 // tslint:disable-next-line:function-constructor
92 return new Function("subst", code.join("\n")) as TemplateFn;
93 }
94
95 const cache: MapOf<TemplateFn> = {};
96
97 export function compile(template: string) {
98 let compiled = cache[template];
99 if (!compiled) {
100 compiled = _compile(template);
101 cache[template] = compiled;
102 }
103 return compiled;
104 }
105
106 function defaultConverter(value: any, pattern: string) {
107 if (pattern && pattern.toLocaleLowerCase() === "json") {
108 const seen = [];
109 return JSON.stringify(value, (k, v) => {
110 if (!isPrimitive(v)) {
111 const id = seen.indexOf(v);
112 if (id >= 0)
113 return "@ref-" + id;
114 else {
115 seen.push(v);
116 return v;
117 }
118 } else {
119 return v;
120 }
121 }, 2);
122 } else if (isNull(value)) {
123 return "";
124 } else if (value instanceof Date) {
125 return value.toISOString();
126 } else {
127 return pattern ? value.toString(pattern) : value.toString();
128 }
129 }
130
131 export class Formatter {
132 _converters: ConvertFn[];
133
134 constructor(converters?: ConvertFn[]) {
135 this._converters = converters || [];
136 this._converters.push(defaultConverter);
137 }
138
139 convert(value: any, pattern: string) {
140 for (const c of this._converters) {
141 const res = c(value, pattern);
142 if (!isNull(res))
143 return res;
144 }
145 return "";
146 }
147
148 format(msg: string, ...args: any[]) {
149 const template = compile(msg);
150
151 return template((name, pattern) => {
152 const value = args[name];
153 return !isNull(value) ? this.convert(value, pattern) : "";
154 });
155
156 }
157
158 compile(msg: string) {
159 const template = compile(msg);
160 return (...args: any[]) => {
161 return template((name, pattern) => {
162 const value = args[name];
163 return !isNull(value) ? this.convert(value, pattern) : "";
164 });
165 };
166 }
167 }
168
169 const _default = new Formatter();
170
171 export function format(msg: string, ...args: any[]) {
172 return _default.format(msg, ...args);
173 }
@@ -1,80 +1,84
1 1 export type Constructor<T = {}> = new (...args: any[]) => T;
2 2
3 3 export type Factory<T = {}> = (...args: any[]) => T;
4 4
5 export interface MapOf<T> {
6 [key: string]: T;
7 }
8
5 9 export interface IDestroyable {
6 10 destroy();
7 11 }
8 12
9 13 export interface ICancellation {
10 14 throwIfRequested(): void;
11 15 isRequested(): boolean;
12 16 isSupported(): boolean;
13 17 register(cb: (e: any) => void): IDestroyable;
14 18 }
15 19
16 20 /**
17 21 * Интерфейс поддерживающий асинхронную активацию
18 22 */
19 23 export interface IActivatable {
20 24 /**
21 25 * @returns Boolean indicates the current state
22 26 */
23 27 isActive(): boolean;
24 28
25 29 /**
26 30 * Starts the component activation
27 31 * @param ct cancellation token for this operation
28 32 */
29 33 activate(ct?: ICancellation): Promise<void>;
30 34
31 35 /**
32 36 * Starts the component deactivation
33 37 * @param ct cancellation token for this operation
34 38 */
35 39 deactivate(ct?: ICancellation): Promise<void>;
36 40
37 41 /**
38 42 * Sets the activation controller for this component
39 43 * @param controller The activation controller
40 44 *
41 45 * Activation controller checks whether this component
42 46 * can be activated and manages the active state of the
43 47 * component
44 48 */
45 49 setActivationController(controller: IActivationController);
46 50
47 51 /**
48 52 * Gets the current activation controller for this component
49 53 */
50 54 getActivationController(): IActivationController;
51 55 }
52 56
53 57 export interface IActivationController {
54 58 activating(component: IActivatable, ct?: ICancellation): Promise<void>;
55 59
56 60 activated(component: IActivatable, ct?: ICancellation): Promise<void>;
57 61
58 62 deactivating(component: IActivatable, ct?: ICancellation): Promise<void>;
59 63
60 64 deactivated(component: IActivatable, ct?: ICancellation): Promise<void>;
61 65
62 66 deactivate(ct?: ICancellation): Promise<void>;
63 67
64 68 activate(component: IActivatable, ct?: ICancellation): Promise<void>;
65 69
66 70 getActive(): IActivatable;
67 71 }
68 72
69 73 export interface IAsyncComponent {
70 74 getCompletion(): Promise<void>;
71 75 }
72 76
73 77 export interface ICancellable {
74 78 cancel(reason?: any): void;
75 79 }
76 80
77 81 export interface IObservable<T> {
78 82 on(next: (x: T) => void, error?: (e: any) => void, complete?: () => void): IDestroyable;
79 83 next(ct?: ICancellation): Promise<T>;
80 84 }
@@ -1,128 +1,128
1 1 import { Observable } from "../Observable";
2 2 import { Registry } from "./Registry";
3 import { format } from "../text/FormatString";
3 import { format } from "../text/StringFormat";
4 4
5 5 export const DebugLevel = 400;
6 6
7 7 export const LogLevel = 300;
8 8
9 9 export const WarnLevel = 200;
10 10
11 11 export const ErrorLevel = 100;
12 12
13 13 export const SilentLevel = 0;
14 14
15 15 export interface TraceEvent {
16 16 readonly source: TraceSource;
17 17
18 18 readonly level: number;
19 19
20 20 readonly arg: any;
21 21 }
22 22
23 23 export class TraceSource {
24 24 readonly id: any;
25 25
26 26 level: number;
27 27
28 28 readonly events: Observable<TraceEvent>;
29 29
30 30 _notifyNext: (arg: TraceEvent) => void;
31 31
32 32 constructor(id: any) {
33 33
34 34 this.id = id || new Object();
35 35 this.events = new Observable(next => {
36 36 this._notifyNext = next;
37 37 });
38 38 }
39 39
40 40 protected emit(level: number, arg: any) {
41 this._notifyNext({ source: this, level, arg});
41 this._notifyNext({ source: this, level, arg });
42 42 }
43 43
44 44 isDebugEnabled() {
45 45 return this.level >= DebugLevel;
46 46 }
47 47
48 48 debug(msg: string, ...args: any[]) {
49 49 if (this.isEnabled(DebugLevel))
50 50 this.emit(DebugLevel, format(msg, args));
51 51 }
52 52
53 53 isLogEnabled() {
54 54 return this.level >= LogLevel;
55 55 }
56 56
57 57 log(msg: string, ...args: any[]) {
58 58 if (this.isEnabled(LogLevel))
59 59 this.emit(LogLevel, format(msg, args));
60 60 }
61 61
62 62 isWarnEnabled() {
63 63 return this.level >= WarnLevel;
64 64 }
65 65
66 66 warn(msg: string, ...args: any[]) {
67 67 if (this.isEnabled(WarnLevel))
68 68 this.emit(WarnLevel, format(msg, args));
69 69 }
70 70
71 71 /**
72 72 * returns true if errors will be recorded.
73 73 */
74 74 isErrorEnabled() {
75 75 return this.level >= ErrorLevel;
76 76 }
77 77
78 78 /**
79 79 * Traces a error.
80 80 *
81 81 * @param msg the message.
82 82 * @param args parameters which will be substituted in the message.
83 83 */
84 84 error(msg: string, ...args: any[]) {
85 85 if (this.isEnabled(ErrorLevel))
86 86 this.emit(ErrorLevel, format.apply(null, arguments));
87 87 }
88 88
89 89 /**
90 90 * Checks whether the specified level is enabled for this
91 91 * trace source.
92 92 *
93 93 * @param level the trace level which should be checked.
94 94 */
95 95 isEnabled(level: number) {
96 96 return (this.level >= level);
97 97 }
98 98
99 99 /**
100 100 * Traces a raw event, passing data as it is to the underlying listeners
101 101 *
102 102 * @param level the level of the event
103 103 * @param arg the data of the event, can be a simple string or any object.
104 104 */
105 105 traceEvent(level: number, arg: any) {
106 106 if (this.isEnabled(level))
107 107 this.emit(level, arg);
108 108 }
109 109
110 110 /**
111 111 * Register the specified handler to be called for every new and already
112 112 * created trace source.
113 113 *
114 114 * @param handler the handler which will be called for each trace source
115 115 */
116 116 static on(handler: (source: TraceSource) => void) {
117 117 return Registry.instance.on(handler);
118 118 }
119 119
120 120 /**
121 121 * Creates or returns already created trace source for the specified id.
122 122 *
123 123 * @param id the id for the trace source
124 124 */
125 125 static get(id: any) {
126 126 return Registry.instance.get(id);
127 127 }
128 128 }
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now