Git Product home page Git Product logo

stack-utils's Introduction

@tapjs

Workspace for node-tap development.

Dev Commands

Do this at least once to get everything set up and ready to go:

npm run bootstrap

(Note: npm install will not work until you do this, because the generated TypeScript eats its own tail.)


Build the test class (required after any plugin or core changes):

npm run build

Any other builds:

npm run prepare -w src/{whatever}

After adding or removing workspaces:

npm i

Run all tests in all workspaces:

npm test

Run all tests, saving snapshots:

npm run snap

Build and serve docs:

npm start

Contents

  • tap The main entry point module, which sets up the root test runner and exposes an alias to the cli runner.
  • tap-parser The module that parses TAP
  • @tapjs/core Most of the basic moving parts of tap
  • tap-yaml Thin wrapper around YAML and yaml-types for consistent handling of JavaScript values in YAML diagnostics.
  • @tapjs/test The plugin-ified Test class.
  • @tapjs/config Handling config files, command line interface parsing, environment variables, and validation
  • @tapjs/run The command line runner
  • tcompare The library that does comparison and object formatting (use heavily by @tapjs/asserts methods).
  • @tapjs/stack Library for capturing stack frames, the descendant of stack-utils.
  • @tapjs/processinfo The library that tracks process information and code coverage (hosted outside the monorepo, because it can't be tested by a version of tap that uses itself without bootstrap paradoxes)
  • default plugins:
  • optional plugins:
  • other stuff:
    • npm-init-template A library for more easily creating npm init packages. This will move out as soon as this version of tap is published.
    • @tapjs/create-plugin An npm init library facilitating npm init @tapjs/plugin to create new plugins.

Bootstrap and skipLibCheck

Run npm run bootstrap to build the @tapjs/test module with the default set of plugins, so that the other libraries can build properly. (This only has to be done once, unless the build script or set of default plugins are changed, of course.)

Because there's a bootstrapping cycle between @tapjs/core, @tapjs/test, and all of the plugins, they MUST use skipLibCheck: true in their tsconfigs. It should not be used in other packages.

stack-utils's People

Contributors

addaleax avatar bendingbender avatar bpmccurdy avatar coreyfarrell avatar erights avatar hkdobrev avatar isaacs avatar jamestalmage avatar novemberborn avatar richardlau avatar rozzzly avatar samverschueren avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

stack-utils's Issues

Fails to clean all internal Node.js frames

In recent versions of Node.js (e.g. v17.0.1, but also earlier versions), there is an extra stack frame at async Promise.all (index 0), e.g:

Error: Message.
    at file://[redacted]/test-director/test/fixtures/fails.mjs:7:9
    at TestDirector.run (file://[redacted]/test-director/index.mjs:121:15)
    at file://[redacted]/test-director/test/fixtures/fails.mjs:49:7
    at ModuleJob.run (node:internal/modules/esm/module_job:185:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:281:24)
    at async loadESM (node:internal/process/esm_loader:88:5)
    at async handleMainPromise (node:internal/modules/run_main:65:12)

The StackUtils.clean method fails to remove this extra frame:

file://test/fixtures/fails.mjs:7:9
TestDirector.run (file://index.mjs:121:15)
file://test/fixtures/fails.mjs:49:7
async Promise.all (index 0)

This leads to very confusing error stacks when presented to users that don't use Promise.all anywhere in their project.

This also leads to very annoying situations where snapshot tests of cleaned error traces that run in both older and newer Node.js versions fail in whichever environment is not the one the snapshots were saved in.

It's not clear the best way to work around this dilemma until the bug is fixed here in stack-utils, as using regex to remove async Promise.all (index 0) before running StackUtils.clean would have to be careful not to remove Promise.all frames that don't relate to Node.js internals and originate in project code.

Does not filter out node internals without function names

const StackUtils = require('stack-utils');
const stack = new StackUtils({cwd: process.cwd(), internals: StackUtils.nodeInternals()});

stack.clean(`
    at ChannelWrap.emitInitNative (internal/async_hooks.js:136:43)
    at new Resolver (internal/dns/utils.js:23:20)
    at internal/dns/utils.js:101:23
    at NativeModule.compile (internal/bootstrap/loaders.js:285:5)
    at nativeModuleRequire (internal/bootstrap/loaders.js:192:14)
    at dns.js:38:5
    at NativeModule.compile (internal/bootstrap/loaders.js:285:5)
    at NativeModule.compileForPublicLoader (internal/bootstrap/loaders.js:220:8)
    at loadNativeModule (internal/modules/cjs/helpers.js:23:9)
    at Function.Module._load (internal/modules/cjs/loader.js:694:15)
`);

Expected result:

''

Received result:

internal/dns/utils.js:101:23
dns.js:38:5

Need to disable some test on debian

With node 8, debian need to disable some test:

Author: Bastien ROUCARIÈS <[email protected]>
Date:   Tue Jun 5 23:16:03 2018 +0200

    Disable some test due to newer node
    
    Forwarded: not-needed

diff --git a/test/at.js b/test/at.js
index 1881469..91c932d 100644
--- a/test/at.js
+++ b/test/at.js
@@ -10,6 +10,7 @@ var base = __filename.substr(process.cwd().length + 1)
 t.match(stack.at(), { line: Number, column: Number, file: base })
 
 // a capture from a native site
+/*
 var arr = [ 0 ]
 var captures = arr.map(function xyz (n) {
   return stack.at(xyz)
@@ -22,3 +23,4 @@ t.match(captures, [ {
   type: 'Array',
   function: 'map'
 } ])
+*/
\ No newline at end of file
diff --git a/test/test.js b/test/test.js
index 58d29a5..340174f 100644
--- a/test/test.js
+++ b/test/test.js
@@ -176,7 +176,7 @@ t.test('captureString: two redirects', function (t) {
   ]));
   t.end()
 });
