PageSourceSearch

https://www.fundebug.com/assets/javascripts/stacktracey.js

js fundebug.com collected 2026-10-03 22:49:50 UTC 6,110 bytes, 186 lines download raw bytes

1"use strict";
2
3/*  ------------------------------------------------------------------------ */
4
5const O              = Object,
6      isBrowser      = (typeof window !== 'undefined') && (window.window === window) && window.navigator,
7      nodeRequire    = isBrowser ? null : module.require, // to prevent bundlers from expanding the require call
8      lastOf         = x => x[x.length - 1],
9      nixSlashes     = x => x.replace (/\\/g, '/'),
10      pathRoot       = isBrowser ? window.location.href : (nixSlashes (process.cwd ()) + '/')
11
12/*  ------------------------------------------------------------------------ */
13
14class StackTracey {
15    constructor(input, offset) {
16
17        const originalInput = input
18            , isParseableSyntaxError = input && (input instanceof SyntaxError && !isBrowser)
19
20        /*  new StackTracey ()            */
21
22        if (!input) {
23            input = new Error()
24            offset = (offset === undefined) ? 1 : offset
25        }
26
27        /*  new StackTracey (Error)      */
28
29        if (input instanceof Error) {
30            input = input.stack || ''
31        }
32
33        /*  new StackTracey (string)     */
34
35        if (typeof input === 'string') {
36            input = this.rawParse(input).slice(offset).map(x => this.extractEntryMetadata(x))
37        }
38
39        /*  new StackTracey (array)      */
40
41        if (Array.isArray(input)) {
42
43            if (isParseableSyntaxError) {
44
45                const rawLines = nodeRequire('util').inspect(originalInput).split('\n')
46                    , fileLine = rawLines[0].split(':')
47                    , line = fileLine.pop()
48                    , file = fileLine.join(':')
49
50                if (file) {
51                    input.unshift({
52                        file: nixSlashes(file),
53                        line: line,
54                        column: (rawLines[2] || '').indexOf('^') + 1,
55                        sourceLine: rawLines[1],
56                        callee: '(syntax error)',
57                        syntaxError: true
58                    })
59                }
60            }
61
62            this.items = input
63
64        } else {
65            this.items = []
66        }
67    }
68
69    extractEntryMetadata(e) {
70
71        const decomposedPath = this.decomposePath(e.file || '')
72        const fileRelative = decomposedPath[0]
73        const externalDomain = decomposedPath[1]
74
75        return O.assign(e, {
76
77            calleeShort: e.calleeShort || lastOf((e.callee || '').split('.')),
78            fileRelative: fileRelative,
79            fileShort: this.shortenPath(fileRelative),
80            fileName: lastOf((e.file || '').split('/')),
81            thirdParty: this.isThirdParty(fileRelative, externalDomain) && !e.index,
82            externalDomain: externalDomain
83        })
84    }
85
86    shortenPath(relativePath) {
87        return relativePath.replace(/^node_modules\//, '')
88            .replace(/^webpack\/bootstrap\//, '')
89            .replace(/^__parcel_source_root\//, '')
90    }
91
92    decomposePath(fullPath) {
93        let result = fullPath
94
95        if (isBrowser) result = result.replace(pathRoot, '')
96
97        const externalDomainMatch = result.match(/^(http|https)\:\/\/?([^\/]+)\/(.*)/)
98        const externalDomain = externalDomainMatch ? externalDomainMatch[2] : undefined
99        result = externalDomainMatch ? externalDomainMatch[3] : result
100
101        if (!isBrowser) result = nodeRequire('path').relative(pathRoot, result)
102
103        return [
104            nixSlashes(result).replace(/^.*\:\/\/?\/?/, ''), // cut webpack:/// and webpack:/ things
105            externalDomain
106        ]
107    }
108
109    isThirdParty(relativePath, externalDomain) {
110        return externalDomain ||
111            (relativePath[0] === '~') || // webpack-specific heuristic
112            (relativePath[0] === '/') || // external source
113            (relativePath.indexOf('node_modules') === 0) ||
114            (relativePath.indexOf('webpack/bootstrap') === 0)
115    }
116
117    rawParse(str) {
118
119        const lines = (str || '').split('\n')
120
121        const entries = lines.map(line => {
122
123            line = line.trim()
124
125            let callee, fileLineColumn = [], native, planA, planB
126
127            if ((planA = line.match(/at (.+) \(eval at .+ \((.+)\), .+\)/)) || // eval calls
128                (planA = line.match(/at (.+) \((.+)\)/)) ||
129                ((line.slice(0, 3) !== 'at ') && (planA = line.match(/(.*)@(.*)/)))) {
130
131                callee = planA[1]
132                native = (planA[2] === 'native')
133                fileLineColumn = (planA[2].match(/(.*):(\d+):(\d+)/) ||
134                    planA[2].match(/(.*):(\d+)/) || []).slice(1)
135
136            } else if ((planB = line.match(/^(at\s+)*(.+):(\d+):(\d+)/))) {
137                fileLineColumn = (planB).slice(2)
138
139            } else {
140                return undefined
141            }
142
143            /*  Detect things like Array.reduce
144                TODO: detect more built-in types            */
145
146            if (callee && !fileLineColumn[0]) {
147                const type = callee.split('.')[0]
148                if (type === 'Array') {
149                    native = true
150                }
151            }
152
153            return {
154                beforeParse: line,
155                callee: callee || '',
156                index: isBrowser && (fileLineColumn[0] === window.location.href),
157                native: native || false,
158                file: nixSlashes(fileLineColumn[0] || ''),
159                line: parseInt(fileLineColumn[1] || '', 10) || undefined,
160                column: parseInt(fileLineColumn[2] || '', 10) || undefined
161            }
162        })
163
164        return entries.filter(x => (x !== undefined))
165    }
166}
167
168
169
170
171
172
173/*  Array methods
174    ------------------------------------------------------------------------ */
175
176// ;['map', 'filter', 'slice', 'concat'].forEach (method => {
177//
178//     StackTracey.prototype[method] = function (/*...args */) { // no support for ...args in Node v4 :(
179//         return new StackTracey (this.items[method].apply (this.items, arguments))
180//     }
181// })
182
183/*  ------------------------------------------------------------------------ */
184
185window.StackTracey = StackTracey
186

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.