@oino-ts/common 0.1.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.
@@ -0,0 +1,211 @@
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
+ import { createHash } from "node:crypto";
7
+ import { OINO_DEBUG_PREFIX, OINO_ERROR_PREFIX, OINO_INFO_PREFIX, OINO_WARNING_PREFIX } from ".";
8
+ /**
9
+ * OINO API request result object with returned data and/or http status code/message and
10
+ * error / warning messages.
11
+ *
12
+ */
13
+ export class OINOResult {
14
+ /** Wheter request was successfully executed */
15
+ success;
16
+ /** HTTP status code */
17
+ statusCode;
18
+ /** HTTP status message */
19
+ statusMessage;
20
+ /** Error / warning messages */
21
+ messages;
22
+ /**
23
+ * Constructor of OINOResult.
24
+ *
25
+ */
26
+ constructor() {
27
+ this.success = true;
28
+ this.statusCode = 200;
29
+ this.statusMessage = "OK";
30
+ this.messages = [];
31
+ }
32
+ /**
33
+ * Copy values from different result.
34
+ *
35
+ * @param result source value
36
+ */
37
+ copy(result) {
38
+ this.success = result.success;
39
+ this.statusCode = result.statusCode;
40
+ this.statusMessage = result.statusMessage;
41
+ this.messages = result.messages.slice();
42
+ }
43
+ /**
44
+ * Set HTTP OK status (does not reset messages).
45
+ *
46
+ */
47
+ setOk() {
48
+ this.success = true;
49
+ this.statusCode = 200;
50
+ this.statusMessage = "OK";
51
+ }
52
+ /**
53
+ * Set HTTP error status using given code and message. Returns self reference for chaining.
54
+ *
55
+ * @param statusCode HTTP status code
56
+ * @param statusMessage HTTP status message
57
+ * @param operation operation where error occured
58
+ *
59
+ */
60
+ setError(statusCode, statusMessage, operation) {
61
+ this.success = false;
62
+ this.statusCode = statusCode;
63
+ if (this.statusMessage != "OK") {
64
+ this.messages.push(this.statusMessage); // latest error becomes status, but if there was something non-trivial, add it to the messages
65
+ }
66
+ if (statusMessage.startsWith(OINO_ERROR_PREFIX)) {
67
+ this.statusMessage = statusMessage;
68
+ }
69
+ else {
70
+ this.statusMessage = OINO_ERROR_PREFIX + " (" + operation + "): " + statusMessage;
71
+ }
72
+ return this;
73
+ }
74
+ /**
75
+ * Add warning message. Returns self reference for chaining.
76
+ *
77
+ * @param message HTTP status message
78
+ * @param operation operation where warning occured
79
+ *
80
+ */
81
+ addWarning(message, operation) {
82
+ message = message.trim();
83
+ if (message) {
84
+ this.messages.push(OINO_WARNING_PREFIX + " (" + operation + "): " + message);
85
+ }
86
+ return this;
87
+ }
88
+ /**
89
+ * Add info message. Returns self reference for chaining.
90
+ *
91
+ * @param message HTTP status message
92
+ * @param operation operation where info occured
93
+ *
94
+ */
95
+ addInfo(message, operation) {
96
+ message = message.trim();
97
+ if (message) {
98
+ this.messages.push(OINO_INFO_PREFIX + " (" + operation + "): " + message);
99
+ }
100
+ return this;
101
+ }
102
+ /**
103
+ * Add debug message. Returns self reference for chaining.
104
+ *
105
+ * @param message HTTP status message
106
+ * @param operation operation where debug occured
107
+ *
108
+ */
109
+ addDebug(message, operation) {
110
+ message = message.trim();
111
+ if (message) {
112
+ this.messages.push(OINO_DEBUG_PREFIX + " (" + operation + "): " + message);
113
+ }
114
+ return this;
115
+ }
116
+ /**
117
+ * Copy given messages to HTTP headers.
118
+ *
119
+ * @param headers HTTP headers
120
+ * @param copyErrors wether error messages should be copied (default true)
121
+ * @param copyWarnings wether warning messages should be copied (default false)
122
+ * @param copyInfos wether info messages should be copied (default false)
123
+ * @param copyDebug wether debug messages should be copied (default false)
124
+ *
125
+ */
126
+ copyMessagesToHeaders(headers, copyErrors = true, copyWarnings = false, copyInfos = false, copyDebug = false) {
127
+ let j = 1;
128
+ for (let i = 0; i < this.messages.length; i++) {
129
+ const message = this.messages[i].replaceAll("\r", " ").replaceAll("\n", " ");
130
+ if (copyErrors && message.startsWith(OINO_ERROR_PREFIX)) {
131
+ headers.append('X-OINO-MESSAGE-' + j, message);
132
+ j++;
133
+ }
134
+ if (copyWarnings && message.startsWith(OINO_WARNING_PREFIX)) {
135
+ headers.append('X-OINO-MESSAGE-' + j, message);
136
+ j++;
137
+ }
138
+ if (copyInfos && message.startsWith(OINO_INFO_PREFIX)) {
139
+ headers.append('X-OINO-MESSAGE-' + j, message);
140
+ j++;
141
+ }
142
+ if (copyDebug && message.startsWith(OINO_DEBUG_PREFIX)) {
143
+ headers.append('X-OINO-MESSAGE-' + j, message);
144
+ j++;
145
+ }
146
+ }
147
+ }
148
+ /**
149
+ * Print result for logging.
150
+ *
151
+ */
152
+ printLog() {
153
+ return "OINOResult: statusCode=" + this.statusCode + ", statusMessage=" + this.statusMessage + ", messages=[" + this.messages.join(", ") + "]";
154
+ }
155
+ }
156
+ /**
157
+ * Specialized result for HTTP responses.
158
+ */
159
+ export class OINOHttpResult extends OINOResult {
160
+ _etag;
161
+ /** HTTP body data */
162
+ body;
163
+ /** HTTP cache expiration value */
164
+ expires;
165
+ /** HTTP cache last-modified value */
166
+ lastModified;
167
+ /**
168
+ * Constructor for a `OINOHttpResult`
169
+ *
170
+ * @param body HTTP body
171
+ *
172
+ */
173
+ constructor(body) {
174
+ super();
175
+ this.body = body;
176
+ this.expires = 0;
177
+ this.lastModified = 0;
178
+ this._etag = "";
179
+ }
180
+ /**
181
+ * Get the ETag value for the body opportunistically, i.e. don't calculate until requested and reuse value.
182
+ *
183
+ */
184
+ getEtag() {
185
+ if (this._etag == "") {
186
+ const hash = createHash("sha256");
187
+ this._etag = hash.update(this.body).digest("hex");
188
+ }
189
+ return this._etag;
190
+ }
191
+ /**
192
+ * Get a Response object from the result values.
193
+ *
194
+ * @param headers HTTP headers (overrides existing values)
195
+ */
196
+ getResponse(headers) {
197
+ const result = new Response(this.body, { status: this.statusCode, statusText: this.statusMessage, headers: headers });
198
+ result.headers.set('Content-Length', this.body.length.toString());
199
+ if (this.lastModified > 0) {
200
+ result.headers.set('Last-Modified', new Date(this.lastModified).toUTCString());
201
+ }
202
+ if (this.expires >= 0) {
203
+ result.headers.set('Expires', Math.round(this.expires).toString());
204
+ if (this.expires == 0) {
205
+ result.headers.set('Pragma', 'no-cache');
206
+ }
207
+ }
208
+ result.headers.set("ETag", this.getEtag());
209
+ return result;
210
+ }
211
+ }
@@ -0,0 +1,261 @@
1
+ import { OINOContentType } from ".";
2
+ /**
3
+ * Static class string utilities.
4
+ *
5
+ */
6
+ export class OINOStr {
7
+ /**
8
+ * Split string by the top level of the given type of brackets.
9
+ * E.g. splitByBrackets("a(bc(d))ef(gh)kl", true, true, '(', ')') would return ["a", "bc(d)", "ef", "gh", "kl"]
10
+ *
11
+ * @param str string to split
12
+ * @param includePartsBetweenBlocks whether to include strings between top level brackets
13
+ * @param includeTrailingUnescapedBlock whether to include final block that is missing necessary end brackets
14
+ * @param startBracket starting bracket, e.g. '('
15
+ * @param endBracket ending bracket, e.g. ')'
16
+ *
17
+ */
18
+ static splitByBrackets(str, includePartsBetweenBlocks, includeTrailingUnescapedBlock, startBracket, endBracket) {
19
+ let result = [];
20
+ let parenthesis_count = 0;
21
+ let start = 0;
22
+ let end = 0;
23
+ while (end < str.length) {
24
+ if (str[end] == startBracket) {
25
+ if (parenthesis_count == 0) {
26
+ if ((end > start) && includePartsBetweenBlocks) { // there is some first level string to add to result
27
+ result.push(str.substring(start, end));
28
+ }
29
+ start = end + 1;
30
+ }
31
+ parenthesis_count++;
32
+ }
33
+ else if (str[end] == endBracket) {
34
+ parenthesis_count--;
35
+ if (parenthesis_count == 0) {
36
+ if (end >= start) {
37
+ result.push(str.substring(start, end));
38
+ }
39
+ start = end + 1;
40
+ }
41
+ }
42
+ end++;
43
+ }
44
+ if ((end > start) && ((includePartsBetweenBlocks && (parenthesis_count == 0)) || (includeTrailingUnescapedBlock && (parenthesis_count > 0)))) { // if there is stuff after last block or unfinished block (and those are supported)
45
+ result.push(str.substring(start, end)); // i == str.length
46
+ }
47
+ return result;
48
+ }
49
+ /**
50
+ * Split string by delimeter excluding delimeters inside given brackets.
51
+ * E.g. splitExcludingBrackets("a,(bc,d),ef,(g,h),k", ',', '(', ')') would return ["a", "bc,d", "ef", "g,h", "k"]
52
+ *
53
+ * @param str string to split
54
+ * @param delimeter string to use as delimeter
55
+ * @param startBracket starting bracket, e.g. '('
56
+ * @param endBracket ending bracket, e.g. ')'
57
+ */
58
+ static splitExcludingBrackets(str, delimeter, startBracket, endBracket) {
59
+ let result = [];
60
+ let bracket_level = 0;
61
+ let start = 0;
62
+ let end = 0;
63
+ while (end < str.length) {
64
+ if (str[end] == startBracket) {
65
+ bracket_level++;
66
+ }
67
+ else if (str[end] == endBracket) {
68
+ bracket_level--;
69
+ }
70
+ else if ((str[end] == delimeter) && (bracket_level == 0)) { // only delimeters at top level will break
71
+ result.push(str.substring(start, end));
72
+ start = end + 1;
73
+ }
74
+ end++;
75
+ }
76
+ if (end > start) {
77
+ result.push(str.substring(start, end)); // i == str.length
78
+ }
79
+ return result;
80
+ }
81
+ /**
82
+ * Encode OINO serialized strings as valid JSON.
83
+ *
84
+ * @param str string to encode
85
+ * @param valueType wether it is a value type
86
+ */
87
+ static encodeJSON(str, valueType = false) {
88
+ if (str === undefined) { // no undefined literal in JSON
89
+ return "null";
90
+ }
91
+ else if (str === null) {
92
+ return "null";
93
+ }
94
+ else {
95
+ if (valueType) {
96
+ return str;
97
+ }
98
+ else {
99
+ return JSON.stringify(str);
100
+ }
101
+ }
102
+ }
103
+ /**
104
+ * Decode JSON string as OINO serialization.
105
+ *
106
+ * @param str string to decode
107
+ */
108
+ static decodeJSON(str) {
109
+ return str; // JSON parsing using JS methods, no need to decode anything
110
+ }
111
+ /**
112
+ * Encode OINO serialized strings as valid CSV.
113
+ *
114
+ * @param str string to encode
115
+ */
116
+ static encodeCSV(str) {
117
+ if (str === undefined) {
118
+ return "";
119
+ }
120
+ else if (str === null) {
121
+ return "null";
122
+ }
123
+ else {
124
+ return "\"" + str.replaceAll("\"", "\"\"") + "\"";
125
+ }
126
+ }
127
+ /**
128
+ * Decode CSV string as OINO serialization.
129
+ *
130
+ * @param str string to decode
131
+ */
132
+ static decodeCSV(str) {
133
+ return str.replaceAll("\"\"", "\"");
134
+ }
135
+ /**
136
+ * Encode OINO serialized strings as valid Formdata.
137
+ *
138
+ * @param str string to encode
139
+ */
140
+ static encodeFormdata(str) {
141
+ if (str === undefined) {
142
+ return "";
143
+ }
144
+ else if (str === null) {
145
+ return "";
146
+ }
147
+ else {
148
+ return str;
149
+ }
150
+ }
151
+ /**
152
+ * Decode Formdata string as OINO serialization.
153
+ *
154
+ * @param str string to decode
155
+ */
156
+ static decodeFormdata(str) {
157
+ return str;
158
+ }
159
+ /**
160
+ * Encode OINO serialized strings as valid Urlencode.
161
+ *
162
+ * @param str string to encode
163
+ */
164
+ static encodeUrlencode(str) {
165
+ if (str === undefined) {
166
+ return "";
167
+ }
168
+ else if (str === null) {
169
+ return "null";
170
+ }
171
+ else {
172
+ return encodeURIComponent(str);
173
+ }
174
+ }
175
+ /**
176
+ * Decode Urlencode string as OINO serialization.
177
+ *
178
+ * @param str string to decode
179
+ */
180
+ static decodeUrlencode(str) {
181
+ return decodeURIComponent(str);
182
+ }
183
+ /**
184
+ * Encode OINO serialized strings as valid HTML content.
185
+ *
186
+ * @param str string to encode
187
+ */
188
+ static encodeHtml(str) {
189
+ if (str === undefined) {
190
+ return "";
191
+ }
192
+ else if (str === null) {
193
+ return "";
194
+ }
195
+ else {
196
+ return str.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll("'", '&#039;');
197
+ }
198
+ }
199
+ /**
200
+ * Decode HTML string as OINO serialization.
201
+ *
202
+ * @param str string to encode
203
+ */
204
+ static decodeHtml(str) {
205
+ return str.replaceAll('&amp;', '&').replaceAll('&lt;', '<').replaceAll('&gt;', '>').replaceAll('&quot;', '"').replaceAll('&#039;', "'");
206
+ }
207
+ /**
208
+ * Decode content type formatted string as OINO serialization.
209
+ *
210
+ * @param str string to decode
211
+ * @param contentType content type for serialization
212
+ *
213
+ */
214
+ static decode(str, contentType) {
215
+ if (contentType == OINOContentType.csv) {
216
+ return this.decodeCSV(str);
217
+ }
218
+ else if (contentType == OINOContentType.json) {
219
+ return this.decodeJSON(str);
220
+ }
221
+ else if (contentType == OINOContentType.formdata) {
222
+ return this.decodeFormdata(str);
223
+ }
224
+ else if (contentType == OINOContentType.urlencode) {
225
+ return this.decodeUrlencode(str);
226
+ }
227
+ else if (contentType == OINOContentType.html) {
228
+ return str;
229
+ }
230
+ else {
231
+ return str;
232
+ }
233
+ }
234
+ /**
235
+ * Encode OINO serialized string to the content type formatting.
236
+ *
237
+ * @param str string to encode
238
+ * @param contentType content type for serialization
239
+ *
240
+ */
241
+ static encode(str, contentType) {
242
+ if (contentType == OINOContentType.csv) {
243
+ return this.encodeCSV(str);
244
+ }
245
+ else if (contentType == OINOContentType.json) {
246
+ return this.encodeJSON(str);
247
+ }
248
+ else if (contentType == OINOContentType.formdata) {
249
+ return this.encodeFormdata(str);
250
+ }
251
+ else if (contentType == OINOContentType.urlencode) {
252
+ return this.encodeUrlencode(str);
253
+ }
254
+ else if (contentType == OINOContentType.html) {
255
+ return this.encodeHtml(str);
256
+ }
257
+ else {
258
+ return str || "";
259
+ }
260
+ }
261
+ }
@@ -0,0 +1,29 @@
1
+ export { OINOBenchmark } from "./OINOBenchmark.js";
2
+ export { OINOLog, OINOLogLevel, OINOConsoleLog } from "./OINOLog.js";
3
+ export { OINOResult, OINOHttpResult } from "./OINOResult.js";
4
+ export { OINOStr } from "./OINOStr.js";
5
+ export { OINOHtmlTemplate } from "./OINOHtmlTemplate.js";
6
+ /** OINO error message prefix */
7
+ export const OINO_ERROR_PREFIX = "OINO ERROR";
8
+ /** OINO warning message prefix */
9
+ export const OINO_WARNING_PREFIX = "OINO WARNING";
10
+ /** OINO info message prefix */
11
+ export const OINO_INFO_PREFIX = "OINO INFO";
12
+ /** OINO debug message prefix */
13
+ export const OINO_DEBUG_PREFIX = "OINO DEBUG";
14
+ /**
15
+ * Supported content format mime-types
16
+ */
17
+ export var OINOContentType;
18
+ (function (OINOContentType) {
19
+ /** JSON encoded data */
20
+ OINOContentType["json"] = "application/json";
21
+ /** CSV encoded data */
22
+ OINOContentType["csv"] = "text/csv";
23
+ /** Multipart encoded form data */
24
+ OINOContentType["formdata"] = "multipart/form-data";
25
+ /** URL encoded form data */
26
+ OINOContentType["urlencode"] = "application/x-www-form-urlencoded";
27
+ /** HTML encoded data (output only) */
28
+ OINOContentType["html"] = "text/html";
29
+ })(OINOContentType || (OINOContentType = {}));
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Static class for benchmarking functions.
3
+ *
4
+ */
5
+ export declare class OINOBenchmark {
6
+ private static _benchmarkCount;
7
+ private static _benchmarkData;
8
+ private static _benchmarkEnabled;
9
+ private static _benchmarkStart;
10
+ /**
11
+ * Reset benchmark data (but not what is enabled).
12
+ *
13
+ */
14
+ static reset(): void;
15
+ /**
16
+ * Set benchmark names that are enabled.
17
+ *
18
+ * @param module array of those benchmarks that are enabled
19
+ */
20
+ static setEnabled(module: string[]): void;
21
+ /**
22
+ * Start benchmark timing.
23
+ *
24
+ * @param module of the benchmark
25
+ * @param method of the benchmark
26
+ */
27
+ static start(module: string, method: string): void;
28
+ /**
29
+ * Complete benchmark timing
30
+ *
31
+ * @param module of the benchmark
32
+ * @param method of the benchmark
33
+ * @param category optional subcategory of the benchmark
34
+ */
35
+ static end(module: string, method: string, category?: string): number;
36
+ /**
37
+ * Get given benchmark data.
38
+ *
39
+ * @param module of the benchmark
40
+ * @param method of the benchmark
41
+ *
42
+ */
43
+ static get(module: string, method: string): number;
44
+ /**
45
+ * Get all benchmark data.
46
+ *
47
+ */
48
+ static getAll(): number;
49
+ }
@@ -0,0 +1,88 @@
1
+ import { OINOResult, OINOHttpResult } from ".";
2
+ /**
3
+ * Class for rendering HTML from data.
4
+ */
5
+ export declare class OINOHtmlTemplate {
6
+ private _tag;
7
+ private _tagCleanRegex;
8
+ private _variables;
9
+ /** HTML template string */
10
+ template: string;
11
+ /** Cache modified value for template */
12
+ modified: number;
13
+ /** Cache expiration value for template */
14
+ expires: number;
15
+ /**
16
+ * Creates HTML Response from a key-value-pair.
17
+ *
18
+ * @param template template string
19
+ * @param tag tag to identify variables in template
20
+ *
21
+ */
22
+ constructor(template: string, tag?: string);
23
+ /**
24
+ * @returns whether template is empty
25
+ */
26
+ isEmpty(): boolean;
27
+ protected _createHttpResult(html: string, removeUnusedTags: boolean): OINOHttpResult;
28
+ protected _renderHtml(): string;
29
+ /**
30
+ * Clear template variables.
31
+ *
32
+ */
33
+ clearVariables(): void;
34
+ /**
35
+ * Sets template variable from a key-value-pair.
36
+ *
37
+ * @param variable key
38
+ * @param value value
39
+ * @param escapeValue whether to escape value
40
+ *
41
+ */
42
+ setVariableFromValue(variable: string, value: string, escapeValue?: boolean): void;
43
+ /**
44
+ * Sets template variables from object properties.
45
+ *
46
+ * @param object any object
47
+ * @param escapeValue whether to escape value
48
+ *
49
+ */
50
+ setVariableFromProperties(object: any, escapeValue?: boolean): void;
51
+ /**
52
+ * Creates HTML Response from set variables.
53
+ *
54
+ * @param removeUnusedTags whether to remove unused tags
55
+ *
56
+ */
57
+ render(removeUnusedTags?: boolean): OINOHttpResult;
58
+ /**
59
+ * Creates HTML Response from a key-value-pair.
60
+ *
61
+ * @param key key
62
+ * @param value value
63
+ * @param removeUnusedTags whether to remove unused tags
64
+ *
65
+ */
66
+ renderFromKeyValue(key: string, value: string, removeUnusedTags?: boolean): OINOHttpResult;
67
+ /**
68
+ * Creates HTML Response from object properties.
69
+ *
70
+ * @param object object
71
+ * @param removeUnusedTags whether to remove unused tags
72
+ *
73
+ */
74
+ renderFromObject(object: any, removeUnusedTags?: boolean): OINOHttpResult;
75
+ /**
76
+ * Creates HTML Response from API result.
77
+ *
78
+ * @param result OINOResult-object
79
+ * @param removeUnusedTags whether to remove unused tags
80
+ * @param messageSeparator HTML separator for messages
81
+ * @param includeErrorMessages include debug messages in result
82
+ * @param includeWarningMessages include debug messages in result
83
+ * @param includeInfoMessages include debug messages in result
84
+ * @param includeDebugMessages include debug messages in result
85
+ *
86
+ */
87
+ renderFromResult(result: OINOResult, removeUnusedTags: boolean | undefined, messageSeparator: string, includeErrorMessages?: boolean, includeWarningMessages?: boolean, includeInfoMessages?: boolean, includeDebugMessages?: boolean): OINOHttpResult;
88
+ }