npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@git.zone/tstest

v3.1.8

Published

a test utility to run tests that match test/**/*.ts

Readme

Improved Internal Protocol Design

Current Issues with TAP Protocol

  1. Delimiter Conflict: Using # for metadata conflicts with test descriptions containing #
  2. Ambiguous Parsing: No clear boundary between test name and metadata
  3. Limited Extensibility: Adding new metadata requires regex changes
  4. Mixed Concerns: Protocol data mixed with human-readable output

Proposed Internal Protocol v2

Design Principles

  1. Clear Separation: Protocol data must be unambiguously separated from user content
  2. Extensibility: Easy to add new metadata without breaking parsers
  3. Backwards Compatible: Can coexist with standard TAP for gradual migration
  4. Machine Readable: Structured format for reliable parsing
  5. Human Friendly: Still readable in raw form

Protocol Options

Option 1: Special Delimiters

ok 1 - test description ::TSTEST:: {"time":123,"retry":0}
not ok 2 - another test ::TSTEST:: {"time":45,"error":"timeout"}
ok 3 - skipped test ::TSTEST:: {"time":0,"skip":"not ready"}

Pros:

  • Simple to implement
  • Backwards compatible with TAP parsers (they ignore the suffix)
  • Easy to parse with split()

Cons:

  • Still could conflict if test name contains ::TSTEST::
  • Not standard TAP

Option 2: Separate Metadata Lines

ok 1 - test description
::METADATA:: {"test":1,"time":123,"retry":0}
not ok 2 - another test  
::METADATA:: {"test":2,"time":45,"error":"timeout"}

Pros:

  • Complete separation of concerns
  • No chance of conflicts
  • Can include arbitrary metadata

Cons:

  • Requires correlation between lines
  • More complex parsing

Option 3: YAML Blocks (TAP 13 Compatible)

ok 1 - test description
  ---
  time: 123
  retry: 0
  ...
not ok 2 - another test
  ---
  time: 45
  error: timeout
  stack: |
    Error: timeout
      at Test.run (test.js:10:5)
  ...

Pros:

  • Standard TAP 13 feature
  • Structured data format
  • Human readable
  • Extensible

Cons:

  • More verbose
  • YAML parsing overhead

Option 4: Binary Protocol Markers (Recommended)

ok 1 - test description
␛[TSTEST:eyJ0aW1lIjoxMjMsInJldHJ5IjowfQ==]␛
not ok 2 - another test
␛[TSTEST:eyJ0aW1lIjo0NSwiZXJyb3IiOiJ0aW1lb3V0In0=]␛

Using ASCII escape character (␛ = \x1B) with base64 encoded JSON.

Pros:

  • Zero chance of accidental conflicts
  • Compact
  • Fast to parse
  • Invisible in most terminals

Cons:

  • Not human readable in raw form
  • Requires base64 encoding/decoding

Recommended Implementation: Hybrid Approach

Use multiple strategies based on context:

  1. For timing and basic metadata: Use structured delimiters

    ok 1 - test name ⟦time:123,retry:0⟧
  2. For complex data (errors, snapshots): Use separate protocol lines

    ok 1 - test failed
    ⟦TSTEST:ERROR⟧
    {"message":"Assertion failed","stack":"...","diff":"..."}
    ⟦/TSTEST:ERROR⟧
  3. For human-readable output: Keep standard TAP comments

    # Test suite: User Authentication
    ok 1 - should login

Implementation Plan

Phase 1: Parser Enhancement

  1. Add new protocol parser alongside existing TAP parser
  2. Support both old and new formats during transition
  3. Add protocol version negotiation

Phase 2: Metadata Structure

interface TestMetadata {
  // Timing
  time: number;           // milliseconds
  startTime?: number;     // Unix timestamp
  endTime?: number;       // Unix timestamp
  
  // Status
  skip?: string;          // skip reason
  todo?: string;          // todo reason
  retry?: number;         // retry attempt
  maxRetries?: number;    // max retries allowed
  
  // Error details
  error?: {
    message: string;
    stack?: string;
    diff?: string;
    actual?: any;
    expected?: any;
  };
  
  // Test context
  file?: string;          // source file
  line?: number;          // line number
  column?: number;        // column number
  
  // Custom data
  tags?: string[];        // test tags
  custom?: Record<string, any>;
}

Phase 3: Protocol Messages

Success Message
ok 1 - user authentication works
⟦TSTEST:META:{"time":123,"tags":["auth","unit"]}⟧
Failure Message
not ok 2 - login fails with invalid password
⟦TSTEST:META:{"time":45,"retry":1,"maxRetries":3}⟧
⟦TSTEST:ERROR⟧
{
  "message": "Expected 401 but got 500",
  "stack": "Error: Expected 401 but got 500\n    at Test.run (auth.test.ts:25:10)",
  "actual": 500,
  "expected": 401
}
⟦/TSTEST:ERROR⟧
Skip Message
ok 3 - database integration test ⟦TSTEST:SKIP:No database connection⟧
Snapshot Communication
⟦TSTEST:SNAPSHOT:user-profile⟧
{
  "name": "John Doe",
  "email": "[email protected]",
  "roles": ["user", "admin"]
}
⟦/TSTEST:SNAPSHOT⟧

Migration Strategy

  1. Version Detection: First line indicates protocol version

    ⟦TSTEST:PROTOCOL:2.0⟧
    TAP version 13
  2. Gradual Rollout:

    • v1.10: Add protocol v2 parser, keep v1 generator
    • v1.11: Generate v2 by default, v1 with --legacy flag
    • v2.0: Remove v1 support
  3. Feature Flags:

    tap.settings({
      protocol: 'v2',        // or 'v1', 'auto'
      protocolFeatures: {
        structuredErrors: true,
        enhancedTiming: true,
        binaryMarkers: false
      }
    });

Benefits of New Protocol

  1. Reliability: No more regex fragility or description conflicts
  2. Performance: Faster parsing with clear boundaries
  3. Extensibility: Easy to add new metadata fields
  4. Debugging: Rich error information with stack traces and diffs
  5. Integration: Better IDE and CI/CD tool integration
  6. Forward Compatible: Room for future enhancements

Example Parser Implementation

class ProtocolV2Parser {
  private readonly MARKER_START = '⟦TSTEST:';
  private readonly MARKER_END = '⟧';
  
  parseMetadata(line: string): TestMetadata | null {
    const start = line.lastIndexOf(this.MARKER_START);
    if (start === -1) return null;
    
    const end = line.indexOf(this.MARKER_END, start);
    if (end === -1) return null;
    
    const content = line.substring(start + this.MARKER_START.length, end);
    const [type, data] = content.split(':', 2);
    
    switch (type) {
      case 'META':
        return JSON.parse(data);
      case 'SKIP':
        return { skip: data };
      case 'TODO':
        return { todo: data };
      default:
        return null;
    }
  }
  
  parseTestLine(line: string): ParsedTest {
    // First extract any metadata
    const metadata = this.parseMetadata(line);
    
    // Then parse the TAP part (without metadata)
    const cleanLine = this.removeMetadata(line);
    const tapResult = this.parseTAP(cleanLine);
    
    return { ...tapResult, metadata };
  }
}

Next Steps

  1. Implement proof of concept with basic metadata support
  2. Test with real-world test suites for edge cases
  3. Benchmark parsing performance
  4. Get feedback from users
  5. Finalize protocol specification
  6. Implement in both tapbundle and tstest