-
+/*
 t.test('captureString: with startStack function', function (t) {
   var stack = new StackUtils({internals: internals(), cwd: utils.fixtureDir});
   var capture = new CaptureFixture(stack);
@@ -188,7 +188,7 @@ t.test('captureString: with startStack function', function (t) {
   ]));
   t.end()
 });
-
+*/
 t.test('captureString: with limit', function (t) {
   var stack = new StackUtils({internals: internals(), cwd: utils.fixtureDir});
   var capture = new CaptureFixture(stack);

Doesn't clean up `fs` properly

In AVA:

import fs from 'fs';
import test from 'ava';

test.cb(() => {
    fs.exists('foo', () => {
        throw new Error('123');
    });
});

Results in:

❯ ava


  2 exceptions

  1. Uncaught Exception
  Error: 123
    test.js:6:9
    FSReqWrap.cb [as oncomplete] (fs.js:212:19)


  2. Test results were not received from test.js

The FSReqWrap.cb [as oncomplete] (fs.js:212:19) part should have been cleaned up.

Tests fail on Node.js master

Using nodejs/node@6d3c85f

> [email protected] test /Users/isaacs/dev/js/stack-utils
> xo && nyc --reporter lcov --reporter text --cache ava --verbose


/Users/isaacs/dev/js/stack-utils/test/test.js
  276:2  warning  Unexpected "todo" comment  no-warning-comments
  322:2  warning  Unexpected "todo" comment  no-warning-comments
  358:2  warning  Unexpected "todo" comment  no-warning-comments

✖ 3 problems (0 errors, 3 warnings)

  ✖ Forked processes must have an IPC channel
----------|----------|----------|----------|----------|----------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines |Uncovered Lines |
----------|----------|----------|----------|----------|----------------|
----------|----------|----------|----------|----------|----------------|
All files |      100 |      100 |      100 |      100 |                |
----------|----------|----------|----------|----------|----------------|

npm ERR! Test failed.  See above for more details.

Avoid property override hazard

Hi! 👋

Firstly, thanks for your work on this project! 🙂

Today I used patch-package to patch [email protected] for the project I'm working on.

Assignments to res.constructor trip over the JavaScript property override mistake, causing Ava test assertion failure results in some environments to become unable to be output. The problem can be reproduced if you freeze Object.prototype.

Here is the diff that solved my problem:

diff --git a/node_modules/stack-utils/index.js b/node_modules/stack-utils/index.js
index ed14bd3..ad9eeb1 100644
--- a/node_modules/stack-utils/index.js
+++ b/node_modules/stack-utils/index.js
@@ -161,7 +161,7 @@ class StackUtils {
     setFile(res, site.getFileName(), this._cwd);
 
     if (site.isConstructor()) {
-      res.constructor = true;
+      Object.defineProperty(res, 'constructor', { value: true });
     }
 
     if (site.isEval()) {
@@ -260,7 +260,7 @@ class StackUtils {
     setFile(res, file, this._cwd);
 
     if (ctor) {
-      res.constructor = true;
+      Object.defineProperty(res, 'constructor', { value: true });
     }
 
     if (evalOrigin) {

This issue body was partially generated by patch-package.

license nit

Hi, obviously it's totally cool to pull node-tap's lib/stack.js into a standalone module, and I appreciate you doing that.

But, since this is based on that code, would you mind updating the license to include the copyright, as required by node-tap's ISC license? Maybe something like this?

Copyright (c) James Talmage <[email protected]> (github.com/jamestalmage), Isaac Z. Schlueter <[email protected]>, and Contributors

Extracted from code in node-tap http://www.node-tap.org/

I don't mean to be weird, and I'm definitely not upset and this is not borne out of frustration or conflict. I'm only mentioning it because being in a new git repo means that the git history doesn't preserve the provenance of the code, and I like to maintain best practices for this sort of thing.

Changing to the MIT license is fine, it's functionally equivalent to ISC anyway.

Thanks :)

Fail to parseLine when path contains '('

Example:

stackUtils.parseLine('    at Context.<anonymous> (/Users/USER/Dropbox (Personal)/example/test.js:14:11)')
// => null

stackUtils.parseLine('    at Context.<anonymous> (/Users/USER/Dropbox/example/test.js:14:11)')
// => { line: 14, column: 11, file: '/Users/USER/Dropbox/example/test.js', function: 'Context.<anonymous>' }

Looking at the possible permutations I am not very confident in my ability to get a patch implemented 😟 Possibly someone with more experience would have time to look at this?


Additionally, I hit this issue trying to utilize another library as well (stack-trace). I wonder if the parseLine functionality could be pulled out and utilized by both libraries in order to maximize reuse, improve consistency, and share workload? Just a thought.

Feature: Support error causes

This is a proposal to support printing stacks of errors nested with error.cause. The JS spec allows error.cause to be any value, but this proposal is mainly concerned with what happens when cause is present as a string or another error.

I've written up the most descriptive form of this proposal as a proposed jest feature. If you don't mind I'll avoid copying it all out here. Jest uses stack-utils under the hood to reformat errors.

The TC39 committee has so far indicated that the language will not provide any official implementation of printing nested errors. Their hands are tied to some extent until they finish specifying the semantics of error.stack. But until then it will be very useful to have best-effort printing and formatting for errors printed in the most common way.

I think errors with causes should be printed more or less like this:

SomeError: The grumblecakes could not be found
    at grumblecake-locator.js:12:2
Caused by: QueryError: Invalid query `SELECT <grumblecakes>`
    at db.js:51:4
Caused by: ParseError: Unexpected character `<` at position 8
    at db.js:1233:10

Currently there is no standard for this. I think stack-utils would be an excellent library in which to create an implementation which formats, prints, and loosely parses errors with multiple messages and stack traces.

I'm willing to build it. Is there interest from the maintainers?

`nodeInternals()` does not include matchers for `node: `

const StackUtils = require('stack-utils');

const stack = new StackUtils();

const cleaned = stack.clean(`
    at ChannelWrap.emitInitNative (internal/async_hooks.js:136:43)
    at new Resolver (internal/dns/utils.js:23:20)
    at internal/dns/utils.js:101:23
    at NativeModule.compile (internal/bootstrap/loaders.js:285:5)
    at nativeModuleRequire (internal/bootstrap/loaders.js:192:14)
    at dns.js:38:5
    at NativeModule.compile (internal/bootstrap/loaders.js:285:5)
    at NativeModule.compileForPublicLoader (internal/bootstrap/loaders.js:220:8)
    at loadNativeModule (internal/modules/cjs/helpers.js:23:9)
    at Function.Module._load (internal/modules/cjs/loader.js:694:15)
    at processTicksAndRejections (node:internal/process/task_queues:93:5)
`);

console.log(cleaned);

Expected result:

''

Received result:

processTicksAndRejections (node:internal/process/task_queues:93:5)

Workaround:

const stack =  new StackUtils({
  internals: StackUtils.nodeInternals().concat(/\s*\(node:/);
});

nodejs/node#35498

Bikeshed on the API

I think most of the functions should take options objects instead of a list of args.

so

stack.capture({limit: 1, startStackFunction: fn});

instead of

stack.capture(1, fn);

Almost every parameter is optional anyways, so it seems more sensible to do it that way.

// @isaacs @bcoe @sindresorhus

stack-utils 1.0.3 causing error in npm test

'node',

facing below error in npm test
node_modules/stack-utils/index.js:16
).map(n => new RegExp((?:\\((?:node:)?${n}(?:\\.js)?:\\d+:\\d+\\)$|^\\s*at (?:node:)?${n}(?:\\.js)?:\\d+:\\d+$)));
^

SyntaxError: Unexpected token )
at createScript (vm.js:56:10)

seems the extra comma(,) casing issue.

Reference Bug - #56

This causing issue as stack-utils used as internal dependency in jest-message-util.
Till 12th November picking 1.0.2 and working fine
after release of 1.0.3 , npm test getting failed.

What should be considered "internal"?

The current list of regular-expressions doesn't capture everything I think it should.

  1. The internal folder in Nodejs.

      /\(internal\/[\w_-]+\.js:[0-9]+:[0-9]+\)$/

    Note this matches the opening (, so it should not match user folders called internal.

  2. Any native methods.

      /\(native\)$/

    Without this, I was getting long-stack-output with the following:

    From previous event:
      Array.map(native)
    

    Which is pretty much useless.

  3. Spawn wrap

     /[\\\/]\.node-spawn-wrap-\w+-\w+[\\\/]node:[0-9]+:[0-9]+\)?$/

    My thought is the only people who need to see spawn wrap output is spawn wrap developers. It doesn't technically qualify as an Nodejs internal, but it's wrapping/replacing internals, and it seems really unlikely to benefit anyone.

  4. node.js

      /node\.js:[0-9]+:[0-9]+\)?$/

    This was appearing at the tail end of a lot of stack-traces in long-stack-trace test suite. I think it should probably match the opening ( like 1.

Incorrectly cleans `file://` paths

file:// URL paths can only be absolute:

file: URLs are always absolute paths.
https://nodejs.org/api/fs.html#fs_file_url_paths

Yet the clean method strips out the CWD from the file: URLs, leaving the file:// at the start, making them invalid.

This is a pressing issue, because the error stack from errors thrown in an ESM file starts with the file: URL of the ESM. The ecosystem is currently migrating to vanilla ESM (in .mjs files, or .js files with package "type": "module") and more people will start to notice this bug.

In test.mjs:

import StackUtils from 'stack-utils';

const stackUtils = new StackUtils();

try {
  throw new Error('Message.');
} catch (error) {
  console.log(error.stack);
  console.log(stackUtils.clean(error.stack));
}

Then, run node test.mjs and the console log is ([CWD] substituting the absolute CWD path):

Error: Message.
    at file://[CWD]/test.mjs:6:9
    at ModuleJob.run (node:internal/modules/esm/module_job:175:25)
    at async Loader.import (node:internal/modules/esm/loader:178:24)
    at async Object.loadESM (node:internal/process/esm_loader:68:5)
file://test.mjs:6:9

Note the invalid file://test.mjs:6:9, it should be test.mjs:6:9.

Supported way to append internals after it is created

Can we get an API to support adding to internals after the object is constructed? Even if the following is officially supported would work:

const StackUtils = require('stack-utils');
const internals = [];
const stackUtils = new StackUtils({internals});
// Add to the array that StackUtils is using
internals.push(/node_modules/);

If we go this route I'd want to add a test to ensure it doesn't get broken in the future.

last line of leading multiline message remains in cleaned stack

// in REPL
const StackUtils = require('stack-utils');
const stack = new StackUtils();
try {
  throw new TypeError(`foo
bar
baz`);
} catch (err) {
  console.log(stack.clean(err.stack));
}

actual:

baz
    REPL18:2:9

expected:

either the entire message or none of it

Support promise long stack traces

Currently this:

Error: e
    at null._onTimeout (/Users/jamestalmage/WebstormProjects/stack-utils/foo.js:27:11)
    at Timer.listOnTimeout (timers.js:119:15)
From previous event:
    at /Users/jamestalmage/WebstormProjects/stack-utils/foo.js:25:9
    at processImmediate [as _immediateCallback] (timers.js:367:17)
From previous event:
    at Object.<anonymous> (/Users/jamestalmage/WebstormProjects/stack-utils/foo.js:24:3)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Function.Module.runMain (module.js:501:10)
    at startup (node.js:129:16)
    at node.js:814:3

becomes this

null._onTimeout (foo.js:27:11)
From previous event:
foo.js:25:9
From previous event:
Object.<anonymous> (foo.js:24:3)
node.js:814:3

Pretty good, but it It would be better if the cleaned stack trace kept some form of indentation between the From previous event lines.

I am not sure the best way to detect this, just look for From previous event? This example is bluebird, but I know q and others support the same idea, but I'm not sure how they format it.

Would it just be better to look for unindented separator lines? That may cover a wider range of implementations, but are normal stack trace lines always guaranteed to be indented?

// @sindresorhus @isaacs

document that parseLine can return null

For some reason, at the top of the stack of one particular error, I have only the error message, rather than a line with a filename. Therefore, my code ran into an issue because it called stack.parseLine(firstLineOfStack) and assumed this method would return an object. I did not realize that this method could return null. I assumed that if it could not parse a line, it would return an object where the properties are set to empty values, or perhaps throw an error.

I believe this possibility should be documented.

But thanks for the great library!

Simplify cleaning up immediate dependencies

I was thinking, is there any way we could simplify this even more? Maybe add an option that accepts immediate module names, so you could just supply ignoredPackages: ['tap'] instead of having the regex? That would cover the most common use-case.

`StackUtils` `parseLine` method chokes on stack traces containing constructor calls

In version 2.0.5 of stack-utils, the parseLine method will commit suicide on line 263 of index.js if there is a constructor call in the stack trace being parsed. This is due to an assignment to res.constructor which clobbers the res constructor and throws. I suspect this was intended to be an assignment to res.ctor, but in any case probably should be given some other property name than constructor.

I've patched my copy of the file and verified that changing res.constructor to res.ctor corrects the problem, but since my use case is not inspecting the returned res value for ctor or constructor I'll leave it to you to determine whether making this change would cause a compatibility issue for users of the package.

However, the problem breaks the Ava test framework when failing test assertions contain such stack traces. The assignment to res.constructor clobbers test execution with a Could not serialize error complaint.

There may be a similar issue on line 164, in the at method.

Add tests for stack traces produced by `--enable-source-maps`

Newer versions of node.js have built-in support for processing source-maps. We should test against some stack traces produced by --enable-source-maps.

Edit: I've been experimenting with --enable-source-maps and everything seems to work correctly though I think I'm likely only hitting nominal conditions.

`at` and `parseLine` have almost (but not quite) identical output formats.

The output of at and parseLine are nearly identical. parseLine just does some extra processing of evalOrigin to split it into evalLine, evalColumn and evalFile.

Seems easy enough to make the two outputs identical.

Perhaps at could even just be reduced to:

this.parseLine(this.captureString({limit: 1, stackStartFunction: fn});

Currently at utilizes the CallSite API directly instead of parsing a string, maybe it's better to stick with that.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.