netstack.js 1.2.0 → 2.0.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 +11 -5
- package/netstack.js +193 -158
- package/package.json +8 -6
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
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
|
[](#) [](#) [](#) [](#) [](#)
|
|
@@ -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.0.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,10 +42,9 @@
|
|
|
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' },
|
|
@@ -72,151 +52,206 @@
|
|
|
72
52
|
{ name: 'chinese', at: '在', in: '位置', line: '行号' }
|
|
73
53
|
];
|
|
74
54
|
|
|
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
|
-
}
|
|
55
|
+
this.init();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function extend() {
|
|
59
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
60
|
+
for (var key in arguments[i]) {
|
|
61
|
+
if (arguments[i].hasOwnProperty(key)) {
|
|
62
|
+
arguments[0][key] = arguments[i][key];
|
|
106
63
|
}
|
|
107
64
|
}
|
|
65
|
+
}
|
|
66
|
+
return arguments[0];
|
|
67
|
+
}
|
|
108
68
|
|
|
109
|
-
|
|
69
|
+
netStack.prototype.search = function(nameKey, myArray) {
|
|
70
|
+
for (var i = 0; i < myArray.length; i++) {
|
|
71
|
+
if (myArray[i].name === nameKey) {
|
|
72
|
+
return myArray[i];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
};
|
|
110
77
|
|
|
111
|
-
|
|
78
|
+
netStack.prototype.replacer = function(args, at_language) {
|
|
79
|
+
if (args[0].substring(0).match(/(-{3}>)/)) {
|
|
80
|
+
return '\r\n ' + args[0];
|
|
81
|
+
} else if (args[0].substring(0).match(/(-{3})/)) {
|
|
82
|
+
return '\r\n ' + args[0];
|
|
83
|
+
} else {
|
|
84
|
+
return '\r\n ' + at_language + ' ' + args[2] + '(' + args[3] + ')';
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
netStack.prototype.formatException = function(exceptionMessage, at_language) {
|
|
89
|
+
var result = exceptionMessage || '';
|
|
90
|
+
var searchReplaces = [
|
|
91
|
+
{
|
|
92
|
+
find: new RegExp('(-{3}>\\s)(.*?)(?=\\s-{3}|(\\s)+' + at_language + ')', 'g'),
|
|
93
|
+
repl: null
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
find: /(-{3}\s)(.*?)(-{3})/gm,
|
|
97
|
+
repl: null
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
find: new RegExp('(\\s)' + at_language + ' ([^-:]*?)\\((.*?)\\)', 'g'),
|
|
101
|
+
repl: null
|
|
102
|
+
}
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
var self = this;
|
|
106
|
+
searchReplaces.forEach(function(item) {
|
|
107
|
+
if (item.repl == null) {
|
|
108
|
+
result = result.replace(item.find, function() {
|
|
109
|
+
return self.replacer(arguments, at_language);
|
|
110
|
+
});
|
|
111
|
+
} else {
|
|
112
|
+
result = result.replace(item.find, item.repl);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
return result;
|
|
116
|
+
};
|
|
112
117
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
netStack.prototype.init = function() {
|
|
119
|
+
// Get the stacktrace, sanitize it, and split it into lines
|
|
120
|
+
var stacktrace = this.element.textContent,
|
|
121
|
+
sanitizedStack = stacktrace.replace(/</g, '<').replace(/>/g, '>'),
|
|
122
|
+
lines = sanitizedStack.split('\n'),
|
|
123
|
+
lang = '',
|
|
124
|
+
clone = '';
|
|
125
|
+
|
|
126
|
+
// look for the language
|
|
127
|
+
for (var i = 0; i < lines.length; ++i) {
|
|
128
|
+
if (lang === '') {
|
|
129
|
+
var regexes = {
|
|
130
|
+
english: /\s+at .*\)/,
|
|
131
|
+
danish: /\s+ved .*\)/,
|
|
132
|
+
german: /\s+bei .*\)/,
|
|
133
|
+
russian: /\s+в .*\)/,
|
|
134
|
+
chinese: /\s+在 .*\)/
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
for (var key in regexes) {
|
|
138
|
+
if (regexes[key].test(lines[i])) {
|
|
139
|
+
lang = key;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
117
143
|
}
|
|
144
|
+
}
|
|
118
145
|
|
|
119
|
-
|
|
146
|
+
if (lang === '') return;
|
|
120
147
|
|
|
121
|
-
|
|
122
|
-
|
|
148
|
+
var selectedLanguage = this.search(lang, this.languages);
|
|
149
|
+
this.language = selectedLanguage.name;
|
|
123
150
|
|
|
151
|
+
// Pritty print result if is set to true
|
|
152
|
+
if (this.settings.prettyprint) {
|
|
153
|
+
sanitizedStack = this.formatException(sanitizedStack, selectedLanguage.at);
|
|
154
|
+
lines = sanitizedStack.split('\n');
|
|
155
|
+
}
|
|
124
156
|
|
|
125
|
-
|
|
157
|
+
for (var i = 0; i < lines.length; ++i) {
|
|
158
|
+
var li = lines[i],
|
|
159
|
+
hli = new RegExp('(\\S*)' + selectedLanguage.at + ' .*\\)');
|
|
126
160
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
161
|
+
if (hli.test(lines[i])) {
|
|
162
|
+
|
|
163
|
+
// Frame
|
|
164
|
+
var regFrame = new RegExp('(\\S*)' + selectedLanguage.at + ' .*?\\)'),
|
|
165
|
+
partsFrame = String(regFrame.exec(lines[i]));
|
|
130
166
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
167
|
+
if (partsFrame.substring(partsFrame.length - 1) == ',') {
|
|
168
|
+
partsFrame = partsFrame.slice(0, -1);
|
|
169
|
+
}
|
|
134
170
|
|
|
135
|
-
|
|
171
|
+
partsFrame = partsFrame.replace(selectedLanguage.at + ' ', '');
|
|
136
172
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
173
|
+
// Frame -> ParameterList
|
|
174
|
+
var regParamList = /\(.*\)/,
|
|
175
|
+
partsParamList = String(regParamList.exec(lines[i]));
|
|
140
176
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
177
|
+
// Frame -> Params
|
|
178
|
+
var partsParams = partsParamList.replace('(', '').replace(')', ''),
|
|
179
|
+
arrParams = partsParams.split(', '),
|
|
180
|
+
stringParam = '';
|
|
145
181
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
paramName = param[1];
|
|
182
|
+
for (var x = 0; x < arrParams.length; ++x) {
|
|
183
|
+
var param = arrParams[x].split(' '),
|
|
184
|
+
paramType = param[0],
|
|
185
|
+
paramName = param[1];
|
|
151
186
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
187
|
+
if (param[0] !== "null" && param[0] !== '') {
|
|
188
|
+
var theParam = '<span class="' + this.settings.paramType + '">' + paramType + '</span>' + ' ' + '<span class="' + this.settings.paramName + '">' + paramName + '</span>';
|
|
189
|
+
stringParam += String(theParam) + ', ';
|
|
156
190
|
}
|
|
191
|
+
}
|
|
157
192
|
|
|
158
|
-
|
|
159
|
-
|
|
193
|
+
stringParam = stringParam.replace(/,\s*$/, "");
|
|
194
|
+
stringParam = '<span class="' + this.settings.paramsList + '">' + '(' + stringParam + ')' + '</span>';
|
|
160
195
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
196
|
+
// Frame -> Type & Method
|
|
197
|
+
var partsTypeMethod = partsFrame.replace(partsParamList, ''),
|
|
198
|
+
arrTypeMethod = partsTypeMethod.split('.'),
|
|
199
|
+
method = arrTypeMethod.pop(),
|
|
200
|
+
type = partsTypeMethod.replace('.' + method, ''),
|
|
201
|
+
stringTypeMethod = '<span class="' + this.settings.type + '">' + type + '</span>.' + '<span class="' + this.settings.method + '">' + method + '</span>';
|
|
167
202
|
|
|
168
|
-
|
|
169
|
-
|
|
203
|
+
// Construct Frame
|
|
204
|
+
var newPartsFrame = partsFrame.replace(partsParamList, stringParam).replace(partsTypeMethod, stringTypeMethod);
|
|
170
205
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
partsLine = partsLine.replace(':', '').trim();
|
|
206
|
+
// Line
|
|
207
|
+
var regLine = new RegExp('\\b:' + selectedLanguage.line + ' \\d+'),
|
|
208
|
+
partsLine = String(regLine.exec(lines[i]));
|
|
175
209
|
|
|
176
|
-
|
|
210
|
+
partsLine = partsLine.replace(':', '').trim();
|
|
177
211
|
|
|
178
|
-
|
|
179
|
-
var regFile = new RegExp(selectedLanguage['in']+'\\s.*$', 'm'),
|
|
180
|
-
partsFile = String(regFile.exec(fileLi));
|
|
212
|
+
var fileLi = li.replace(selectedLanguage.at + " " + partsFrame, '').trim();
|
|
181
213
|
|
|
182
|
-
|
|
214
|
+
// File => (!) text requires multiline to exec regex, otherwise it will return null.
|
|
215
|
+
var regFile = new RegExp(selectedLanguage.in + '\\s.*$', 'm'),
|
|
216
|
+
partsFile = String(regFile.exec(fileLi));
|
|
183
217
|
|
|
184
|
-
|
|
185
|
-
.replace(partsFile, '<span class="' + settings.file + '">' + partsFile + '</span>')
|
|
186
|
-
.replace(partsLine, '<span class="' + settings.line + '">' + partsLine + '</span>');
|
|
218
|
+
partsFile = partsFile.replace(selectedLanguage.in + ' ', '').replace(':' + partsLine, '').replace('<---', '');
|
|
187
219
|
|
|
188
|
-
|
|
220
|
+
li = li.replace(partsFrame, '<span class="' + this.settings.frame + '">' + newPartsFrame + '</span>')
|
|
221
|
+
.replace(partsFile, '<span class="' + this.settings.file + '">' + partsFile + '</span>')
|
|
222
|
+
.replace(partsLine, '<span class="' + this.settings.line + '">' + partsLine + '</span>');
|
|
223
|
+
|
|
224
|
+
li = li.replace(/</g, '<span><</span>').replace(/>/g, '<span>></span>');
|
|
225
|
+
|
|
226
|
+
if (lines.length - 1 == i) {
|
|
227
|
+
clone += li;
|
|
228
|
+
} else {
|
|
229
|
+
clone += li + '\n';
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
if ((lines[i].trim()).length) {
|
|
233
|
+
li = lines[i];
|
|
189
234
|
|
|
190
235
|
if (lines.length - 1 == i) {
|
|
191
236
|
clone += li;
|
|
192
237
|
} else {
|
|
193
238
|
clone += li + '\n';
|
|
194
239
|
}
|
|
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
240
|
}
|
|
206
241
|
}
|
|
242
|
+
}
|
|
207
243
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
self.getLanguage = function () {
|
|
213
|
-
return selectedLanguage ? selectedLanguage.name : null;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return $(this).html(clone);
|
|
244
|
+
this.element.innerHTML = clone;
|
|
245
|
+
};
|
|
217
246
|
|
|
218
|
-
|
|
247
|
+
netStack.prototype.getJSON = function() {
|
|
248
|
+
return JSON.stringify(this.element.innerHTML);
|
|
249
|
+
};
|
|
219
250
|
|
|
251
|
+
netStack.prototype.getLanguage = function() {
|
|
252
|
+
return this.language;
|
|
220
253
|
};
|
|
221
254
|
|
|
222
|
-
|
|
255
|
+
return netStack;
|
|
256
|
+
|
|
257
|
+
}));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netstack.js",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "A simple and easy
|
|
3
|
+
"version": "2.0.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
|
+
}
|