diff options
| author | akiyamn | 2023-09-24 23:22:21 +1000 |
|---|---|---|
| committer | akiyamn | 2023-09-24 23:22:21 +1000 |
| commit | 4e87195739f2a5d9a05451b48773c8afdc680765 (patch) | |
| tree | 9cba501844a4a11dcbdffc4050ed8189561c55ed /node_modules/stacktracey | |
| download | price-tracker-worker-4e87195739f2a5d9a05451b48773c8afdc680765.tar.gz price-tracker-worker-4e87195739f2a5d9a05451b48773c8afdc680765.zip | |
Initial commit (by create-cloudflare CLI)
Diffstat (limited to 'node_modules/stacktracey')
| -rw-r--r-- | node_modules/stacktracey/.eslintrc | 6 | ||||
| -rw-r--r-- | node_modules/stacktracey/.gitattributes | 0 | ||||
| -rw-r--r-- | node_modules/stacktracey/.travis.yml | 24 | ||||
| -rw-r--r-- | node_modules/stacktracey/CHANGELOG.md | 16 | ||||
| -rw-r--r-- | node_modules/stacktracey/LICENSE | 24 | ||||
| -rw-r--r-- | node_modules/stacktracey/README.md | 281 | ||||
| -rw-r--r-- | node_modules/stacktracey/appveyor.yml | 19 | ||||
| -rw-r--r-- | node_modules/stacktracey/impl/partition.js | 22 | ||||
| -rw-r--r-- | node_modules/stacktracey/package.json | 87 | ||||
| -rw-r--r-- | node_modules/stacktracey/stacktracey.d.ts | 88 | ||||
| -rw-r--r-- | node_modules/stacktracey/stacktracey.js | 339 | ||||
| -rw-r--r-- | node_modules/stacktracey/test.js | 356 | ||||
| -rw-r--r-- | node_modules/stacktracey/test_files/mkay.js | 4 | ||||
| -rw-r--r-- | node_modules/stacktracey/test_files/mkay.uglified.js | 2 | ||||
| -rw-r--r-- | node_modules/stacktracey/test_files/mkay.uglified.js.map | 1 | ||||
| -rw-r--r-- | node_modules/stacktracey/test_files/syntax_error.js | 2 |
16 files changed, 1271 insertions, 0 deletions
diff --git a/node_modules/stacktracey/.eslintrc b/node_modules/stacktracey/.eslintrc new file mode 100644 index 0000000..955b07d --- /dev/null +++ b/node_modules/stacktracey/.eslintrc @@ -0,0 +1,6 @@ +{ + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "script" + } +}
\ No newline at end of file diff --git a/node_modules/stacktracey/.gitattributes b/node_modules/stacktracey/.gitattributes new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/node_modules/stacktracey/.gitattributes diff --git a/node_modules/stacktracey/.travis.yml b/node_modules/stacktracey/.travis.yml new file mode 100644 index 0000000..90f2741 --- /dev/null +++ b/node_modules/stacktracey/.travis.yml @@ -0,0 +1,24 @@ +language: node_js +node_js: +- '8' +script: +- set -e +- npm run test +- npm run coveralls +# after_success: +# - git config --global user.email "travis@travis-ci.org" +# - git config --global user.name "Travis CI" +# - npm config set git-tag-version=false +# - NPM_VERSION=$(npm version patch) +# - git commit -a -m "${NPM_VERSION:1}" -m "[ci skip]" +# - git remote remove origin +# - git remote add origin https://${GITHUB_TOKEN}@github.com/xpl/stacktracey.git +# - git push origin HEAD:master +# deploy: +# provider: npm +# email: rocket.mind@gmail.com +# api_key: +# secure: n+nrZcPygki2A9RnfNCT/9pkx7cpr+C45B1lZqHBVe6G+7ZxPCVFnAsf9VmZJW/cDxQQ6UFnFCv6O3DfLECgkG5c8m1JE+rX7pxAr8Ra2IPqdaQF7AtN4gmaaGvsBiPN+kEnDWZhidfa7Se28q4wMHd+OGk0RKBcye9PCnQZDonAFkqjaAOFJQ/0l8DtsZ2A2IFCcxUJxVvsx3t0JzxLcCvYRgODeNAfEdintxHixzM/l1+oZ0Mge5upr5SHQFNTjduMjsEWLqoAJb9m9237mNLGiD/DI/nbqGqj0neZYBXcahR2vHxAn/RAL51BLXbBaoyzcGVyAcRBJZJg/E+55u27jKD4ivQoUglJPBkHoV77MbRSQ6hIW2/Fuf6XecFxfgnu3aIRPelAB/B4vfoqkA4QL0FGE/bBr/3bBHgigLQeHB6IiFrcIK0UAgRxEHykOD77m1OcPuYQoorsVdihjzAQ4qD8tck6R9d4sy5lAmthN563GCReyGQgoUnFpcOJXcQSluyUKORvnJ94Zal7X1i/VcPTu9WP7QL3rM3K3fokcbhWp5NaxmfiU69MmvYbKS5yrV4x9qp8fkU0Er49qEHZIqBg7fbm4nlGTUGgeIJtn7VLPbT1JxTz9E2rLLGuE91HvFbr8IRS7EaHsVYS360BDL6TZ9v97iXfk/jeuWc= +env: + global: + secure: UXE5LWFM8sVrkQeBq8Ybn1I8M+e1tN23wVtngoDxWcMOpmIUmHvHuYCLCm7yuKhnLtjpxnmTl+yJyvrluQUZqXxti71s17ZcXXAuEe4I3thp1VNEVFYlPDjTntQHQYn4BZc8UBsojlBbUZvx3XzDxdIQ/dQPr2rbC7Es33VHkeZez7pZFygDRhwRHED5W0bO7kAyWEfGoWTpsM7keztEyAAZ1uWz8LZ5TTSiGBDGkn09KRPcNEgjwNvl8dYwzCvfZ25DmZjkwstioRGJkvJXD8lOnr4adDsuA63Lbz/8F7h1uBtoiln0g7yQ0wKvc+7HOeY4WXA81COLBT7QuH11EuMxjn5RhwkMSnSOjzWkEDZ14CaHQB+QuCK87amb0pBDrx9Ykgd4pDbUwv2gX87KjXDXD5FGjfXzoJ7FD1dGmrgncgeXna8ln9Kyc3zUVQTPlrpFtjGbMyq/9VIVOmyGlTwj50XWGx62fM/3UDQot3urjvywnv3RcPKDw3YjoUHpZk/YQKLpOVmUucnUX1CuUv0s7npwttSrUSq5mZ1qRbCIwy6na1cbql9VX0nktxaSyl6GDNxtwr7uLQeSmOj63ff7QbSO47lTS+EqEF0NGiemXS9rCfdNdrfc/9EsKX99aQuiHHZGnggAuGCeGJwAi2EWpA9e6N9mqYaWwREQv1Q= diff --git a/node_modules/stacktracey/CHANGELOG.md b/node_modules/stacktracey/CHANGELOG.md new file mode 100644 index 0000000..411d94f --- /dev/null +++ b/node_modules/stacktracey/CHANGELOG.md @@ -0,0 +1,16 @@ +# Version 2.0 (with breaking changes) + +- Added asynchronous methods, `withSourcesAsync` and `cleanAsync`. + +- All property accessors like `.clean` are now methods (e.g. `.clean ()`) for consistency reasons + +- `.pretty` now `.asTable (opts?: { maxColumnWidths:? { callee, file, sourceLine } })` + + - Also, it does not call `withSources` automatically — you need to call it explicitly. + +- It is no longer `extends Array` due to non-working user subclassing with Babel ES5 + - Use `.items` to access original array + +- No static methods and properties (except public `.locationsEqual` helper) + - `.isThirdParty` is now just an overrideable method + - `.maxColumnWidths` is an overrideable method + a configuration option passed to `asTable ()` method diff --git a/node_modules/stacktracey/LICENSE b/node_modules/stacktracey/LICENSE new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/node_modules/stacktracey/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org/> diff --git a/node_modules/stacktracey/README.md b/node_modules/stacktracey/README.md new file mode 100644 index 0000000..50877cf --- /dev/null +++ b/node_modules/stacktracey/README.md @@ -0,0 +1,281 @@ +# StackTracey + +[](https://travis-ci.org/xpl/stacktracey) [](https://ci.appveyor.com/project/xpl/stacktracey) [](https://coveralls.io/github/xpl/stacktracey) [](http://npmjs.com/package/stacktracey) [](https://scrutinizer-ci.com/g/xpl/stacktracey/?branch=master) [](https://david-dm.org/xpl/stacktracey) + +Parses call stacks. Reads sources. Clean & filtered output. Sourcemaps. Node & browsers. + +## Why + +- [x] Simple +- [x] Works in Node and browsers, \*nix and Windows +- [x] Allows hiding library calls / ad-hoc exclusion (via `// @hide` marker) +- [x] Provides source text for call locations +- [x] Fetches sources (via [get-source](https://github.com/xpl/get-source)) +- [x] Supports both asynchronous and synchronous interfaces (works even in browsers) +- [x] Full sourcemap support +- [x] Extracts useful information from `SyntaxError` instances +- [x] [Pretty printing](https://github.com/xpl/stacktracey/#pretty-printing) + <img width="898" alt="screen shot 2017-09-27 at 16 53 46" src="https://user-images.githubusercontent.com/1707/30917345-79899004-a3a4-11e7-8d48-e217e2d5e2cd.png"> + +## What For + +- [Error overlay UIs](https://github.com/xpl/panic-overlay/#how-it-looks) for easier front-end development +- [Better error reporting](https://github.com/xpl/ololog#pretty-printing-error-instances) for Node projects +- [Advanced logging](https://github.com/xpl/ololog#displaying-call-location) (displaying call locations) +- Assertion printing + +## How To + +```bash +npm install stacktracey +``` + +```javascript +import StackTracey from 'stacktracey' +``` + +Captures the current call stack: + +```javascript +stack = new StackTracey () // captures the current call stack +``` + +Parses stacks from an `Error` object: + +```javascript +stack = new StackTracey (error) +stack = new StackTracey (error.stack) // ...or from raw string +``` + +Stores parsed data in `.items`: + +```javascript +stack.items.length // num entries +stack.items[0] // top +``` + +...where each item exposes: + +```javascript +{ + beforeParse: <original text>, + callee: <function name>, + calleeShort: <shortened function name>, + file: <full path to file>, // e.g. /Users/john/my_project/node_modules/foobar/main.js + fileRelative: <relative path to file>, // e.g. node_modules/foobar/main.js + fileShort: <short path to file>, // e.g. foobar/main.js + fileName: <file name>, // e.g. main.js + line: <line number>, // starts from 1 + column: <column number>, // starts from 1 + + index: /* true if occured in HTML file at index page */, + native: /* true if occured in native browser code */, + thirdParty: /* true if occured in library code */, + hide: /* true if marked as hidden by "// @hide" tag */, + syntaxError: /* true if generated from a SyntaxError instance */ +} +``` + +Accessing sources (**synchronously**, use with caution in browsers): + +```javascript +stack = stack.withSources () // returns a copy of stack with all items supplied with sources +top = stack.items[0] // top item +``` + +Accessing sources (**asynchronously**, preferred method in browsers): + +```javascript +stack = await stack.withSourcesAsync () // returns a copy of stack with all items supplied with sources +top = stack.items[0] // top item +``` + +...or: + +```javascript +top = stack.withSourceAt (0) // supplies source for an individiual item (by index) +``` +```javascript +top = await stack.withSourceAsyncAt (0) // supplies source for an individiual item (by index) +``` + +...or: + +```javascript +top = stack.withSource (stack.items[0]) // supplies source for an individiual item +``` +```javascript +top = await stack.withSourceAsync (stack.items[0]) // supplies source for an individiual item +``` + +The returned items contain the following additional fields (already mapped through sourcemaps): + +```javascript +{ + ... // all the previously described fields + + line: <original line number>, + column: <original column number>, + sourceFile: <original source file object>, + sourceLine: <original source line text> +} +``` + +To learn about the `sourceFile` object, read the [get-source](https://github.com/xpl/get-source#get-source) docs. + +## Cleaning Output + +Synchronously (use with caution in browsers): + +```javascript +stack = stack.clean () +``` + +...or (asynchronously): + +```javascript +stack = await stack.cleanAsync () +``` + +It does the following: + +1. Reads sources (if available) +2. Excludes locations marked with the `isThirdParty` flag (library calls) +3. Excludes locations marked with a `// @hide` comment (user defined exclusion) +4. Merges repeated lines (via the `.mergeRepeatedLines`) + +You can customize its behavior by overriding the `isClean (entry, index)` predicate. + +## Custom `isThirdParty` Predicate + +You can override the `isThirdParty` behavior by subclassing `StackTracey`: + +```javascript +class MyStackTracey extends StackTracey { + + isThirdParty (path, externalDomain) { // you can use externalDomain to include traces from libs from other domains + return (super.isThirdParty (path) // include default behavior + || path.includes ('my-lib')) // paths including 'my-lib' will be marked as thirdParty + && !path.includes ('jquery') // jquery paths won't be marked as thirdParty + } +} + +... + +const stack = new MyStackTracey (error).withSources () +``` + +## Pretty Printing + +```javascript +const prettyPrintedString = new StackTracey (error).withSources ().asTable () +``` +```javascript +const prettyPrintedString = (await new StackTracey (error).withSourcesAsync ()).asTable () // asynchronous version +``` + +...or (for pretty printing cleaned output): + +```javascript +const prettyPrintedString = new StackTracey (error).clean ().asTable () +``` +```javascript +const prettyPrintedString = (await new StackTracey (error).cleanAsync ()).asTable () // asynchronous version +``` + +It produces a nice compact table layout (thanks to [`as-table`](https://github.com/xpl/as-table)), supplied with source lines (if available): + +``` +at shouldBeVisibleInStackTrace test.js:25 const shouldBeVisibleInStackTrace = () => new StackTracey () +at it test.js:100 const stack = shouldBeVisibleInStackTrace () +at callFn mocha/lib/runnable.js:326 var result = fn.call(ctx); +at run mocha/lib/runnable.js:319 callFn(this.fn); +at runTest mocha/lib/runner.js:422 test.run(fn); +at mocha/lib/runner.js:528 self.runTest(function(err) { +at next mocha/lib/runner.js:342 return fn(); +at mocha/lib/runner.js:352 next(suites.pop()); +at next mocha/lib/runner.js:284 return fn(); +at <anonymous> mocha/lib/runner.js:320 next(0); +``` + +If you find your pretty printed tables undesirably trimmed (or maybe too long to fit in the line), you can provide custom column widths when calling `asTable` (...or, alternatively, by overriding `maxColumnWidths ()` method): + +```javascript +stack.asTable ({ + callee: 30, + file: 60, + sourceLine: 80 +}) +``` + +## Using As A Custom Exception Printer In Node + +You can even replace the default NodeJS exception printer with this! This is how you can do it: + +```javascript +process.on ('uncaughtException', e => { /* print the stack here */ }) +process.on ('unhandledRejection', e => { /* print the stack here */ }) +``` + +But the most simple way to achieve that is to use the [`ololog`](https://github.com/xpl/ololog/blob/master/README.md) library (that is built upon StackTracey and several other handy libraries coded by me). Check it out, [it's pretty awesome and will blow your brains out](https://github.com/xpl/ololog/blob/master/README.md) :) + +```javascript +const log = require ('ololog').handleNodeErrors () + +// you can also print Errors by simply passing them to the log() function +``` + +<img width="1066" alt="screen shot 2018-05-11 at 19 51 03" src="https://user-images.githubusercontent.com/1707/39936393-ffd529c2-5554-11e8-80f8-eff1229017c4.png"> + +## Parsing `SyntaxError` instances + +For example, when trying to `require` a file named `test_files/syntax_error.js`: + +```javascript +// next line contains a syntax error (not a valid JavaScript) +foo->bar () +``` + +...the pretty printed call stack for the error thrown would be something like: + +``` +at (syntax error) test_files/syntax_error.js:2 foo->bar () +at it test.js:184 try { require ('./test_files/syntax_error.js') } +at runCallback timers.js:781 +at tryOnImmediate timers.js:743 +at processImmediate [as _immediat timers.js:714 +``` + +...where the first line is generated from parsing the raw output from the `util.inspect` call in Node. Unfortunately, this won't work in older versions of Node (v4 and below) as these versions can't provide any meaningful information for a `SyntaxError` instance. + +## Array Methods + +All StackTracey instances expose `map`, `filter`, `concat` and `slice` methods. These methods will return mapped, filtered, joined, reversed and sliced `StackTracey` instances, respectively: + +```javascript +s = new StackTracey ().slice (1).filter (x => !x.thirdParty) // current stack shifted by 1 and cleaned from library calls + +s instanceof StackTracey // true +``` + +## Extra Stuff + +You can compare two locations via this predicate (tests `file`, `line` and `column` for equality): + +```javascript +StackTracey.locationsEqual (a, b) +``` + +To force-reload the sources, you can invalidate the global source cache: + +```javascript +StackTracey.resetCache () +``` + +## Projects That Use StackTracey + +- [Ololog](https://github.com/xpl/ololog) — a better `console.log` for the log-driven debugging junkies! +- [CCXT](https://github.com/ccxt-dev/ccxt) — a cryptocurrency trading library that supports 130+ exchanges +- [pnpm](https://github.com/pnpm/pnpm) — a fast, disk space efficient package manager (faster than npm and Yarn!) +- [panic-overlay](https://github.com/xpl/panic-overlay/) — a lightweight standalone alternative to `react-error-overlay` + diff --git a/node_modules/stacktracey/appveyor.yml b/node_modules/stacktracey/appveyor.yml new file mode 100644 index 0000000..0209ff1 --- /dev/null +++ b/node_modules/stacktracey/appveyor.yml @@ -0,0 +1,19 @@ +environment: + matrix: + - nodejs_version: '8' +install: + - ps: Install-Product node $env:nodejs_version + - set CI=true + - npm install --global npm@latest + - set PATH=%APPDATA%\npm;%PATH% + - npm install +matrix: + fast_finish: true +build: off +shallow_clone: true +test_script: + - node --version + - npm --version + - npm run test-no-coverage +cache: +- '%APPDATA%\npm-cache' diff --git a/node_modules/stacktracey/impl/partition.js b/node_modules/stacktracey/impl/partition.js new file mode 100644 index 0000000..bb130b5 --- /dev/null +++ b/node_modules/stacktracey/impl/partition.js @@ -0,0 +1,22 @@ +"use strict"; + +module.exports = (arr_, pred) => { + + const arr = arr_ || [], + spans = [] + + let span = { label: undefined, + items: [arr.first] } + + arr.forEach (x => { + + const label = pred (x) + + if ((span.label !== label) && span.items.length) { + spans.push (span = { label: label, items: [x] }) } + + else { + span.items.push (x) } }) + + return spans +}
\ No newline at end of file diff --git a/node_modules/stacktracey/package.json b/node_modules/stacktracey/package.json new file mode 100644 index 0000000..97829f5 --- /dev/null +++ b/node_modules/stacktracey/package.json @@ -0,0 +1,87 @@ +{ + "name": "stacktracey", + "version": "2.1.8", + "description": "Parses call stacks. Reads sources. Clean & filtered output. Sourcemaps. Node & browsers.", + "main": "stacktracey", + "types": "./stacktracey.d.ts", + "scripts": { + "lint": "eslint stacktracey.js", + "test": "nyc --reporter=html --reporter=text mocha --reporter spec", + "test-no-coverage": "mocha --reporter spec", + "autotest": "mocha --reporter spec --watch", + "coveralls": "nyc report --reporter=text-lcov | coveralls" + }, + "repository": { + "type": "git", + "url": "https://github.com/xpl/stacktracey.git" + }, + "keywords": [ + "stack", + "stacktrace", + "stack printer", + "error printer", + "print error", + "print stack", + "print debug trace", + "debug", + "trace", + "parse", + "print", + "pretty", + "callstack", + "call stack", + "read sources", + "error", + "Error.stack", + "error stack", + "stack parse", + "call stack parsing", + "stack parsing", + "stack parse", + "parse stack", + "parse call stack", + "callstack parser", + "call stack parse", + "parse callstack", + "parse stacktrace", + "parse stack trace", + "error stack parse", + "Error.stack parse", + "stack parser", + "error parser", + "error trace", + "trace error", + "sourcemap", + "call location", + "source text", + "source lines", + "print error with sources", + "show error", + "handling exceptions", + "exception parser", + "exception printer", + "custom error", + "pretty print", + "pretty print errors", + "pretty print stack" + ], + "author": "Vitaly Gordon <rocket.mind@gmail.com>", + "license": "Unlicense", + "bugs": { + "url": "https://github.com/xpl/stacktracey/issues" + }, + "homepage": "https://xpl.github.io/stacktracey", + "devDependencies": { + "babel-cli": "^6.26.0", + "chai": "^4.2.0", + "coveralls": "^3.0.3", + "eslint": "^4.19.1", + "istanbul": "^0.4.5", + "mocha": "^4.1.0", + "nyc": "^14.1.1" + }, + "dependencies": { + "as-table": "^1.0.36", + "get-source": "^2.0.12" + } +} diff --git a/node_modules/stacktracey/stacktracey.d.ts b/node_modules/stacktracey/stacktracey.d.ts new file mode 100644 index 0000000..bf4e3a4 --- /dev/null +++ b/node_modules/stacktracey/stacktracey.d.ts @@ -0,0 +1,88 @@ +declare class StackTracey { + + constructor (input?: Error|string|StackTracey.Entry[], offset?: number) + + items: StackTracey.Entry[] + + extractEntryMetadata (e: StackTracey.Entry): StackTracey.Entry + + shortenPath (relativePath: string): string + relativePath (fullPath: string): string + isThirdParty (relativePath: string): boolean + + rawParse (str: string): StackTracey.Entry[] + + withSourceAt (i: number): StackTracey.Entry + withSourceAsyncAt (i: number): Promise<StackTracey.Entry> + + withSource (entry: StackTracey.Entry): StackTracey.Entry + withSourceAsync (entry: StackTracey.Entry): Promise<StackTracey.Entry> + + withSources (): StackTracey + withSourcesAsync (): Promise<StackTracey> + mergeRepeatedLines (): StackTracey + + clean (): StackTracey + cleanAsync (): Promise<StackTracey> + + isClean (entry: StackTracey.Entry, index: number): boolean + + map (f: (x: StackTracey.Entry, i: number, arr: StackTracey.Entry[]) => StackTracey.Entry): StackTracey + filter (f: (x: StackTracey.Entry, i: number, arr: StackTracey.Entry[]) => boolean): StackTracey + slice (from?: number, to?: number): StackTracey + concat (...args: StackTracey.Entry[]): StackTracey + + at (i: number): StackTracey.Entry + + asTable (opts?: { maxColumnWidths?: StackTracey.MaxColumnWidths }): string + + maxColumnWidths (): StackTracey.MaxColumnWidths + + static resetCache (): void + static locationsEqual (a: StackTracey.Location, b: StackTracey.Location): boolean +} + +declare namespace StackTracey { + + interface SourceFile { + + path: string + text: string + lines: string[] + error?: Error + } + + interface Location { + + file: string + line?: number + column?: number + } + + interface Entry extends Location { + + beforeParse: string + callee: string + index: boolean + native: boolean + + calleeShort: string + fileRelative: string + fileShort: string + fileName: string + thirdParty: boolean + + hide?: boolean + sourceLine?: string + sourceFile?: SourceFile + error?: Error + } + + interface MaxColumnWidths { + callee: number + file: number + sourceLine: number + } +} + +export = StackTracey diff --git a/node_modules/stacktracey/stacktracey.js b/node_modules/stacktracey/stacktracey.js new file mode 100644 index 0000000..b86b6db --- /dev/null +++ b/node_modules/stacktracey/stacktracey.js @@ -0,0 +1,339 @@ +"use strict"; + +/* ------------------------------------------------------------------------ */ + +const O = Object, + isBrowser = (typeof window !== 'undefined') && (window.window === window) && window.navigator, + nodeRequire = isBrowser ? null : module.require, // to prevent bundlers from expanding the require call + lastOf = x => x[x.length - 1], + getSource = require ('get-source'), + partition = require ('./impl/partition'), + asTable = require ('as-table'), + nixSlashes = x => x.replace (/\\/g, '/'), + pathRoot = isBrowser ? window.location.href : (nixSlashes (process.cwd ()) + '/') + +/* ------------------------------------------------------------------------ */ + +class StackTracey { + + constructor (input, offset) { + + const originalInput = input + , isParseableSyntaxError = input && (input instanceof SyntaxError && !isBrowser) + + /* new StackTracey () */ + + if (!input) { + input = new Error () + offset = (offset === undefined) ? 1 : offset + } + + /* new StackTracey (Error) */ + + if (input instanceof Error) { + input = input.stack || '' + } + + /* new StackTracey (string) */ + + if (typeof input === 'string') { + input = this.rawParse (input).slice (offset).map (x => this.extractEntryMetadata (x)) + } + + /* new StackTracey (array) */ + + if (Array.isArray (input)) { + + if (isParseableSyntaxError) { + + const rawLines = nodeRequire ('util').inspect (originalInput).split ('\n') + , fileLine = rawLines[0].split (':') + , line = fileLine.pop () + , file = fileLine.join (':') + + if (file) { + input.unshift ({ + file: nixSlashes (file), + line: line, + column: (rawLines[2] || '').indexOf ('^') + 1, + sourceLine: rawLines[1], + callee: '(syntax error)', + syntaxError: true + }) + } + } + + this.items = input + + } else { + this.items = [] + } + } + + extractEntryMetadata (e) { + + const decomposedPath = this.decomposePath (e.file || '') + const fileRelative = decomposedPath[0] + const externalDomain = decomposedPath[1] + + return O.assign (e, { + + calleeShort: e.calleeShort || lastOf ((e.callee || '').split ('.')), + fileRelative: fileRelative, + fileShort: this.shortenPath (fileRelative), + fileName: lastOf ((e.file || '').split ('/')), + thirdParty: this.isThirdParty (fileRelative, externalDomain) && !e.index, + externalDomain: externalDomain + }) + } + + shortenPath (relativePath) { + return relativePath.replace (/^node_modules\//, '') + .replace (/^webpack\/bootstrap\//, '') + .replace (/^__parcel_source_root\//, '') + } + + decomposePath (fullPath) { + let result = fullPath + + if (isBrowser) result = result.replace (pathRoot, '') + + const externalDomainMatch = result.match (/^(http|https)\:\/\/?([^\/]+)\/(.*)/) + const externalDomain = externalDomainMatch ? externalDomainMatch[2] : undefined + result = externalDomainMatch ? externalDomainMatch[3] : result + + if (!isBrowser) result = nodeRequire ('path').relative (pathRoot, result) + + return [ + nixSlashes(result).replace (/^.*\:\/\/?\/?/, ''), // cut webpack:/// and webpack:/ things + externalDomain + ] + } + + isThirdParty (relativePath, externalDomain) { + return externalDomain || + (relativePath[0] === '~') || // webpack-specific heuristic + (relativePath[0] === '/') || // external source + (relativePath.indexOf ('node_modules') === 0) || + (relativePath.indexOf ('webpack/bootstrap') === 0) + } + + rawParse (str) { + + const lines = (str || '').split ('\n') + + const entries = lines.map (line => { + + line = line.trim () + + let callee, fileLineColumn = [], native, planA, planB + + if ((planA = line.match (/at (.+) \(eval at .+ \((.+)\), .+\)/)) || // eval calls + (planA = line.match (/at (.+) \((.+)\)/)) || + ((line.slice (0, 3) !== 'at ') && (planA = line.match (/(.*)@(.*)/)))) { + + callee = planA[1] + native = (planA[2] === 'native') + fileLineColumn = (planA[2].match (/(.*):(\d+):(\d+)/) || + planA[2].match (/(.*):(\d+)/) || []).slice (1) + + } else if ((planB = line.match (/^(at\s+)*(.+):(\d+):(\d+)/) )) { + fileLineColumn = (planB).slice (2) + + } else { + return undefined + } + + /* Detect things like Array.reduce + TODO: detect more built-in types */ + + if (callee && !fileLineColumn[0]) { + const type = callee.split ('.')[0] + if (type === 'Array') { + native = true + } + } + + return { + beforeParse: line, + callee: callee || '', + index: isBrowser && (fileLineColumn[0] === window.location.href), + native: native || false, + file: nixSlashes (fileLineColumn[0] || ''), + line: parseInt (fileLineColumn[1] || '', 10) || undefined, + column: parseInt (fileLineColumn[2] || '', 10) || undefined + } + }) + + return entries.filter (x => (x !== undefined)) + } + + withSourceAt (i) { + return this.items[i] && this.withSource (this.items[i]) + } + + withSourceAsyncAt (i) { + return this.items[i] && this.withSourceAsync (this.items[i]) + } + + withSource (loc) { + + if (this.shouldSkipResolving (loc)) { + return loc + + } else { + + let resolved = getSource (loc.file || '').resolve (loc) + + if (!resolved.sourceFile) { + return loc + } + + return this.withSourceResolved (loc, resolved) + } + } + + withSourceAsync (loc) { + + if (this.shouldSkipResolving (loc)) { + return Promise.resolve (loc) + + } else { + return getSource.async (loc.file || '') + .then (x => x.resolve (loc)) + .then (resolved => this.withSourceResolved (loc, resolved)) + .catch (e => this.withSourceResolved (loc, { error: e, sourceLine: '' })) + } + } + + shouldSkipResolving (loc) { + return loc.sourceFile || loc.error || (loc.file && loc.file.indexOf ('<') >= 0) // skip things like <anonymous> and stuff that was already fetched + } + + withSourceResolved (loc, resolved) { + + if (resolved.sourceFile && !resolved.sourceFile.error) { + resolved.file = nixSlashes (resolved.sourceFile.path) + resolved = this.extractEntryMetadata (resolved) + } + + if (resolved.sourceLine.includes ('// @hide')) { + resolved.sourceLine = resolved.sourceLine.replace ('// @hide', '') + resolved.hide = true + } + + if (resolved.sourceLine.includes ('__webpack_require__') || // webpack-specific heuristics + resolved.sourceLine.includes ('/******/ ({')) { + resolved.thirdParty = true + } + + return O.assign ({ sourceLine: '' }, loc, resolved) + } + + withSources () { + return this.map (x => this.withSource (x)) + } + + withSourcesAsync () { + return Promise.all (this.items.map (x => this.withSourceAsync (x))) + .then (items => new StackTracey (items)) + } + + mergeRepeatedLines () { + return new StackTracey ( + partition (this.items, e => e.file + e.line).map ( + group => { + return group.items.slice (1).reduce ((memo, entry) => { + memo.callee = (memo.callee || '<anonymous>') + ' → ' + (entry.callee || '<anonymous>') + memo.calleeShort = (memo.calleeShort || '<anonymous>') + ' → ' + (entry.calleeShort || '<anonymous>') + return memo + }, O.assign ({}, group.items[0])) + } + ) + ) + } + + clean () { + const s = this.withSources ().mergeRepeatedLines () + return s.filter (s.isClean.bind (s)) + } + + cleanAsync () { + return this.withSourcesAsync ().then (s => { + s = s.mergeRepeatedLines () + return s.filter (s.isClean.bind (s)) + }) + } + + isClean (entry, index) { + return (index === 0) || !(entry.thirdParty || entry.hide || entry.native) + } + + at (i) { + return O.assign ({ + + beforeParse: '', + callee: '<???>', + index: false, + native: false, + file: '<???>', + line: 0, + column: 0 + + }, this.items[i]) + } + + asTable (opts) { + + const maxColumnWidths = (opts && opts.maxColumnWidths) || this.maxColumnWidths () + + const trimEnd = (s, n) => s && ((s.length > n) ? (s.slice (0, n-1) + '…') : s) + const trimStart = (s, n) => s && ((s.length > n) ? ('…' + s.slice (-(n-1))) : s) + + const trimmed = this.map ( + e => [ + ('at ' + trimEnd (e.calleeShort, maxColumnWidths.callee)), + trimStart ((e.fileShort && (e.fileShort + ':' + e.line)) || '', maxColumnWidths.file), + trimEnd (((e.sourceLine || '').trim () || ''), maxColumnWidths.sourceLine) + ] + ) + + return asTable (trimmed.items) + } + + maxColumnWidths () { + return { + callee: 30, + file: 60, + sourceLine: 80 + } + } + + static resetCache () { + + getSource.resetCache () + getSource.async.resetCache () + } + + static locationsEqual (a, b) { + + return (a.file === b.file) && + (a.line === b.line) && + (a.column === b.column) + } +} + +/* Array methods + ------------------------------------------------------------------------ */ + +;['map', 'filter', 'slice', 'concat'].forEach (method => { + + StackTracey.prototype[method] = function (/*...args */) { // no support for ...args in Node v4 :( + return new StackTracey (this.items[method].apply (this.items, arguments)) + } +}) + +/* ------------------------------------------------------------------------ */ + +module.exports = StackTracey + diff --git a/node_modules/stacktracey/test.js b/node_modules/stacktracey/test.js new file mode 100644 index 0000000..38270b1 --- /dev/null +++ b/node_modules/stacktracey/test.js @@ -0,0 +1,356 @@ +"use strict"; + +/* ------------------------------------------------------------------------ */ + +const nodeVersion = Math.floor (Number (process.version.match (/^v(\d+\.\d+)/)[1])) + +/* ------------------------------------------------------------------------ */ + +require ('chai').should () + +/* ------------------------------------------------------------------------ */ + +describe ('impl/partition', () => { + + const partition = require ('./impl/partition') + const spans = partition ([ 'a', 'b', 'c', undefined, undefined, 42], x => typeof x) + + spans.should.deep.equal ([ { label: 'string', items: ['a', 'b', 'c'] }, + { label: 'undefined', items: [undefined, undefined] }, + { label: 'number', items: [42] } ]) +}) + +/* ------------------------------------------------------------------------ */ + +describe ('StackTracey', () => { + + const path = require ('path') + const StackTracey = require ('./stacktracey') + + StackTracey.resetCache () + + const shouldBeVisibleInStackTrace = () => new StackTracey () // @hide + + it ('works', () => { + + const stack = shouldBeVisibleInStackTrace () + + stack.should.be.an.instanceof (StackTracey) + + stack.items[0].should.deep.equal ({ + beforeParse: 'at shouldBeVisibleInStackTrace (' + path.join (process.cwd (), 'test.js') + ':32:47)', + callee: 'shouldBeVisibleInStackTrace', + index: false, + native: false, + file: path.join (process.cwd (), 'test.js').replace (/\\/g, '/'), + line: 32, + column: 47, + calleeShort: 'shouldBeVisibleInStackTrace', + fileName: 'test.js', + fileRelative: 'test.js', + fileShort: 'test.js', + thirdParty: false, + externalDomain: undefined + }) + }) + + it ('allows to read sources', () => { + + const stack = shouldBeVisibleInStackTrace ().withSources () // @hide + + stack.should.be.an.instanceof (StackTracey) + stack.items[0].beforeParse.should.not.be.undefined // should preserve previous fields + stack.items[0].sourceLine.should.equal (' const shouldBeVisibleInStackTrace = () => new StackTracey () ') + stack.items[0].hide.should.equal (true) // reads // @hide marker + stack.items[1].hide.should.equal (true) // reads // @hide marker + + const cleanStack = stack.clean () + + cleanStack.should.be.an.instanceof (StackTracey) + + StackTracey.locationsEqual (cleanStack.items[0], stack.items[0]).should.equal (true) // should not clean top element + StackTracey.locationsEqual (cleanStack.items[1], stack.items[1]).should.equal (false) // should clean second element (due to // @hide) + }) + + + it ('allows to read sources (async)', () => { + + return shouldBeVisibleInStackTrace ().withSourcesAsync ().then (stack => { // @hide + + stack.should.be.an.instanceof (StackTracey) + stack.items[0].beforeParse.should.not.be.undefined // should preserve previous fields + stack.items[0].sourceLine.should.equal (' const shouldBeVisibleInStackTrace = () => new StackTracey () ') + stack.items[0].hide.should.equal (true) // reads // @hide marker + stack.items[1].hide.should.equal (true) // reads // @hide marker + + return stack.cleanAsync ().then (cleanStack => { + + cleanStack.should.be.an.instanceof (StackTracey) + + StackTracey.locationsEqual (cleanStack.items[0], stack.items[0]).should.equal (true) // should not clean top element + StackTracey.locationsEqual (cleanStack.items[1], stack.items[1]).should.equal (false) // should clean second element (due to // @hide) + }) + }) + }) + + it ('allows creation from array + groups duplicate lines', () => { + + const stack = new StackTracey ([ + { file: 'yo.js', line: 11, callee: 'a.funkktion', calleeShort: 'a' }, + { file: 'yo.js', line: 10, callee: 'foobar.boobar', calleeShort: 'foobar' }, + { file: 'yo.js', line: 10, callee: 'foobar.boobar', calleeShort: 'foobar' }, + { file: 'lol.js', line: 10, callee: '', calleeShort: '' }, + ]) + + const clean = stack.clean ().map (x => Object.assign ({ + file: x.file, + line: x.line, + callee: x.callee, + calleeShort: x.calleeShort })) + + clean.should.be.an.instanceof (StackTracey) + + clean.items.should.deep.equal ([ // .should does not recognize StackTracey as normal array... + + { file: 'yo.js', line: 11, callee: 'a.funkktion', calleeShort: 'a' }, + { file: 'yo.js', line: 10, callee: 'foobar.boobar → foobar.boobar', calleeShort: 'foobar → foobar' }, + { file: 'lol.js', line: 10, callee: '', calleeShort: '' }, + ]) + }) + + it ('handles inaccessible files', () => { + + const stack = shouldBeVisibleInStackTrace () + stack.items[0].file = '^___^' + stack.withSources ().items[0].sourceLine.should.equal ('') + stack.withSourceAt (0).error.should.be.an.instanceof (Error) + }) + + it ('exposes some Array methods', () => { + + const stack = shouldBeVisibleInStackTrace () + const sliced = stack.slice (1) + const deltaLength = (stack.items.length - sliced.items.length) + + deltaLength.should.equal (1) + sliced.should.be.an.instanceof (StackTracey) + + sliced.filter (x => true).should.be.an.instanceof (StackTracey) + }) + + it ('works with sourcemaps', () => { + + const mkay = require ('./test_files/mkay.uglified') + + try { + mkay () + } + catch (e) { + + e.message.should.equal ('mkay') + + const top = new StackTracey (e).withSourceAt (0) + + top.line .should.equal (4) + top.sourceLine .should.equal ('\t\t\t\t\tthrow new Error (\'mkay\') }') + + top.file .should.equal (path.resolve ('./test_files/mkay.js').replace (/\\/g, '/')) + top.fileShort .should.equal ('test_files/mkay.js') + top.fileName .should.equal ('mkay.js') + } + }) + + it ('pretty printing works', function prettyTest () { + + const pretty = new StackTracey ().clean ().asTable () + + console.log ('') + console.log (pretty, '\n') + + //const spaces = nodeVersion > 8 ? ' ' : ' '; + + console.log (pretty.split ('\n')[0].match (/at prettyTest\s+test.js\:144\s+const pretty = new StackTracey \(\)\.clean\.pretty/)) + }) + + it ('trims too long columns in the pretty printed output', () => { + + const stack = new StackTracey ([ + { fileShort: 'dasdasdasdadadadasdasdasdasdasddasdsadadasdassdasdaddadasdas.js', line: 11, calleeShort: 'dadasdasdasdasdasdasdasdasdasdasdasdasd' }, + ]) + + stack.withSources ().asTable ().split ('\n')[0].should.equal ('at dadasdasdasdasdasdasdasdasdas… …asdadadadasdasdasdasdasddasdsadadasdassdasdaddadasdas.js:11 ') + }) + + it ('exposes Array methods', () => { + + const stack = new StackTracey ([ + { file: 'foo' }, + { file: 'bar' } + ]) + + const mapped = stack.map ((x, i) => Object.assign (x, { i })) + + mapped.items.should.deep.equal ([ { file: 'foo', i: 0 }, { file: 'bar', i: 1 } ]) + mapped.should.be.an.instanceof (StackTracey) + + const filtered = stack.filter (x => x.file === 'bar') + + filtered.items.length.should.equal (1) + filtered.items[0].should.deep.equal ({ file: 'bar', i: 1 }) + }) + + it ('computes relative path correctly', () => { + + StackTracey.prototype.decomposePath ('webpack:///~/jquery/dist/jquery.js') + .should.deep.equal ( ['~/jquery/dist/jquery.js', undefined]) + + StackTracey.prototype.decomposePath ('webpack:/webpack/bootstrap') + .should.deep.equal ( ['webpack/bootstrap', undefined]) + }) + + it ('computes short path correctly', () => { + + StackTracey.prototype.shortenPath ('webpack/bootstrap/jquery/dist/jquery.js') + .should.equal ('jquery/dist/jquery.js') + + StackTracey.prototype.shortenPath ('node_modules/jquery/dist/jquery.js') + .should.equal ('jquery/dist/jquery.js') + }) + + if (nodeVersion >= 5) { + + it ('recognizes SyntaxErrors', () => { + + try { require ('./test_files/syntax_error.js') } + catch (e) { + + const stack = new StackTracey (e).clean () + + console.log ('') + console.log (stack.asTable (), '\n') + + stack.items[0].syntaxError.should.equal (true) + stack.items[0].column.should.equal (5) + + const spaces = nodeVersion > 8 ? ' ' : ' ' + const spaces2 = nodeVersion > 8 ? (nodeVersion > 11 ? ' ' : ' ') : ' ' + + stack.asTable ().split ('\n')[0].should.equal ('at (syntax error)' + spaces + 'test_files/syntax_error.js:2' + spaces2 + 'foo->bar () ') + } + }) + } + + it ('allows to override isThirdParty()', () => { + + class MyStackTracey extends StackTracey { + isThirdParty (path) { + return super.isThirdParty (path) || (path === 'test.js') + } + } + + new MyStackTracey ().items[0].thirdParty.should.equal (true) + + class MyStackTracey2 extends MyStackTracey { + isThirdParty (path) { + return super.isThirdParty (path) && (path !== 'test.js') + } + } + + new MyStackTracey2 ().items[0].thirdParty.should.equal (false) + }) + + it ('.withSourceAt', () => { + + const line = new StackTracey ().withSourceAt (0).sourceLine.trim () + line.should.equal ('const line = new StackTracey ().withSourceAt (0).sourceLine.trim ()') + }) + + it ('.at', () => { + + new StackTracey ().at (0).file.includes ('stacktracey/test.js').should.equal (true) + }) + + it ('detects Array methods as native', () => { + + const arr = [1,2,3] + const stack = arr.reduce (() => new StackTracey ()) + + stack.items[1].native.should.equal (true) + }) + + it ('works on Windows', () => { + + const dir = process.cwd () + + const windowsStack = + [ + 'Error', + ' at Context.it (' + dir + '\\test.js:38:22)', + ' at callFn (' + dir + '\\node_modules\\mocha\\lib\\runnable.js:354:21)', + ' at runCallback (timers.js:800:20)' + ].join ('\n') + + const stack = new StackTracey (windowsStack) + const pretty = stack.withSources ().asTable () + const lines = pretty.split ('\n') + + console.log ('') + console.log (pretty, '\n') + + lines[0].should.equal ('at it test.js:38 stack.should.be.an.instanceof (StackTracey)') + lines[1].indexOf ('at callFn mocha/lib/runnable.js:354').should.equal (0) + }) + + it ('parses "eval at" stuff', () => { + + function bar() { + const entry = new StackTracey().items[1] + entry.callee.should.equal('eval') + entry.fileName.should.equal('test.js') + } + function foo() { + eval('bar()') + } + foo() + }) + + it ('recognizes externalDomain', () => { + + const stack = + [ + 'Error', + ' at foo (test.js:38:22)', + ' at bar (http://shmoogle.google.com/hohoho/test.js:38:22)', + ].join ('\n') + + const items = new StackTracey(stack).items + + ;(items[0].externalDomain === undefined).should.be.true + items[1].externalDomain.should.equal('shmoogle.google.com') + + items[0].thirdParty.should.be.false + items[1].thirdParty.should.be.true + + items[1].fileRelative.should.equal('hohoho/test.js') + }) + + it ('recognizes locations without column', () => { + const stack = [ + 'Error', + ' at ValidateCompatibilityWithBindGroupLayout (../../third_party/dawn/src/dawn_native/ShaderModule.cpp:395)', + ].join ('\n') + + const items = new StackTracey(stack).items + + items[0].should.contain({ + callee: 'ValidateCompatibilityWithBindGroupLayout', + calleeShort: 'ValidateCompatibilityWithBindGroupLayout', + fileRelative: '../../third_party/dawn/src/dawn_native/ShaderModule.cpp', + fileShort: '../../third_party/dawn/src/dawn_native/ShaderModule.cpp', + fileName: 'ShaderModule.cpp' + }) + }) +}) + + + diff --git a/node_modules/stacktracey/test_files/mkay.js b/node_modules/stacktracey/test_files/mkay.js new file mode 100644 index 0000000..6301f48 --- /dev/null +++ b/node_modules/stacktracey/test_files/mkay.js @@ -0,0 +1,4 @@ +/* This will help assuring whether our source mapping works OK */ + +module.exports = function mkay () { + throw new Error ('mkay') }
\ No newline at end of file diff --git a/node_modules/stacktracey/test_files/mkay.uglified.js b/node_modules/stacktracey/test_files/mkay.uglified.js new file mode 100644 index 0000000..8bafeaf --- /dev/null +++ b/node_modules/stacktracey/test_files/mkay.uglified.js @@ -0,0 +1,2 @@ +module.exports=function mkay(){throw new Error("mkay")}; +//# sourceMappingURL=mkay.uglified.js.map
\ No newline at end of file diff --git a/node_modules/stacktracey/test_files/mkay.uglified.js.map b/node_modules/stacktracey/test_files/mkay.uglified.js.map new file mode 100644 index 0000000..fbe3ad6 --- /dev/null +++ b/node_modules/stacktracey/test_files/mkay.uglified.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["mkay.js"],"names":["module","exports","mkay","Error"],"mappings":"AAEAA,OAAOC,QAAU,QAASC,QACrB,KAAM,IAAIC,OAAO","file":"mkay.uglified.js"}
\ No newline at end of file diff --git a/node_modules/stacktracey/test_files/syntax_error.js b/node_modules/stacktracey/test_files/syntax_error.js new file mode 100644 index 0000000..78eb0fb --- /dev/null +++ b/node_modules/stacktracey/test_files/syntax_error.js @@ -0,0 +1,2 @@ +// next line contains a syntax error (not a valid JavaScript) +foo->bar ()
\ No newline at end of file |
