@oino-ts/common 0.10.4 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/OINOFormatter.js +161 -0
- package/dist/cjs/OINOHtmlTemplate.js +58 -25
- package/dist/cjs/OINOLog.js +14 -3
- package/dist/cjs/index.js +4 -1
- package/dist/esm/OINOFormatter.js +157 -0
- package/dist/esm/OINOHtmlTemplate.js +58 -25
- package/dist/esm/OINOLog.js +14 -3
- package/dist/esm/index.js +1 -0
- package/dist/types/OINOFormatter.d.ts +45 -0
- package/dist/types/OINOHtmlTemplate.d.ts +14 -13
- package/dist/types/OINOLog.d.ts +8 -1
- package/dist/types/index.d.ts +1 -0
- package/package.json +4 -2
- package/src/OINOFormatter.ts +165 -0
- package/src/OINOHtmlTemplate.test.ts +114 -0
- package/src/OINOHtmlTemplate.ts +59 -25
- package/src/OINOLog.ts +15 -3
- package/src/index.ts +1 -0
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { OINOStr, OINOContentType, OINOHttpResult, OINO_ERROR_PREFIX, OINO_WARNING_PREFIX, OINO_INFO_PREFIX, OINO_DEBUG_PREFIX, OINOBenchmark } from ".";
|
|
2
|
+
import { OINO_EMPTY_FORMATTER, OINOFormatter } from "./OINOFormatter";
|
|
2
3
|
/**
|
|
3
4
|
* Class for rendering HTML from data.
|
|
4
5
|
*/
|
|
5
6
|
export class OINOHtmlTemplate {
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
_tagOpen;
|
|
8
|
+
_tagClose;
|
|
8
9
|
_variables = {};
|
|
10
|
+
_tagStart = [];
|
|
11
|
+
_tagEnd = [];
|
|
12
|
+
_tagVariable = [];
|
|
13
|
+
_tagFormatters = [];
|
|
14
|
+
_tagCount = 0;
|
|
9
15
|
/** HTML template string */
|
|
10
16
|
template;
|
|
11
17
|
/** Cache modified value for template */
|
|
@@ -19,12 +25,13 @@ export class OINOHtmlTemplate {
|
|
|
19
25
|
* @param tag tag to identify variables in template
|
|
20
26
|
*
|
|
21
27
|
*/
|
|
22
|
-
constructor(template,
|
|
28
|
+
constructor(template, tagOpen = "{{{", tagClose = "}}}") {
|
|
23
29
|
this.template = template;
|
|
24
30
|
this.modified = 0;
|
|
25
31
|
this.expires = 0;
|
|
26
|
-
this.
|
|
27
|
-
this.
|
|
32
|
+
this._tagOpen = tagOpen;
|
|
33
|
+
this._tagClose = tagClose;
|
|
34
|
+
this._parseTemplate();
|
|
28
35
|
}
|
|
29
36
|
/**
|
|
30
37
|
* @returns whether template is empty
|
|
@@ -32,10 +39,30 @@ export class OINOHtmlTemplate {
|
|
|
32
39
|
isEmpty() {
|
|
33
40
|
return this.template == "";
|
|
34
41
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
_parseTemplate() {
|
|
43
|
+
const tag_open_length = this._tagOpen.length;
|
|
44
|
+
const tag_close_length = this._tagClose.length;
|
|
45
|
+
let tag_start_pos = this.template.indexOf(this._tagOpen, 0);
|
|
46
|
+
let tag_end_pos = this.template.indexOf(this._tagClose, tag_start_pos + tag_open_length) + tag_close_length;
|
|
47
|
+
while ((tag_start_pos >= 0) && (tag_end_pos > tag_start_pos)) {
|
|
48
|
+
this._tagStart.push(tag_start_pos);
|
|
49
|
+
this._tagEnd.push(tag_end_pos);
|
|
50
|
+
let variable = this.template.slice(tag_start_pos + tag_open_length, tag_end_pos - tag_close_length);
|
|
51
|
+
const variable_parts = variable.split("|");
|
|
52
|
+
if (variable_parts.length > 1) {
|
|
53
|
+
const formatter = OINOFormatter.parse(variable_parts.slice(1));
|
|
54
|
+
this._tagFormatters.push(formatter);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
this._tagFormatters.push(OINO_EMPTY_FORMATTER);
|
|
58
|
+
}
|
|
59
|
+
this._tagVariable.push(variable_parts[0]);
|
|
60
|
+
this._tagCount = this._tagCount + 1;
|
|
61
|
+
tag_start_pos = this.template.indexOf(this._tagOpen, tag_end_pos);
|
|
62
|
+
tag_end_pos = this.template.indexOf(this._tagClose, tag_start_pos + tag_open_length) + tag_close_length;
|
|
38
63
|
}
|
|
64
|
+
}
|
|
65
|
+
_createHttpResult(html) {
|
|
39
66
|
const result = new OINOHttpResult(html);
|
|
40
67
|
if (this.expires >= 1) {
|
|
41
68
|
result.expires = Math.round(this.expires);
|
|
@@ -46,11 +73,22 @@ export class OINOHtmlTemplate {
|
|
|
46
73
|
return result;
|
|
47
74
|
}
|
|
48
75
|
_renderHtml() {
|
|
49
|
-
let html =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
76
|
+
let html = "";
|
|
77
|
+
let start_pos = 0;
|
|
78
|
+
let end_pos = 0;
|
|
79
|
+
for (let i = 0; i < this._tagCount; i++) {
|
|
80
|
+
end_pos = this._tagStart[i];
|
|
81
|
+
const key = this._tagVariable[i];
|
|
82
|
+
const value = this._tagFormatters[i].format(this._variables[key] || "");
|
|
83
|
+
html += this.template.slice(start_pos, end_pos) + value;
|
|
84
|
+
start_pos = this._tagEnd[i];
|
|
53
85
|
}
|
|
86
|
+
html += this.template.slice(start_pos);
|
|
87
|
+
// let html:string = this.template
|
|
88
|
+
// for (let key in this._variables) {
|
|
89
|
+
// const value = this._variables[key]
|
|
90
|
+
// html = html.replaceAll(this._tag + key + this._tag, value)
|
|
91
|
+
// }
|
|
54
92
|
return html;
|
|
55
93
|
}
|
|
56
94
|
/**
|
|
@@ -96,26 +134,23 @@ export class OINOHtmlTemplate {
|
|
|
96
134
|
/**
|
|
97
135
|
* Creates HTML Response from set variables.
|
|
98
136
|
*
|
|
99
|
-
* @param removeUnusedTags whether to remove unused tags
|
|
100
|
-
*
|
|
101
137
|
*/
|
|
102
|
-
render(
|
|
138
|
+
render() {
|
|
103
139
|
const html = this._renderHtml();
|
|
104
140
|
this.clearVariables(); // clear variables after rendering
|
|
105
|
-
return this._createHttpResult(html
|
|
141
|
+
return this._createHttpResult(html);
|
|
106
142
|
}
|
|
107
143
|
/**
|
|
108
144
|
* Creates HTML Response from a key-value-pair.
|
|
109
145
|
*
|
|
110
146
|
* @param key key
|
|
111
147
|
* @param value value
|
|
112
|
-
* @param removeUnusedTags whether to remove unused tags
|
|
113
148
|
*
|
|
114
149
|
*/
|
|
115
|
-
renderFromKeyValue(key, value
|
|
150
|
+
renderFromKeyValue(key, value) {
|
|
116
151
|
OINOBenchmark.startMetric("OINOHtmlTemplate", "renderFromKeyValue");
|
|
117
152
|
this.setVariableFromValue(key, value);
|
|
118
|
-
const result = this.render(
|
|
153
|
+
const result = this.render();
|
|
119
154
|
OINOBenchmark.endMetric("OINOHtmlTemplate", "renderFromKeyValue");
|
|
120
155
|
return result;
|
|
121
156
|
}
|
|
@@ -123,13 +158,12 @@ export class OINOHtmlTemplate {
|
|
|
123
158
|
* Creates HTML Response from object properties.
|
|
124
159
|
*
|
|
125
160
|
* @param object object
|
|
126
|
-
* @param removeUnusedTags whether to remove unused tags
|
|
127
161
|
*
|
|
128
162
|
*/
|
|
129
|
-
renderFromObject(object
|
|
163
|
+
renderFromObject(object = true) {
|
|
130
164
|
OINOBenchmark.startMetric("OINOHtmlTemplate", "renderFromObject");
|
|
131
165
|
this.setVariableFromProperties(object);
|
|
132
|
-
const result = this.render(
|
|
166
|
+
const result = this.render();
|
|
133
167
|
OINOBenchmark.endMetric("OINOHtmlTemplate", "renderFromObject");
|
|
134
168
|
return result;
|
|
135
169
|
}
|
|
@@ -137,7 +171,6 @@ export class OINOHtmlTemplate {
|
|
|
137
171
|
* Creates HTML Response from API result.
|
|
138
172
|
*
|
|
139
173
|
* @param result OINOResult-object
|
|
140
|
-
* @param removeUnusedTags whether to remove unused tags
|
|
141
174
|
* @param messageSeparator HTML separator for messages
|
|
142
175
|
* @param includeErrorMessages include debug messages in result
|
|
143
176
|
* @param includeWarningMessages include debug messages in result
|
|
@@ -145,7 +178,7 @@ export class OINOHtmlTemplate {
|
|
|
145
178
|
* @param includeDebugMessages include debug messages in result
|
|
146
179
|
*
|
|
147
180
|
*/
|
|
148
|
-
renderFromResult(result,
|
|
181
|
+
renderFromResult(result, messageSeparator = "", includeErrorMessages = false, includeWarningMessages = false, includeInfoMessages = false, includeDebugMessages = false) {
|
|
149
182
|
OINOBenchmark.startMetric("OINOHtmlTemplate", "renderFromResult");
|
|
150
183
|
this.setVariableFromValue("statusCode", result.statusCode.toString());
|
|
151
184
|
this.setVariableFromValue("statusMessage", result.statusMessage.toString());
|
|
@@ -167,7 +200,7 @@ export class OINOHtmlTemplate {
|
|
|
167
200
|
if (messageSeparator && (messages.length > 0)) {
|
|
168
201
|
this.setVariableFromValue("messages", messages.join(messageSeparator), false); // messages have been escaped already
|
|
169
202
|
}
|
|
170
|
-
const http_result = this.render(
|
|
203
|
+
const http_result = this.render();
|
|
171
204
|
OINOBenchmark.endMetric("OINOHtmlTemplate", "renderFromResult");
|
|
172
205
|
return http_result;
|
|
173
206
|
}
|
package/dist/esm/OINOLog.js
CHANGED
|
@@ -183,14 +183,13 @@ export class OINOLog {
|
|
|
183
183
|
return result;
|
|
184
184
|
}
|
|
185
185
|
/**
|
|
186
|
-
*
|
|
186
|
+
* Set log levels from an array of objects with domain, channel, method and level overwriting existing values (i.e. non-existing values are not affected).
|
|
187
187
|
*
|
|
188
188
|
* @param logLevels array of log level objects
|
|
189
189
|
*
|
|
190
190
|
*/
|
|
191
|
-
static
|
|
191
|
+
static setLogLevels(logLevels) {
|
|
192
192
|
if (OINOLog._instance) {
|
|
193
|
-
OINOLog._instance._logLevels = { "||": OINOLog._instance._defaultLogLevel }; // reset to default log level
|
|
194
193
|
for (const logLevel of logLevels) {
|
|
195
194
|
const domain = logLevel.domain || "";
|
|
196
195
|
const channel = logLevel.channel || "";
|
|
@@ -202,6 +201,18 @@ export class OINOLog {
|
|
|
202
201
|
}
|
|
203
202
|
}
|
|
204
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* Import log levels from an array of objects with domain, channel, method and level resetting existing values (i.e. non-existing values get removed).
|
|
206
|
+
*
|
|
207
|
+
* @param logLevels array of log level objects
|
|
208
|
+
*
|
|
209
|
+
*/
|
|
210
|
+
static importLogLevels(logLevels) {
|
|
211
|
+
if (OINOLog._instance) {
|
|
212
|
+
OINOLog._instance._logLevels = { "||": OINOLog._instance._defaultLogLevel }; // reset to default log level
|
|
213
|
+
this.setLogLevels(logLevels);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
205
216
|
}
|
|
206
217
|
/**
|
|
207
218
|
* Logging implementation based on console.log.
|
package/dist/esm/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { OINOLog, OINOLogLevel, OINOConsoleLog } from "./OINOLog.js";
|
|
|
3
3
|
export { OINOResult, OINOHttpResult } from "./OINOResult.js";
|
|
4
4
|
export { OINOStr } from "./OINOStr.js";
|
|
5
5
|
export { OINOHtmlTemplate } from "./OINOHtmlTemplate.js";
|
|
6
|
+
export { OINOFormatter, OINO_EMPTY_FORMATTER } from "./OINOFormatter.js";
|
|
6
7
|
/** OINO error message prefix */
|
|
7
8
|
export const OINO_ERROR_PREFIX = "OINO ERROR";
|
|
8
9
|
/** OINO warning message prefix */
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Class for formatting strings and values.
|
|
3
|
+
*
|
|
4
|
+
*/
|
|
5
|
+
export declare class OINOFormatter {
|
|
6
|
+
static OINO_FORMATTER_REGEXP: RegExp;
|
|
7
|
+
_types: string[];
|
|
8
|
+
_params: any[][];
|
|
9
|
+
/**
|
|
10
|
+
* Constructor of `OINOFormatter`
|
|
11
|
+
* @param types array of formatter types
|
|
12
|
+
* @param params array of formatter parameters according to type
|
|
13
|
+
*/
|
|
14
|
+
constructor(types: string[], params: any[][]);
|
|
15
|
+
/**
|
|
16
|
+
* Constructor for `OINOFormatter` as parser of http parameter.
|
|
17
|
+
*
|
|
18
|
+
* @param formatters string or array of strings of serialized representation of formatters with following functions
|
|
19
|
+
* - trim()
|
|
20
|
+
* - trimLeft()
|
|
21
|
+
* - trimRight()
|
|
22
|
+
* - toUpper()
|
|
23
|
+
* - toLower()
|
|
24
|
+
* - cropLeft(charsToCrop)
|
|
25
|
+
* - cropRight(charsToCrop)
|
|
26
|
+
* - cropToDelimiter(delimiter,offsetChars)
|
|
27
|
+
* - cropFromDelimiter(delimiter,offsetChars)
|
|
28
|
+
* - substring(start,end)
|
|
29
|
+
* - replace(search,replace)
|
|
30
|
+
*/
|
|
31
|
+
static parse(formatters: string | string[]): OINOFormatter;
|
|
32
|
+
/**
|
|
33
|
+
* Does formatter include any operations.
|
|
34
|
+
* @return true if formatter is empty
|
|
35
|
+
*/
|
|
36
|
+
isEmpty(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Applies all formatters in order to given value.
|
|
39
|
+
*
|
|
40
|
+
* @param value string value to be formatted
|
|
41
|
+
* @returns formatted string value
|
|
42
|
+
*/
|
|
43
|
+
format(value: string): string;
|
|
44
|
+
}
|
|
45
|
+
export declare const OINO_EMPTY_FORMATTER: OINOFormatter;
|
|
@@ -3,9 +3,14 @@ import { OINOResult, OINOHttpResult } from ".";
|
|
|
3
3
|
* Class for rendering HTML from data.
|
|
4
4
|
*/
|
|
5
5
|
export declare class OINOHtmlTemplate {
|
|
6
|
-
private
|
|
7
|
-
private
|
|
6
|
+
private _tagOpen;
|
|
7
|
+
private _tagClose;
|
|
8
8
|
private _variables;
|
|
9
|
+
private _tagStart;
|
|
10
|
+
private _tagEnd;
|
|
11
|
+
private _tagVariable;
|
|
12
|
+
private _tagFormatters;
|
|
13
|
+
private _tagCount;
|
|
9
14
|
/** HTML template string */
|
|
10
15
|
template: string;
|
|
11
16
|
/** Cache modified value for template */
|
|
@@ -19,12 +24,13 @@ export declare class OINOHtmlTemplate {
|
|
|
19
24
|
* @param tag tag to identify variables in template
|
|
20
25
|
*
|
|
21
26
|
*/
|
|
22
|
-
constructor(template: string,
|
|
27
|
+
constructor(template: string, tagOpen?: string, tagClose?: string);
|
|
23
28
|
/**
|
|
24
29
|
* @returns whether template is empty
|
|
25
30
|
*/
|
|
26
31
|
isEmpty(): boolean;
|
|
27
|
-
protected
|
|
32
|
+
protected _parseTemplate(): void;
|
|
33
|
+
protected _createHttpResult(html: string): OINOHttpResult;
|
|
28
34
|
protected _renderHtml(): string;
|
|
29
35
|
/**
|
|
30
36
|
* Clear template variables.
|
|
@@ -51,32 +57,27 @@ export declare class OINOHtmlTemplate {
|
|
|
51
57
|
/**
|
|
52
58
|
* Creates HTML Response from set variables.
|
|
53
59
|
*
|
|
54
|
-
* @param removeUnusedTags whether to remove unused tags
|
|
55
|
-
*
|
|
56
60
|
*/
|
|
57
|
-
render(
|
|
61
|
+
render(): OINOHttpResult;
|
|
58
62
|
/**
|
|
59
63
|
* Creates HTML Response from a key-value-pair.
|
|
60
64
|
*
|
|
61
65
|
* @param key key
|
|
62
66
|
* @param value value
|
|
63
|
-
* @param removeUnusedTags whether to remove unused tags
|
|
64
67
|
*
|
|
65
68
|
*/
|
|
66
|
-
renderFromKeyValue(key: string, value: string
|
|
69
|
+
renderFromKeyValue(key: string, value: string): OINOHttpResult;
|
|
67
70
|
/**
|
|
68
71
|
* Creates HTML Response from object properties.
|
|
69
72
|
*
|
|
70
73
|
* @param object object
|
|
71
|
-
* @param removeUnusedTags whether to remove unused tags
|
|
72
74
|
*
|
|
73
75
|
*/
|
|
74
|
-
renderFromObject(object
|
|
76
|
+
renderFromObject(object?: any): OINOHttpResult;
|
|
75
77
|
/**
|
|
76
78
|
* Creates HTML Response from API result.
|
|
77
79
|
*
|
|
78
80
|
* @param result OINOResult-object
|
|
79
|
-
* @param removeUnusedTags whether to remove unused tags
|
|
80
81
|
* @param messageSeparator HTML separator for messages
|
|
81
82
|
* @param includeErrorMessages include debug messages in result
|
|
82
83
|
* @param includeWarningMessages include debug messages in result
|
|
@@ -84,5 +85,5 @@ export declare class OINOHtmlTemplate {
|
|
|
84
85
|
* @param includeDebugMessages include debug messages in result
|
|
85
86
|
*
|
|
86
87
|
*/
|
|
87
|
-
renderFromResult(result: OINOResult,
|
|
88
|
+
renderFromResult(result: OINOResult, messageSeparator?: string, includeErrorMessages?: boolean, includeWarningMessages?: boolean, includeInfoMessages?: boolean, includeDebugMessages?: boolean): OINOHttpResult;
|
|
88
89
|
}
|
package/dist/types/OINOLog.d.ts
CHANGED
|
@@ -134,7 +134,14 @@ export declare abstract class OINOLog {
|
|
|
134
134
|
*/
|
|
135
135
|
static exportLogLevels(): any[];
|
|
136
136
|
/**
|
|
137
|
-
*
|
|
137
|
+
* Set log levels from an array of objects with domain, channel, method and level overwriting existing values (i.e. non-existing values are not affected).
|
|
138
|
+
*
|
|
139
|
+
* @param logLevels array of log level objects
|
|
140
|
+
*
|
|
141
|
+
*/
|
|
142
|
+
static setLogLevels(logLevels: any[]): void;
|
|
143
|
+
/**
|
|
144
|
+
* Import log levels from an array of objects with domain, channel, method and level resetting existing values (i.e. non-existing values get removed).
|
|
138
145
|
*
|
|
139
146
|
* @param logLevels array of log level objects
|
|
140
147
|
*
|
package/dist/types/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { OINOLog, OINOLogLevel, OINOConsoleLog } from "./OINOLog.js";
|
|
|
3
3
|
export { OINOResult, OINOHttpResult } from "./OINOResult.js";
|
|
4
4
|
export { OINOStr } from "./OINOStr.js";
|
|
5
5
|
export { OINOHtmlTemplate } from "./OINOHtmlTemplate.js";
|
|
6
|
+
export { OINOFormatter, OINO_EMPTY_FORMATTER } from "./OINOFormatter.js";
|
|
6
7
|
/** OINO error message prefix */
|
|
7
8
|
export declare const OINO_ERROR_PREFIX = "OINO ERROR";
|
|
8
9
|
/** OINO warning message prefix */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oino-ts/common",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "OINO TS package for common classes.",
|
|
5
5
|
"author": "Matias Kiviniemi (pragmatta)",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@oino-ts/types": "0.
|
|
22
|
+
"@oino-ts/types": "0.12.0",
|
|
23
|
+
"@types/node": "^22.0.0",
|
|
24
|
+
"typescript": "~5.9.0"
|
|
23
25
|
},
|
|
24
26
|
"files": [
|
|
25
27
|
"src/*.ts",
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { OINO_ERROR_PREFIX, OINOLog } from "./index.js"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Class for formatting strings and values.
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
export class OINOFormatter {
|
|
16
|
+
static OINO_FORMATTER_REGEXP = /\s?(trim(\(\))?|trimLeft(\(\))?|trimRight(\(\))?|toUpper(\(\))?|toLower(\(\))?|cropLeft\((\d+)\)|cropRight\((\d+)\)|cropToDelimiter\(([^\(\),]+),(\d+)\)|cropFromDelimiter\(([^\(\),]+),(\d+)\)|substring\((\d+),(\d+)\)|replace\(([^\(\),]+),([^\(\),]+)\))\s?$/i
|
|
17
|
+
_types: string[]
|
|
18
|
+
_params: any[][]
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Constructor of `OINOFormatter`
|
|
22
|
+
* @param types array of formatter types
|
|
23
|
+
* @param params array of formatter parameters according to type
|
|
24
|
+
*/
|
|
25
|
+
constructor(types: string[], params: any[][]) {
|
|
26
|
+
this._types = types
|
|
27
|
+
this._params = params
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Constructor for `OINOFormatter` as parser of http parameter.
|
|
32
|
+
*
|
|
33
|
+
* @param formatters string or array of strings of serialized representation of formatters with following functions
|
|
34
|
+
* - trim()
|
|
35
|
+
* - trimLeft()
|
|
36
|
+
* - trimRight()
|
|
37
|
+
* - toUpper()
|
|
38
|
+
* - toLower()
|
|
39
|
+
* - cropLeft(charsToCrop)
|
|
40
|
+
* - cropRight(charsToCrop)
|
|
41
|
+
* - cropToDelimiter(delimiter,offsetChars)
|
|
42
|
+
* - cropFromDelimiter(delimiter,offsetChars)
|
|
43
|
+
* - substring(start,end)
|
|
44
|
+
* - replace(search,replace)
|
|
45
|
+
*/
|
|
46
|
+
static parse(formatters: string|string[]): OINOFormatter {
|
|
47
|
+
if (typeof formatters === "string") {
|
|
48
|
+
formatters = [formatters]
|
|
49
|
+
}
|
|
50
|
+
if (!formatters || formatters.length === 0) {
|
|
51
|
+
return OINO_EMPTY_FORMATTER
|
|
52
|
+
|
|
53
|
+
} else {
|
|
54
|
+
const types:string[] = []
|
|
55
|
+
const params:any[][] = []
|
|
56
|
+
for (let i=0; i<formatters.length; i++) {
|
|
57
|
+
let match = formatters[i]?.match(this.OINO_FORMATTER_REGEXP)
|
|
58
|
+
if (!match) {
|
|
59
|
+
OINOLog.error("@oino-ts/common", "OINOFormatter", "parse", "Invalid formatter string", {formatter:formatters[i]})
|
|
60
|
+
throw new Error(OINO_ERROR_PREFIX + "Invalid formatter: " + formatters[i])
|
|
61
|
+
} else {
|
|
62
|
+
const formatter_type = match[1].toLowerCase().substring(0, match[1].indexOf('('))
|
|
63
|
+
const formatter_params: any[] = []
|
|
64
|
+
if ((formatter_type === "trim") || (formatter_type === "trimleft") || (formatter_type === "trimright") || (formatter_type === "toupper") || (formatter_type === "tolower")) {
|
|
65
|
+
// no parameters
|
|
66
|
+
|
|
67
|
+
} else if (formatter_type=== "cropleft") {
|
|
68
|
+
formatter_params.push(parseInt(match[7]))
|
|
69
|
+
|
|
70
|
+
} else if (formatter_type === "cropright") {
|
|
71
|
+
formatter_params.push(parseInt(match[8]))
|
|
72
|
+
|
|
73
|
+
} else if (formatter_type === "croptodelimiter") {
|
|
74
|
+
formatter_params.push(decodeURIComponent(match[9]), parseInt(match[10]))
|
|
75
|
+
|
|
76
|
+
} else if (formatter_type === "cropfromdelimiter") {
|
|
77
|
+
formatter_params.push(decodeURIComponent(match[11]), parseInt(match[12]))
|
|
78
|
+
|
|
79
|
+
} else if (formatter_type === "substring") {
|
|
80
|
+
formatter_params.push(parseInt(match[13]), parseInt(match[14]))
|
|
81
|
+
|
|
82
|
+
} else if (formatter_type === "replace") {
|
|
83
|
+
formatter_params.push(decodeURIComponent(match[15]), decodeURIComponent(match[16]))
|
|
84
|
+
} else {
|
|
85
|
+
OINOLog.error("@oino-ts/common", "OINOFormatter", "parse", "Unknown formatter type", {formatter:formatters[i]})
|
|
86
|
+
throw new Error(OINO_ERROR_PREFIX + "Unsupported formatter: " + formatters[i])
|
|
87
|
+
}
|
|
88
|
+
types.push(formatter_type)
|
|
89
|
+
params.push(formatter_params)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return new OINOFormatter(types, params)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Does formatter include any operations.
|
|
98
|
+
* @return true if formatter is empty
|
|
99
|
+
*/
|
|
100
|
+
isEmpty():boolean {
|
|
101
|
+
return this._types.length === 0
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Applies all formatters in order to given value.
|
|
106
|
+
*
|
|
107
|
+
* @param value string value to be formatted
|
|
108
|
+
* @returns formatted string value
|
|
109
|
+
*/
|
|
110
|
+
format(value: string): string {
|
|
111
|
+
let formatted = value
|
|
112
|
+
for (let i = 0; i < this._types.length; i++) {
|
|
113
|
+
const formatter_type = this._types[i]
|
|
114
|
+
const formatter_params = this._params[i]
|
|
115
|
+
if (formatter_type === "trim") {
|
|
116
|
+
formatted = formatted.trim()
|
|
117
|
+
|
|
118
|
+
} else if (formatter_type === "trimleft") {
|
|
119
|
+
formatted = formatted.trimStart()
|
|
120
|
+
|
|
121
|
+
} else if (formatter_type === "trimright") {
|
|
122
|
+
formatted = formatted.trimEnd()
|
|
123
|
+
|
|
124
|
+
} else if (formatter_type === "toupper") {
|
|
125
|
+
formatted = formatted.toUpperCase()
|
|
126
|
+
|
|
127
|
+
} else if (formatter_type === "tolower") {
|
|
128
|
+
formatted = formatted.toLowerCase()
|
|
129
|
+
|
|
130
|
+
} else if (formatter_type === "cropleft") {
|
|
131
|
+
formatted = formatted.slice(formatter_params[0])
|
|
132
|
+
|
|
133
|
+
} else if (formatter_type === "cropright") {
|
|
134
|
+
formatted = formatted.slice(0, formatted.length-formatter_params[0])
|
|
135
|
+
|
|
136
|
+
} else if (formatter_type === "croptodelimiter") {
|
|
137
|
+
const to_demilimiter_idx = formatted.indexOf(formatter_params[0])
|
|
138
|
+
if (to_demilimiter_idx >= 0) {
|
|
139
|
+
formatted = formatted.slice(Math.max(to_demilimiter_idx + formatter_params[0].length + formatter_params[1], 0))
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
} else if (formatter_type === "cropfromdelimiter") {
|
|
143
|
+
const from_demilimiter_idx = formatted.indexOf(formatter_params[0])
|
|
144
|
+
if (from_demilimiter_idx >= 0) {
|
|
145
|
+
formatted = formatted.slice(0, Math.max(from_demilimiter_idx + formatter_params[1], 0))
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
} else if (formatter_type === "substring") {
|
|
149
|
+
const start = formatter_params[0] ? parseInt(formatter_params[0]) : 0
|
|
150
|
+
const end = formatter_params[1] ? parseInt(formatter_params[1]) : formatted.length
|
|
151
|
+
formatted = formatted.substring(start, end)
|
|
152
|
+
|
|
153
|
+
} else if (formatter_type === "replace") {
|
|
154
|
+
const search = formatter_params[0]
|
|
155
|
+
const replacement = formatter_params[1]
|
|
156
|
+
formatted = formatted.replaceAll(search, replacement)
|
|
157
|
+
}
|
|
158
|
+
// console.log("formatter:", formatter_type, "params:", formatter_params, "formatted:", formatted)
|
|
159
|
+
}
|
|
160
|
+
return formatted
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export const OINO_EMPTY_FORMATTER = new OINOFormatter([], [])
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { expect, test } from "bun:test";
|
|
8
|
+
|
|
9
|
+
import { OINOHtmlTemplate } from "./OINOHtmlTemplate"
|
|
10
|
+
import { OINOFormatter } from "./OINOFormatter";
|
|
11
|
+
import { OINOLog, OINOConsoleLog, OINOLogLevel } from "./OINOLog"
|
|
12
|
+
|
|
13
|
+
Math.random()
|
|
14
|
+
|
|
15
|
+
OINOLog.setInstance(new OINOConsoleLog(OINOLogLevel.error))
|
|
16
|
+
|
|
17
|
+
const VARIABLE_OPTIONS = [
|
|
18
|
+
"{{{var{i}}}}", // 0 nothing
|
|
19
|
+
"{{{var{i}|trim()}}}", // 1 trim
|
|
20
|
+
"{{{var{i}|trimLeft()}}}", // 2 trimLeft
|
|
21
|
+
"{{{var{i}|trimRight()}}}", // 3 trimRight
|
|
22
|
+
"{{{var{i}|toLower()}}}", // 4 toLower
|
|
23
|
+
"{{{var{i}|cropLeft(1)}}}", // 5 cropLeft
|
|
24
|
+
"{{{var{i}|cropRight(1)}}}", // 6 cropRight
|
|
25
|
+
"{{{var{i}|cropToDelimiter(¤,1)}}}", // 7 cropToDelimiter
|
|
26
|
+
"{{{var{i}|cropFromDelimiter(¤,0)}}}", // 8 cropFromDelimiter
|
|
27
|
+
"{{{var{i}|substring(2,10)}}}", // 9 substring
|
|
28
|
+
"{{{var{i}|replace(¤,a)}}}" // 10 replace
|
|
29
|
+
]
|
|
30
|
+
const VARIABLE_VALUES = [
|
|
31
|
+
"value{i}", // 0 nothing
|
|
32
|
+
" value{i} ", // 1 trim
|
|
33
|
+
" value{i}", // 2 trimLeft
|
|
34
|
+
"value{i} ", // 3 trimRight
|
|
35
|
+
"VALUE{i}", // 4 toLower
|
|
36
|
+
"¤value{i}", // 5 cropLeft
|
|
37
|
+
"value{i}¤", // 6 cropRight
|
|
38
|
+
"¤¤value{i}", // 7 cropToDelimiter
|
|
39
|
+
"value{i}¤!", // 8 cropFromDelimiter
|
|
40
|
+
"!¤value{i}", // 9 substring
|
|
41
|
+
"v¤lue{i}" // 10 replace
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
function _generateTemplateVariable(i:number): string {
|
|
46
|
+
return VARIABLE_OPTIONS[i % VARIABLE_OPTIONS.length].replace(/\{i\}/g, i.toString())
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function _generateTemplateHtml(variableCount: number): string {
|
|
50
|
+
let template = "{{{header}}}\n<div>\n" // edge case: tag at the start of the template
|
|
51
|
+
for (let i = 1; i <= variableCount; i++) {
|
|
52
|
+
template += `<p>${_generateTemplateVariable(i)}</p>\n`
|
|
53
|
+
}
|
|
54
|
+
template += "</div>\n{{{footer}}}" // edge case: tag at the end of the template
|
|
55
|
+
return template
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function _generateResultHtml(variableCount: number): string {
|
|
59
|
+
let template = "header\n<div>\n"
|
|
60
|
+
for (let i = 1; i <= variableCount; i++) {
|
|
61
|
+
template += `<p>value${i}</p>\n`
|
|
62
|
+
}
|
|
63
|
+
template += "</div>\nfooter"
|
|
64
|
+
return template
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
function _generateValue(i: number): string {
|
|
69
|
+
return VARIABLE_VALUES[i % VARIABLE_VALUES.length].replace(/\{i\}/g, i.toString())
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function _generateValues(variableCount: number): any {
|
|
73
|
+
const values: any = { header: "header", footer: "footer" }
|
|
74
|
+
for (let i = 1; i <= variableCount; i++) {
|
|
75
|
+
values[`var${i}`] = _generateValue(i)
|
|
76
|
+
}
|
|
77
|
+
return values
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function benchmarkOINOHtmlTemplate(variables:number, replacements: number = 1000): number {
|
|
81
|
+
const template = new OINOHtmlTemplate(_generateTemplateHtml(variables))
|
|
82
|
+
const values = _generateValues(variables)
|
|
83
|
+
const result = _generateResultHtml(variables)
|
|
84
|
+
|
|
85
|
+
const start = performance.now();
|
|
86
|
+
|
|
87
|
+
for (let i = 0; i < replacements; i+=variables) {
|
|
88
|
+
template.setVariableFromProperties(values)
|
|
89
|
+
const res = template.render()
|
|
90
|
+
expect(res.body).toBe(result)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const end = performance.now()
|
|
94
|
+
const duration = end - start
|
|
95
|
+
return Math.round(replacements / duration)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
await test("OINOHtmlTemplate render and performance", async () => {
|
|
99
|
+
|
|
100
|
+
let hps_min = Number.MAX_VALUE
|
|
101
|
+
let hps_max = 0
|
|
102
|
+
|
|
103
|
+
for (let j=10; j<=100; j+=10) {
|
|
104
|
+
const rps = benchmarkOINOHtmlTemplate(j, 100000)
|
|
105
|
+
// console.log(`Template variable renders per second with ${j} variables: ${rps}krps`)
|
|
106
|
+
hps_min = Math.min(rps, hps_min)
|
|
107
|
+
hps_max = Math.max(rps, hps_max)
|
|
108
|
+
expect(hps_min).toBeGreaterThanOrEqual(2500)
|
|
109
|
+
expect(hps_max).toBeLessThanOrEqual(5000)
|
|
110
|
+
}
|
|
111
|
+
console.log("OINOHtmlTemplate performance: " + hps_min + "k - " + hps_max + "k renders per second")
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
|