##// END OF EJS Templates
text/format refactoring
cin -
r54:2fd5aee49888 di-typescript
parent child
Show More
@@ -0,0 +1,40
1 import { format as dojoFormatNumber } from "dojo/number";
2 import { format as dojoFormatDate } from "dojo/date/locale";
3
4 import { isNumber } from "./safe";
5
6 interface NumberFormatOptions {
7 round?: number;
8 pattern?: string;
9 }
10
11 function formatNumber(value: any, pattern: string) {
12 if (isNumber(value)) {
13 const nopt = {} as NumberFormatOptions;
14 if (pattern.indexOf("!") === 0) {
15 nopt.round = -1;
16 pattern = pattern.substr(1);
17 }
18 nopt.pattern = pattern;
19
20 return dojoFormatNumber(value, nopt);
21 }
22 }
23
24 function formatDate(value: any, pattern: string) {
25 if (value instanceof Date) {
26 const m = pattern.match(/^(\w+)-(\w+)$/);
27 if (m)
28 return dojoFormatDate(value, {
29 selector: m[2],
30 formatLength: m[1]
31 });
32 else if (pattern === "iso")
33 return value.toISOString();
34 else
35 return dojoFormatDate(value, {
36 selector: "date",
37 datePattern: pattern
38 });
39 }
40 }
@@ -0,0 +1,160
1 import { isPrimitive, isNumber, isNull } from "../safe";
2
3 type SubstFn = (name: string, format?: string) => string;
4 type FormatFn = (subst: SubstFn) => string;
5 type ConvertFn = (value: any, format?: string) => string;
6
7 const map = {
8 "\\{": "&curlopen;",
9 "\\}": "&curlclose;",
10 "&": "&",
11 "\\:": ":"
12 };
13
14 const rev = {
15 curlopen: "{",
16 curlclose: "}",
17 amp: "&",
18 colon: ":"
19 };
20
21 function espaceString(s: string) {
22 if (!s)
23 return s;
24 return "'" + s.replace(/('|\\)/g, "\\$1").replace("\n", "\\n") + "'";
25 }
26
27 function encode(s: string) {
28 if (!s)
29 return s;
30 return s.replace(/\\{|\\}|&|\\:|\n/g, m => map[m] || m);
31 }
32
33 function decode(s: string) {
34 if (!s)
35 return s;
36 return s.replace(/&(\w+);/g, (m, $1) => rev[$1] || m);
37 }
38
39 function subst(s: string) {
40 const i = s.indexOf(":");
41 let name: string;
42 let pattern: string;
43 if (i >= 0) {
44 name = s.substr(0, i);
45 pattern = s.substr(i + 1);
46 } else {
47 name = s;
48 }
49
50 if (pattern)
51 return [
52 espaceString(decode(name)),
53 espaceString(decode(pattern))];
54 else
55 return [espaceString(decode(name))];
56 }
57
58 function _compile(str: string) {
59 if (!str)
60 return () => void 0;
61
62 const chunks = encode(str).split("{");
63 let chunk: string;
64
65 const code = ["var result=[];"];
66
67 for (let i = 0; i < chunks.length; i++) {
68 chunk = chunks[i];
69
70 if (i === 0) {
71 if (chunk)
72 code.push("result.push(" + espaceString(decode(chunk)) +
73 ");");
74 } else {
75 const len = chunk.indexOf("}");
76 if (len < 0)
77 throw new Error("Unbalanced substitution #" + i);
78
79 code.push("result.push(subst(" +
80 subst(chunk.substr(0, len)).join(",") + "));");
81 if (chunk.length > len + 1)
82 code.push("result.push(" +
83 espaceString(decode(chunk.substr(len + 1))) + ");");
84 }
85 }
86
87 code.push("return result.join('');");
88
89 // the code for this function is generated from the template
90 // tslint:disable-next-line:function-constructor
91 return new Function("subst", code.join("\n")) as FormatFn;
92 }
93
94 const cache = {} as {
95 [i: string]: FormatFn
96 };
97
98 export function compile(template: string) {
99 let compiled = cache[template];
100 if (!compiled) {
101 compiled = _compile(template);
102 cache[template] = compiled;
103 }
104 return compiled;
105 }
106
107 function convert(value: any, pattern) {
108 if (!pattern)
109 return value.toString();
110
111 if (pattern.toLocaleLowerCase() === "json") {
112 const seen = [];
113 return JSON.stringify(value, (k, v) => {
114 if (!isPrimitive(v)) {
115 const id = seen.indexOf(v);
116 if (id >= 0)
117 return "@ref-" + id;
118 else {
119 seen.push(v);
120 return v;
121 }
122 } else {
123 return v;
124 }
125 }, 2);
126 }
127
128 defaultFormatter(value, pattern);
129 }
130
131 function defaultFormatter(value: any, pattern: string) {
132 if (value instanceof Date) {
133 return value.toISOString();
134 } else {
135 return value.toString(pattern);
136 }
137 }
138
139 export function format(fmt: string, ...args: any[]) {
140 if (args.length === 0)
141 return fmt;
142
143 const template = compile(fmt);
144
145 return template((name, pattern) => {
146 const value = args[name];
147 return !isNull(value) ? convert(value, pattern) : "";
148 });
149 }
150
151 export function compileFormat(fmt: string) {
152 const template = compile(fmt);
153
154 return (...args: any[]) => {
155 return template((name, pattern) => {
156 const value = args[name];
157 return !isNull(value) ? convert(value, pattern) : "";
158 });
159 };
160 }
@@ -1,40 +1,40
1 1 import { Cancellation } from "../Cancellation";
2 2 import { IAsyncComponent, ICancellation, ICancellable, IDestroyable } from "../interfaces";
3 3 import { destroy } from "../safe";
4 4
5 5 export class AsyncComponent implements IAsyncComponent, ICancellable {
6 6 _cancel: (e) => void;
7 7
8 8 _completion: Promise<void> = Promise.resolve();
9 9
10 getCompletion() { return this._completion };
10 getCompletion() { return this._completion; }
11 11
12 12 runOperation(op: (ct: ICancellation) => any, ct: ICancellation = Cancellation.none) {
13 13 // create inner cancellation bound to the passed cancellation token
14 14 let h: IDestroyable;
15 let inner = new Cancellation(cancel => {
15 const inner = new Cancellation(cancel => {
16 16
17 17 this._cancel = cancel;
18 18 h = ct.register(cancel);
19 19 });
20 20
21 21 // TODO create cancellation source here
22 let guard = async () => {
22 const guard = async () => {
23 23 try {
24 24 await op(inner);
25 25 } finally {
26 26 // after the operation is complete we need to cleanup the
27 27 // resources
28 28 destroy(h);
29 29 this._cancel = null;
30 30 }
31 }
31 };
32 32
33 33 return this._completion = guard();
34 34 }
35 35
36 36 cancel(reason) {
37 37 if (this._cancel)
38 38 this._cancel(reason);
39 39 }
40 } No newline at end of file
40 }
@@ -1,128 +1,128
1 import * as format from "../text/format";
2 1 import { Observable } from "../Observable";
3 2 import { Registry } from "./Registry";
3 import { format } from "../text/FormatString";
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 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 this.emit(DebugLevel, format.apply(null, arguments));
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 this.emit(LogLevel, format.apply(null, arguments));
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 this.emit(WarnLevel, format.apply(null, arguments));
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
General Comments 0
You need to be logged in to leave comments. Login now