@oino-ts/types 0.0.11

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,68 @@
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
+ /**
8
+ * Static class for benchmarking functions.
9
+ *
10
+ */
11
+ export class OINOBenchmark {
12
+
13
+ private static _benchmarkCount:Record<string, number> = {}
14
+ private static _benchmarkData:Record<string, number> = {}
15
+ private static _benchmarkEnabled:Record<string, boolean> = {}
16
+ private static _benchmarkStart:Record<string, number> = {}
17
+
18
+ /**
19
+ * Reset benchmark data (but not what is enabled).
20
+ *
21
+ */
22
+ static reset() {
23
+ this._benchmarkData = {}
24
+ this._benchmarkCount = {}
25
+ }
26
+
27
+ /**
28
+ * Set benchmark names that are enabled.
29
+ *
30
+ * @param names array of those benchmarks that are enabled
31
+ */
32
+ static setEnabled(names:string[]):void {
33
+ this._benchmarkEnabled = {}
34
+ names.forEach(name => {
35
+ this._benchmarkEnabled[name] = true
36
+ });
37
+ }
38
+
39
+ /**
40
+ * Start benchmark timing.
41
+ *
42
+ * @param name of the benchmark
43
+ */
44
+ static start(name:string):void {
45
+ if (this._benchmarkEnabled[name]) {
46
+ if (this._benchmarkCount[name] == undefined) {
47
+ this._benchmarkCount[name] = 0
48
+ this._benchmarkData[name] = 0
49
+ }
50
+ this._benchmarkStart[name] = performance.now()
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Complete benchmark timing
56
+ *
57
+ * @param name of the benchmark
58
+ */
59
+ static end(name:string):number {
60
+ let result:number = 0
61
+ if (this._benchmarkEnabled[name]) {
62
+ this._benchmarkCount[name] += 1
63
+ this._benchmarkData[name] += performance.now() - this._benchmarkStart[name]
64
+ result = this._benchmarkData[name] / this._benchmarkCount[name]
65
+ }
66
+ return result
67
+ }
68
+ }
package/src/OINOLog.ts ADDED
@@ -0,0 +1,160 @@
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
+ /** Logging levels */
8
+ export enum OINOLogLevel {
9
+ /** Debug messages */
10
+ debug=0,
11
+ /** Informational messages */
12
+ info=1,
13
+ /** Warning messages */
14
+ warn=2,
15
+ /** Error messages */
16
+ error=3
17
+ }
18
+
19
+ /**
20
+ * Abstract base class for logging implementations supporting
21
+ * - error, warning, info and debug channels
22
+ * - setting level of logs outputted
23
+ *
24
+ */
25
+
26
+ export abstract class OINOLog {
27
+ protected static _instance:OINOLog
28
+
29
+ protected _logLevel:OINOLogLevel = OINOLogLevel.warn
30
+
31
+ /**
32
+ * Abstract logging method to implement the actual logging operation.
33
+ *
34
+ * @param logLevel level of the log events
35
+ *
36
+ */
37
+ constructor (logLevel:OINOLogLevel = OINOLogLevel.warn) {
38
+ // console.log("OINOLog.constructor: logLevel=" + logLevel)
39
+ this._logLevel = logLevel
40
+ }
41
+
42
+
43
+ /**
44
+ * Abstract logging method to implement the actual logging operation.
45
+ *
46
+ * @param levelStr level string of the log event
47
+ * @param message message of the log event
48
+ * @param data structured data associated with the log event
49
+ *
50
+ */
51
+ protected abstract _writeLog(levelStr:string, message:string, data?:any):void
52
+
53
+ /**
54
+ * Abstract logging method to implement the actual logging operation.
55
+ *
56
+ * @param level level of the log event
57
+ * @param levelStr level string of the log event
58
+ * @param message message of the log event
59
+ * @param data structured data associated with the log event
60
+ *
61
+ */
62
+ protected static _log(level:OINOLogLevel, levelStr:string, message:string, data?:any):void {
63
+ // console.log("_log: level=" + level + ", levelStr=" + levelStr + ", message=" + message + ", data=" + data)
64
+ if ((OINOLog._instance) && (OINOLog._instance._logLevel <= level)) {
65
+ OINOLog._instance?._writeLog(levelStr, message, data)
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Set active logger and log level.
71
+ *
72
+ * @param logger logger instance
73
+ *
74
+ */
75
+ static setLogger(logger: OINOLog) {
76
+ // console.log("setLogger: " + log)
77
+ if (logger) {
78
+ OINOLog._instance = logger
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Set log level.
84
+ *
85
+ * @param logLevel log level to use
86
+ *
87
+ */
88
+ static setLogLevel(logLevel:OINOLogLevel) {
89
+ if (OINOLog._instance) {
90
+ OINOLog._instance._logLevel = logLevel
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Log error event.
96
+ *
97
+ * @param message message of the log event
98
+ * @param data structured data associated with the log event
99
+ *
100
+ */
101
+ static error(message:string, data?:any) {
102
+ OINOLog._log(OINOLogLevel.error, "ERROR", message, data)
103
+ }
104
+
105
+ /**
106
+ * Log warning event.
107
+ *
108
+ * @param message message of the log event
109
+ * @param data structured data associated with the log event
110
+ *
111
+ */
112
+ static warning(message:string, data?:any) {
113
+ OINOLog._log(OINOLogLevel.warn, "WARN", message, data)
114
+ }
115
+
116
+ /**
117
+ * Log info event.
118
+ *
119
+ * @param message message of the log event
120
+ * @param data structured data associated with the log event
121
+ *
122
+ */
123
+ static info(message:string, data?:any) {
124
+ OINOLog._log(OINOLogLevel.info, "INFO", message, data)
125
+ }
126
+
127
+ /**
128
+ * Log debug event.
129
+ *
130
+ * @param message message of the log event
131
+ * @param data structured data associated with the log event
132
+ *
133
+ */
134
+ static debug(message:string, data?:any) {
135
+ OINOLog._log(OINOLogLevel.debug, "DEBUG", message, data)
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Logging implementation based on console.log.
141
+ *
142
+ */
143
+ export class OINOConsoleLog extends OINOLog {
144
+
145
+ /**
146
+ * Constructor of `OINOConsoleLog`
147
+ * @param logLevel logging level
148
+ */
149
+ constructor (logLevel:OINOLogLevel = OINOLogLevel.warn) {
150
+ super(logLevel)
151
+ }
152
+
153
+ protected _writeLog(level:string, message:string, data?:any):void {
154
+ let log:string = "OINOLog " + level + ": " + message
155
+ if (data) {
156
+ log += " " + JSON.stringify(data)
157
+ }
158
+ console.log(log)
159
+ }
160
+ }
@@ -0,0 +1,143 @@
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_DEBUG_PREFIX, OINO_ERROR_PREFIX, OINO_INFO_PREFIX, OINO_WARNING_PREFIX } from ".";
8
+
9
+ /**
10
+ * OINO API request result object with returned data and/or http status code/message and
11
+ * error / warning messages.
12
+ *
13
+ */
14
+ export class OINOResult {
15
+ /** Wheter request was successfully executed */
16
+ success: boolean
17
+
18
+ /** HTTP status code */
19
+ statusCode: number;
20
+
21
+ /** HTTP status message */
22
+ statusMessage: string;
23
+
24
+ /** Error / warning messages */
25
+ messages: string[];
26
+
27
+ /**
28
+ * Constructor of OINOResult.
29
+ *
30
+ */
31
+ constructor () {
32
+ this.success = true
33
+ this.statusCode = 200
34
+ this.statusMessage = "OK"
35
+ this.messages = []
36
+ }
37
+
38
+ /**
39
+ * Set HTTP OK status (does not reset messages).
40
+ *
41
+ */
42
+ setOk() {
43
+ this.success = true
44
+ this.statusCode = 200
45
+ this.statusMessage = "OK"
46
+ }
47
+
48
+ /**
49
+ * Set HTTP error status using given code and message.
50
+ *
51
+ * @param statusCode HTTP status code
52
+ * @param statusMessage HTTP status message
53
+ * @param operation operation where error occured
54
+ *
55
+ */
56
+ setError(statusCode:number, statusMessage:string, operation:string) {
57
+ this.success = false
58
+ this.statusCode = statusCode
59
+ if (this.statusMessage != "OK") {
60
+ this.messages.push(this.statusMessage) // latest error becomes status, but if there was something non-trivial, add it to the messages
61
+ }
62
+ if (statusMessage.startsWith(OINO_ERROR_PREFIX)) {
63
+ this.statusMessage = statusMessage
64
+ } else {
65
+ this.statusMessage = OINO_ERROR_PREFIX + " (" + operation + "): " + statusMessage
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Add warning message.
71
+ *
72
+ * @param message HTTP status message
73
+ * @param operation operation where warning occured
74
+ *
75
+ */
76
+ addWarning(message:string, operation:string) {
77
+ message = message.trim()
78
+ if (message) {
79
+ this.messages.push(OINO_WARNING_PREFIX + " (" + operation + "): " + message)
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Add info message.
85
+ *
86
+ * @param message HTTP status message
87
+ * @param operation operation where info occured
88
+ *
89
+ */
90
+ addInfo(message:string, operation:string) {
91
+ message = message.trim()
92
+ if (message) {
93
+ this.messages.push(OINO_INFO_PREFIX + " (" + operation + "): " + message)
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Add debug message.
99
+ *
100
+ * @param message HTTP status message
101
+ * @param operation operation where debug occured
102
+ *
103
+ */
104
+ addDebug(message:string, operation:string) {
105
+ message = message.trim()
106
+ if (message) {
107
+ this.messages.push(OINO_DEBUG_PREFIX + " (" + operation + "): " + message)
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Copy given messages to HTTP headers.
113
+ *
114
+ * @param headers HTTP headers
115
+ * @param copyErrors wether error messages should be copied (default true)
116
+ * @param copyWarnings wether warning messages should be copied (default false)
117
+ * @param copyInfos wether info messages should be copied (default false)
118
+ * @param copyDebug wether debug messages should be copied (default false)
119
+ *
120
+ */
121
+ copyMessagesToHeaders(headers:Headers, copyErrors:boolean = true, copyWarnings:boolean = false, copyInfos:boolean = false, copyDebug:boolean = false) {
122
+ let j=1
123
+ for(let i=0; i<this.messages.length; i++) {
124
+ const message = this.messages[i].replaceAll("\r", " ").replaceAll("\n", " ")
125
+ if (copyErrors && message.startsWith(OINO_ERROR_PREFIX)) {
126
+ headers.append('X-OINO-MESSAGE-'+j, message)
127
+ j++
128
+ }
129
+ if (copyWarnings && message.startsWith(OINO_WARNING_PREFIX)) {
130
+ headers.append('X-OINO-MESSAGE-'+j, message)
131
+ j++
132
+ }
133
+ if (copyInfos && message.startsWith(OINO_INFO_PREFIX)) {
134
+ headers.append('X-OINO-MESSAGE-'+j, message)
135
+ j++
136
+ }
137
+ if (copyDebug && message.startsWith(OINO_DEBUG_PREFIX)) {
138
+ headers.append('X-OINO-MESSAGE-'+j, message)
139
+ j++
140
+ }
141
+ }
142
+ }
143
+ }
package/src/OINOStr.ts ADDED
@@ -0,0 +1,254 @@
1
+ import { OINOContentType } from "."
2
+
3
+ /** Callback to filter data fields */
4
+ export type OINOStrEncoder = (str:string) => string
5
+
6
+ /**
7
+ * Static class string utilities.
8
+ *
9
+ */
10
+ export class OINOStr {
11
+
12
+ /**
13
+ * Split string by the top level of the given type of brackets.
14
+ * E.g. splitByBrackets("a(bc(d))ef(gh)kl", true, true, '(', ')') would return ["a", "bc(d)", "ef", "gh", "kl"]
15
+ *
16
+ * @param str string to split
17
+ * @param includePartsBetweenBlocks whether to include strings between top level brackets
18
+ * @param includeTrailingUnescapedBlock whether to include final block that is missing necessary end brackets
19
+ * @param startBracket starting bracket, e.g. '('
20
+ * @param endBracket ending bracket, e.g. ')'
21
+ *
22
+ */
23
+ static splitByBrackets(str:string, includePartsBetweenBlocks:boolean, includeTrailingUnescapedBlock:boolean, startBracket:string, endBracket:string):string[] {
24
+
25
+ let result:string[] = []
26
+ let parenthesis_count:number = 0
27
+ let start:number = 0
28
+ let end:number = 0
29
+ while (end<str.length) {
30
+ if (str[end] == startBracket) {
31
+ if (parenthesis_count == 0) {
32
+ if ((end > start) && includePartsBetweenBlocks) { // there is some first level string to add to result
33
+ result.push(str.substring(start, end))
34
+ }
35
+ start = end+1
36
+ }
37
+ parenthesis_count++
38
+
39
+ } else if (str[end] == endBracket) {
40
+ parenthesis_count--
41
+ if (parenthesis_count == 0) {
42
+ if (end >= start) {
43
+ result.push(str.substring(start, end))
44
+ }
45
+ start = end+1
46
+ }
47
+ }
48
+ end++
49
+ }
50
+ 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)
51
+ result.push(str.substring(start, end)) // i == str.length
52
+ }
53
+ return result
54
+ }
55
+
56
+ /**
57
+ * Split string by delimeter excluding delimeters inside given brackets.
58
+ * E.g. splitExcludingBrackets("a,(bc,d),ef,(g,h),k", ',', '(', ')') would return ["a", "bc,d", "ef", "g,h", "k"]
59
+ *
60
+ * @param str string to split
61
+ * @param delimeter string to use as delimeter
62
+ * @param startBracket starting bracket, e.g. '('
63
+ * @param endBracket ending bracket, e.g. ')'
64
+ */
65
+ static splitExcludingBrackets(str:string, delimeter:string, startBracket:string, endBracket:string):string[] {
66
+ let result:string[] = []
67
+ let bracket_level:number = 0
68
+ let start:number = 0
69
+ let end:number = 0
70
+ while (end<str.length) {
71
+ if (str[end] == startBracket) {
72
+ bracket_level++
73
+ } else if (str[end] == endBracket) {
74
+ bracket_level--
75
+ } else if ((str[end] == delimeter) && (bracket_level==0)) { // only delimeters at top level will break
76
+ result.push(str.substring(start, end))
77
+ start = end+1
78
+ }
79
+ end++
80
+ }
81
+ if (end > start) {
82
+ result.push(str.substring(start, end)) // i == str.length
83
+ }
84
+ return result
85
+ }
86
+
87
+ /**
88
+ * Encode OINO serialized strings as valid JSON.
89
+ *
90
+ * @param str string to encode
91
+ * @param valueType wether it is a value type
92
+ */
93
+ static encodeJSON(str:string|null|undefined, valueType:boolean = false):string {
94
+ if (str === undefined) { // no undefined literal in JSON
95
+ return "null"
96
+ } else if (str === null) {
97
+ return "null"
98
+ } else {
99
+ if (valueType) {
100
+ return str
101
+ } else {
102
+ return JSON.stringify(str)
103
+ }
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Decode JSON string as OINO serialization.
109
+ *
110
+ * @param str string to decode
111
+ */
112
+ static decodeJSON(str:string):string|null|undefined {
113
+ return str // JSON parsing using JS methods, no need to decode anything
114
+ }
115
+
116
+ /**
117
+ * Encode OINO serialized strings as valid CSV.
118
+ *
119
+ * @param str string to encode
120
+ */
121
+ static encodeCSV(str:string|null|undefined):string {
122
+ if (str === undefined) {
123
+ return ""
124
+ } else if (str === null) {
125
+ return "null"
126
+ } else {
127
+ return "\"" + str.replaceAll("\"", "\"\"") + "\"";
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Decode CSV string as OINO serialization.
133
+ *
134
+ * @param str string to decode
135
+ */
136
+ static decodeCSV(str:string):string|null|undefined {
137
+ return str.replaceAll("\"\"", "\"")
138
+ }
139
+
140
+ /**
141
+ * Encode OINO serialized strings as valid Formdata.
142
+ *
143
+ * @param str string to encode
144
+ */
145
+ static encodeFormdata(str:string|null|undefined):string {
146
+ if (str === undefined) {
147
+ return ""
148
+ } else if (str === null) {
149
+ return ""
150
+ } else {
151
+ return str
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Decode Formdata string as OINO serialization.
157
+ *
158
+ * @param str string to decode
159
+ */
160
+ static decodeFormdata(str:string):string|null|undefined {
161
+ return str
162
+ }
163
+ /**
164
+ * Encode OINO serialized strings as valid Urlencode.
165
+ *
166
+ * @param str string to encode
167
+ */
168
+ static encodeUrlencode(str:string|null|undefined):string {
169
+ if (str === undefined) {
170
+ return ""
171
+ } else if (str === null) {
172
+ return "null"
173
+ } else {
174
+ return encodeURIComponent(str)
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Decode Urlencode string as OINO serialization.
180
+ *
181
+ * @param str string to decode
182
+ */
183
+ static decodeUrlencode(str:string):string|null|undefined {
184
+ return decodeURIComponent(str)
185
+ }
186
+
187
+ /**
188
+ * Encode OINO serialized strings as valid HTML content.
189
+ *
190
+ * @param str string to encode
191
+ */
192
+ static encodeHtml(str:string|null|undefined):string {
193
+ if (str === undefined) {
194
+ return ""
195
+ } else if (str === null) {
196
+ return ""
197
+ } else {
198
+ return str.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll("'", '&#039;')
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Decode HTML string as OINO serialization.
204
+ *
205
+ * @param str string to encode
206
+ */
207
+ static decodeHtml(str:string):string|null|undefined {
208
+ return str.replaceAll('&amp;', '&').replaceAll('&lt;', '<').replaceAll('&gt;', '>').replaceAll('&quot;', '"').replaceAll('&#039;', "'")
209
+ }
210
+ /**
211
+ * Decode content type formatted string as OINO serialization.
212
+ *
213
+ * @param str string to decode
214
+ * @param contentType content type for serialization
215
+ *
216
+ */
217
+ static decode(str:string, contentType:OINOContentType):string|null|undefined {
218
+ if (contentType == OINOContentType.csv) {
219
+ return this.decodeCSV(str)
220
+ } else if (contentType == OINOContentType.json) {
221
+ return this.decodeJSON(str)
222
+ } else if (contentType == OINOContentType.formdata) {
223
+ return this.decodeFormdata(str)
224
+ } else if (contentType == OINOContentType.urlencode) {
225
+ return this.decodeUrlencode(str)
226
+ } else if (contentType == OINOContentType.html) {
227
+ return str
228
+ } else {
229
+ return str
230
+ }
231
+ }
232
+ /**
233
+ * Encode OINO serialized string to the content type formatting.
234
+ *
235
+ * @param str string to encode
236
+ * @param contentType content type for serialization
237
+ *
238
+ */
239
+ static encode(str:string|null|undefined, contentType:OINOContentType):string {
240
+ if (contentType == OINOContentType.csv) {
241
+ return this.encodeCSV(str)
242
+ } else if (contentType == OINOContentType.json) {
243
+ return this.encodeJSON(str)
244
+ } else if (contentType == OINOContentType.formdata) {
245
+ return this.encodeFormdata(str)
246
+ } else if (contentType == OINOContentType.urlencode) {
247
+ return this.encodeUrlencode(str)
248
+ } else if (contentType == OINOContentType.html) {
249
+ return this.encodeHtml(str)
250
+ } else {
251
+ return str || ""
252
+ }
253
+ }
254
+ }
package/src/index.ts ADDED
@@ -0,0 +1,28 @@
1
+ export { OINOBenchmark } from "./OINOBenchmark.js"
2
+ export { OINOLog, OINOLogLevel, OINOConsoleLog } from "./OINOLog.js"
3
+ export { OINOResult } from "./OINOResult.js"
4
+ export { OINOStr } from "./OINOStr.js"
5
+
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
+ export enum OINOContentType {
17
+ /** JSON encoded data */
18
+ json='application/json',
19
+ /** CSV encoded data */
20
+ csv='text/csv',
21
+ /** Multipart encoded form data */
22
+ formdata='multipart/form-data',
23
+ /** URL encoded form data */
24
+ urlencode='application/x-www-form-urlencoded',
25
+ /** HTML encoded data (output only) */
26
+ html='text/html'
27
+ }
28
+