netstack.js 1.2.0 → 2.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.
- package/README.md +12 -6
- package/netstack.js +195 -158
- package/package.json +8 -6
package/README.md
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|

|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
A simple and easy
|
|
7
|
+
A simple and easy JavaScript library for highlighting .NET stack traces
|
|
8
8
|
|
|
9
9
|
#### Stacktrace - Language support
|
|
10
|
-
[](#) [](#) [](#) [](#) [](#)
|
|
10
|
+
[](#) [](#) [](#) [](#) [](#) [](#)
|
|
11
11
|
|
|
12
12
|
#### Demo
|
|
13
13
|
[](https://elmah.io/tools/stack-trace-formatter/)
|
|
@@ -15,13 +15,19 @@ A simple and easy jQuery plugin for highlighting .NET stack traces
|
|
|
15
15
|
[Stack Trace Formatter - Online pretty print of .NET stack traces](https://elmah.io/tools/stack-trace-formatter/)
|
|
16
16
|
|
|
17
17
|
#### Initialization
|
|
18
|
+
Using a string that represents a CSS selector:
|
|
18
19
|
```javascript
|
|
19
|
-
|
|
20
|
+
const stack = new netStack('.stacktrace');
|
|
21
|
+
```
|
|
22
|
+
Passing an HTMLElement object:
|
|
23
|
+
```javascript
|
|
24
|
+
const stackElement = document.querySelector('.stacktrace');
|
|
25
|
+
const stack = new netStack(stackElement);
|
|
20
26
|
```
|
|
21
27
|
|
|
22
28
|
#### Default values for classes
|
|
23
29
|
```javascript
|
|
24
|
-
|
|
30
|
+
const stack = new netStack('.stacktrace', {
|
|
25
31
|
frame: 'st-frame',
|
|
26
32
|
type: 'st-type',
|
|
27
33
|
method: 'st-method',
|
|
@@ -38,7 +44,7 @@ $('.stacktrace').netStack({
|
|
|
38
44
|
Default: false.
|
|
39
45
|
Pretty prints your stacktrace.
|
|
40
46
|
```javascript
|
|
41
|
-
|
|
47
|
+
const stack = new netStack('.stacktrace', {
|
|
42
48
|
prettyprint: true
|
|
43
49
|
});
|
|
44
50
|
```
|
|
@@ -58,4 +64,4 @@ pre, code {background-color:#333; color: #ffffff;}
|
|
|
58
64
|
---
|
|
59
65
|
### Acknowledgments
|
|
60
66
|
|
|
61
|
-
* [IgoR-NiK](https://github.com/IgoR-NiK)
|
|
67
|
+
* [IgoR-NiK](https://github.com/IgoR-NiK)
|
package/netstack.js
CHANGED
|
@@ -1,57 +1,38 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* netStack
|
|
3
|
-
* A simple and easy
|
|
4
|
-
* License
|
|
5
|
-
* Author
|
|
2
|
+
* netStack v2.1.0
|
|
3
|
+
* A simple and easy JavaScript library for highlighting .NET stack traces
|
|
4
|
+
* License: Apache 2
|
|
5
|
+
* Author: https://elmah.io
|
|
6
6
|
*/
|
|
7
|
-
(function($) {
|
|
8
|
-
'use strict';
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
8
|
+
(function(root, factory) {
|
|
9
|
+
if (typeof define === 'function' && define.amd) {
|
|
10
|
+
// AMD
|
|
11
|
+
define([], factory);
|
|
12
|
+
} else if (typeof module === 'object' && module.exports) {
|
|
13
|
+
// Node, CommonJS-like
|
|
14
|
+
module.exports = factory();
|
|
15
|
+
} else {
|
|
16
|
+
// Browser globals (root is window)
|
|
17
|
+
root.netStack = factory();
|
|
18
|
+
}
|
|
19
|
+
}(typeof self !== 'undefined' ? self : this, function() {
|
|
20
|
+
|
|
21
|
+
function netStack(element, options) {
|
|
22
|
+
if (typeof document !== 'undefined') {
|
|
23
|
+
if (typeof element === 'string') {
|
|
24
|
+
this.element = document.querySelector(element);
|
|
25
|
+
} else if (element instanceof HTMLElement) {
|
|
26
|
+
this.element = element;
|
|
25
27
|
} else {
|
|
26
|
-
|
|
28
|
+
throw new Error('The element parameter must be a selector string or an HTMLElement.');
|
|
27
29
|
}
|
|
30
|
+
} else {
|
|
31
|
+
throw new Error('netStack requires a DOM environment');
|
|
28
32
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
var searchReplaces = [
|
|
33
|
-
{
|
|
34
|
-
find: /(-{3}\s)(.*?)(-{3})/gm,
|
|
35
|
-
repl: null
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
find: new RegExp('(\\s)'+at_language+' ([^-:]*?)\\((.*?)\\)', 'g'),
|
|
39
|
-
repl: null
|
|
40
|
-
}
|
|
41
|
-
]
|
|
42
|
-
searchReplaces.forEach(function(item){
|
|
43
|
-
if(item.repl == null) {
|
|
44
|
-
result = result.replace(item.find, function(){ return replacer(arguments, at_language); });
|
|
45
|
-
} else {
|
|
46
|
-
result = result.replace(item.find, item.repl);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
return result;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
var settings = $.extend({
|
|
53
|
-
|
|
54
|
-
// Default values for classes
|
|
33
|
+
|
|
34
|
+
// Default values for classes
|
|
35
|
+
this.settings = extend({
|
|
55
36
|
prettyprint: false,
|
|
56
37
|
frame: 'st-frame',
|
|
57
38
|
type: 'st-type',
|
|
@@ -61,162 +42,218 @@
|
|
|
61
42
|
paramName: 'st-param-name',
|
|
62
43
|
file: 'st-file',
|
|
63
44
|
line: 'st-line'
|
|
64
|
-
|
|
65
45
|
}, options);
|
|
66
46
|
|
|
67
|
-
|
|
47
|
+
this.languages = [
|
|
68
48
|
{ name: 'english', at: 'at', in: 'in', line: 'line' },
|
|
69
49
|
{ name: 'danish', at: 'ved', in: 'i', line: 'linje' },
|
|
70
50
|
{ name: 'german', at: 'bei', in: 'in', line: 'Zeile' },
|
|
51
|
+
{ name: 'spanish', at: 'en', in: 'en', line: 'línea' },
|
|
71
52
|
{ name: 'russian', at: 'в', in: 'в', line: 'строка' },
|
|
72
53
|
{ name: 'chinese', at: '在', in: '位置', line: '行号' }
|
|
73
54
|
];
|
|
74
55
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
clone = '';
|
|
84
|
-
|
|
85
|
-
// search for language
|
|
86
|
-
for (var i = 0, j = lines.length; i < j; ++i) {
|
|
87
|
-
if(lang === '') {
|
|
88
|
-
var line = lines[i];
|
|
89
|
-
var english = new RegExp('(\\s+)at .*\\)'),
|
|
90
|
-
danish = new RegExp('(\\s+)ved .*\\)'),
|
|
91
|
-
german = new RegExp('(\\s+)bei .*\\)'),
|
|
92
|
-
russian = new RegExp('(\\s+)в .*\\)'),
|
|
93
|
-
chinese = new RegExp('(\\s+)在 .*\\)');
|
|
94
|
-
|
|
95
|
-
if(english.test(lines[i])) {
|
|
96
|
-
lang = 'english';
|
|
97
|
-
} else if (danish.test(lines[i])) {
|
|
98
|
-
lang = 'danish';
|
|
99
|
-
} else if (german.test(lines[i])) {
|
|
100
|
-
lang = 'german';
|
|
101
|
-
} else if (russian.test(lines[i])) {
|
|
102
|
-
lang = 'russian';
|
|
103
|
-
} else if (chinese.test(lines[i])) {
|
|
104
|
-
lang = 'chinese';
|
|
105
|
-
}
|
|
56
|
+
this.init();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function extend() {
|
|
60
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
61
|
+
for (var key in arguments[i]) {
|
|
62
|
+
if (arguments[i].hasOwnProperty(key)) {
|
|
63
|
+
arguments[0][key] = arguments[i][key];
|
|
106
64
|
}
|
|
107
65
|
}
|
|
66
|
+
}
|
|
67
|
+
return arguments[0];
|
|
68
|
+
}
|
|
108
69
|
|
|
109
|
-
|
|
70
|
+
netStack.prototype.search = function(nameKey, myArray) {
|
|
71
|
+
for (var i = 0; i < myArray.length; i++) {
|
|
72
|
+
if (myArray[i].name === nameKey) {
|
|
73
|
+
return myArray[i];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
};
|
|
110
78
|
|
|
111
|
-
|
|
79
|
+
netStack.prototype.replacer = function(args, at_language) {
|
|
80
|
+
if (args[0].substring(0).match(/(-{3}>)/)) {
|
|
81
|
+
return '\r\n ' + args[0];
|
|
82
|
+
} else if (args[0].substring(0).match(/(-{3})/)) {
|
|
83
|
+
return '\r\n ' + args[0];
|
|
84
|
+
} else {
|
|
85
|
+
return '\r\n ' + at_language + ' ' + args[2] + '(' + args[3] + ')';
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
netStack.prototype.formatException = function(exceptionMessage, at_language) {
|
|
90
|
+
var result = exceptionMessage || '';
|
|
91
|
+
var searchReplaces = [
|
|
92
|
+
{
|
|
93
|
+
find: new RegExp('(-{3}>\\s)(.*?)(?=\\s-{3}|(\\s)+' + at_language + ')', 'g'),
|
|
94
|
+
repl: null
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
find: /(-{3}\s)(.*?)(-{3})/gm,
|
|
98
|
+
repl: null
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
find: new RegExp('(\\s)' + at_language + ' ([^-:]*?)\\((.*?)\\)', 'g'),
|
|
102
|
+
repl: null
|
|
103
|
+
}
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
var self = this;
|
|
107
|
+
searchReplaces.forEach(function(item) {
|
|
108
|
+
if (item.repl == null) {
|
|
109
|
+
result = result.replace(item.find, function() {
|
|
110
|
+
return self.replacer(arguments, at_language);
|
|
111
|
+
});
|
|
112
|
+
} else {
|
|
113
|
+
result = result.replace(item.find, item.repl);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
return result;
|
|
117
|
+
};
|
|
112
118
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
119
|
+
netStack.prototype.init = function() {
|
|
120
|
+
// Get the stacktrace, sanitize it, and split it into lines
|
|
121
|
+
var stacktrace = this.element.textContent,
|
|
122
|
+
sanitizedStack = stacktrace.replace(/</g, '<').replace(/>/g, '>'),
|
|
123
|
+
lines = sanitizedStack.split('\n'),
|
|
124
|
+
lang = '',
|
|
125
|
+
clone = '';
|
|
126
|
+
|
|
127
|
+
// look for the language
|
|
128
|
+
for (var i = 0; i < lines.length; ++i) {
|
|
129
|
+
if (lang === '') {
|
|
130
|
+
var regexes = {
|
|
131
|
+
english: /\s+at .*\)/,
|
|
132
|
+
danish: /\s+ved .*\)/,
|
|
133
|
+
german: /\s+bei .*\)/,
|
|
134
|
+
spanish: /\s+en .*\)/,
|
|
135
|
+
russian: /\s+в .*\)/,
|
|
136
|
+
chinese: /\s+在 .*\)/
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
for (var key in regexes) {
|
|
140
|
+
if (regexes[key].test(lines[i])) {
|
|
141
|
+
lang = key;
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
117
145
|
}
|
|
146
|
+
}
|
|
118
147
|
|
|
119
|
-
|
|
148
|
+
if (lang === '') return;
|
|
120
149
|
|
|
121
|
-
|
|
122
|
-
|
|
150
|
+
var selectedLanguage = this.search(lang, this.languages);
|
|
151
|
+
this.language = selectedLanguage.name;
|
|
123
152
|
|
|
153
|
+
// Pritty print result if is set to true
|
|
154
|
+
if (this.settings.prettyprint) {
|
|
155
|
+
sanitizedStack = this.formatException(sanitizedStack, selectedLanguage.at);
|
|
156
|
+
lines = sanitizedStack.split('\n');
|
|
157
|
+
}
|
|
124
158
|
|
|
125
|
-
|
|
159
|
+
for (var i = 0; i < lines.length; ++i) {
|
|
160
|
+
var li = lines[i],
|
|
161
|
+
hli = new RegExp('(\\S*)' + selectedLanguage.at + ' .*\\)');
|
|
126
162
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
163
|
+
if (hli.test(lines[i])) {
|
|
164
|
+
|
|
165
|
+
// Frame
|
|
166
|
+
var regFrame = new RegExp('(\\S*)' + selectedLanguage.at + ' .*?\\)'),
|
|
167
|
+
partsFrame = String(regFrame.exec(lines[i]));
|
|
130
168
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
169
|
+
if (partsFrame.substring(partsFrame.length - 1) == ',') {
|
|
170
|
+
partsFrame = partsFrame.slice(0, -1);
|
|
171
|
+
}
|
|
134
172
|
|
|
135
|
-
|
|
173
|
+
partsFrame = partsFrame.replace(selectedLanguage.at + ' ', '');
|
|
136
174
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
175
|
+
// Frame -> ParameterList
|
|
176
|
+
var regParamList = /\(.*\)/,
|
|
177
|
+
partsParamList = String(regParamList.exec(lines[i]));
|
|
140
178
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
179
|
+
// Frame -> Params
|
|
180
|
+
var partsParams = partsParamList.replace('(', '').replace(')', ''),
|
|
181
|
+
arrParams = partsParams.split(', '),
|
|
182
|
+
stringParam = '';
|
|
145
183
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
paramName = param[1];
|
|
184
|
+
for (var x = 0; x < arrParams.length; ++x) {
|
|
185
|
+
var param = arrParams[x].split(' '),
|
|
186
|
+
paramType = param[0],
|
|
187
|
+
paramName = param[1];
|
|
151
188
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
189
|
+
if (param[0] !== "null" && param[0] !== '') {
|
|
190
|
+
var theParam = '<span class="' + this.settings.paramType + '">' + paramType + '</span>' + ' ' + '<span class="' + this.settings.paramName + '">' + paramName + '</span>';
|
|
191
|
+
stringParam += String(theParam) + ', ';
|
|
156
192
|
}
|
|
193
|
+
}
|
|
157
194
|
|
|
158
|
-
|
|
159
|
-
|
|
195
|
+
stringParam = stringParam.replace(/,\s*$/, "");
|
|
196
|
+
stringParam = '<span class="' + this.settings.paramsList + '">' + '(' + stringParam + ')' + '</span>';
|
|
160
197
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
198
|
+
// Frame -> Type & Method
|
|
199
|
+
var partsTypeMethod = partsFrame.replace(partsParamList, ''),
|
|
200
|
+
arrTypeMethod = partsTypeMethod.split('.'),
|
|
201
|
+
method = arrTypeMethod.pop(),
|
|
202
|
+
type = partsTypeMethod.replace('.' + method, ''),
|
|
203
|
+
stringTypeMethod = '<span class="' + this.settings.type + '">' + type + '</span>.' + '<span class="' + this.settings.method + '">' + method + '</span>';
|
|
167
204
|
|
|
168
|
-
|
|
169
|
-
|
|
205
|
+
// Construct Frame
|
|
206
|
+
var newPartsFrame = partsFrame.replace(partsParamList, stringParam).replace(partsTypeMethod, stringTypeMethod);
|
|
170
207
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
partsLine = partsLine.replace(':', '').trim();
|
|
208
|
+
// Line
|
|
209
|
+
var regLine = new RegExp('\\b:' + selectedLanguage.line + ' \\d+'),
|
|
210
|
+
partsLine = String(regLine.exec(lines[i]));
|
|
175
211
|
|
|
176
|
-
|
|
212
|
+
partsLine = partsLine.replace(':', '').trim();
|
|
177
213
|
|
|
178
|
-
|
|
179
|
-
var regFile = new RegExp(selectedLanguage['in']+'\\s.*$', 'm'),
|
|
180
|
-
partsFile = String(regFile.exec(fileLi));
|
|
214
|
+
var fileLi = li.replace(selectedLanguage.at + " " + partsFrame, '').trim();
|
|
181
215
|
|
|
182
|
-
|
|
216
|
+
// File => (!) text requires multiline to exec regex, otherwise it will return null.
|
|
217
|
+
var regFile = new RegExp(selectedLanguage.in + '\\s.*$', 'm'),
|
|
218
|
+
partsFile = String(regFile.exec(fileLi));
|
|
183
219
|
|
|
184
|
-
|
|
185
|
-
.replace(partsFile, '<span class="' + settings.file + '">' + partsFile + '</span>')
|
|
186
|
-
.replace(partsLine, '<span class="' + settings.line + '">' + partsLine + '</span>');
|
|
220
|
+
partsFile = partsFile.replace(selectedLanguage.in + ' ', '').replace(':' + partsLine, '').replace('<---', '');
|
|
187
221
|
|
|
188
|
-
|
|
222
|
+
li = li.replace(partsFrame, '<span class="' + this.settings.frame + '">' + newPartsFrame + '</span>')
|
|
223
|
+
.replace(partsFile, '<span class="' + this.settings.file + '">' + partsFile + '</span>')
|
|
224
|
+
.replace(partsLine, '<span class="' + this.settings.line + '">' + partsLine + '</span>');
|
|
225
|
+
|
|
226
|
+
li = li.replace(/</g, '<span><</span>').replace(/>/g, '<span>></span>');
|
|
227
|
+
|
|
228
|
+
if (lines.length - 1 == i) {
|
|
229
|
+
clone += li;
|
|
230
|
+
} else {
|
|
231
|
+
clone += li + '\n';
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
if ((lines[i].trim()).length) {
|
|
235
|
+
li = lines[i];
|
|
189
236
|
|
|
190
237
|
if (lines.length - 1 == i) {
|
|
191
238
|
clone += li;
|
|
192
239
|
} else {
|
|
193
240
|
clone += li + '\n';
|
|
194
241
|
}
|
|
195
|
-
} else {
|
|
196
|
-
if((lines[i].trim()).length) {
|
|
197
|
-
li = lines[i];
|
|
198
|
-
|
|
199
|
-
if (lines.length - 1 == i) {
|
|
200
|
-
clone += li;
|
|
201
|
-
} else {
|
|
202
|
-
clone += li + '\n';
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
242
|
}
|
|
206
243
|
}
|
|
244
|
+
}
|
|
207
245
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
self.getLanguage = function () {
|
|
213
|
-
return selectedLanguage ? selectedLanguage.name : null;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return $(this).html(clone);
|
|
246
|
+
this.element.innerHTML = clone;
|
|
247
|
+
};
|
|
217
248
|
|
|
218
|
-
|
|
249
|
+
netStack.prototype.getJSON = function() {
|
|
250
|
+
return JSON.stringify(this.element.innerHTML);
|
|
251
|
+
};
|
|
219
252
|
|
|
253
|
+
netStack.prototype.getLanguage = function() {
|
|
254
|
+
return this.language;
|
|
220
255
|
};
|
|
221
256
|
|
|
222
|
-
|
|
257
|
+
return netStack;
|
|
258
|
+
|
|
259
|
+
}));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netstack.js",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "A simple and easy
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "A simple and easy JavaScript library for highlighting .NET stack traces",
|
|
5
5
|
"main": "netstack.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "mocha"
|
|
@@ -20,15 +20,17 @@
|
|
|
20
20
|
".NET",
|
|
21
21
|
"stacktrace",
|
|
22
22
|
"formatter",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
23
|
+
"JavaScript",
|
|
24
|
+
"library",
|
|
25
25
|
"elmah.io"
|
|
26
26
|
],
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"assert": "^2.0.0",
|
|
29
29
|
"chai": "^4.3.4",
|
|
30
|
-
"jquery": "^3.6.0",
|
|
31
30
|
"jsdom": "^17.0.0",
|
|
32
31
|
"mocha": "^9.1.2"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"gulp": "^5.0.0"
|
|
33
35
|
}
|
|
34
|
-
}
|
|
36
|
+
}
|