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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@livy/util

v1.0.6

Published

Common utilities for the Livy logger

Downloads

846

Readme

@livy/util

This package contains common utilities for building components for the Livy logger.


Table of Contents:


General Purpose Utilities

Helpers

There's also a whole bunch general-purpose helper functions in this file. They are thoroughly documented, including examples, so you're probably best off to just dive into the source code.

Types

For TypeScript users, there are also some handy types to be found in this file.

Environment

Determines whether the runtime is Node.js or a browser and derives related environment-specific data.

const Environment = require('@livy/util/lib/environment')

Environment.isNodeJs // `true` or `false`
Environment.isBrowser // `true` or `false`
Environment.EOL // os.EOL in Node.js, '\n' otherwise

ValidatableSet

An extended Set with the array methods some and every on top:

const { ValidatableSet } = require('@livy/util/lib/validatable-set')

const set = new ValidatableSet([1, 2, 3])

set.every(item => typeof item === 'number') // true
set.some(item => item < 0)                  // false

// Behaves like the corresponding array methods on empty sets:
set.clear()
set.every(anyCondition) // false
set.some(anyCondition)  // true

GatedSet

An extended ValidatableSet that allows to validate and reject values that go inside the set.

const { GatedSet } = require('@livy/util/lib/gated-set')

const integers = new GatedSet(value => {
  if (typeof value !== 'number' || !Number.isInteger(value)) {
    throw new TypeError('Set only accepts integers')
  }
})

integers.add(5)     // OK
integers.add(-50)   // OK
integers.add(5.5)   // Throws TypeError
integers.add(NaN)   // Throws TypeError
integers.add('foo') // Throws TypeError

HTML

A function/template tag that allows you to easily construct HTML strings without having to worry about escaping:

const { HTML } = require('@livy/util/lib/html')

const snippet = '<em>awesome</em>'

HTML`<p>Markup is ${snippet}!</p>`.toString()
// '<p>Markup is &lt;em&gt;awesome&lt;/em&gt;!</p>'

// Use HTML as template tag in interpolations to avoid escaping:
HTML`<p>Markup is ${HTML`<em>awesome</em>`}!</p>`.toString()
// '<p>Markup is <em>awesome</em>!</p>'

// Use HTML as a function to avoid escaping of variables:
HTML`<p>Markup is ${HTML(snippet)}!</p>`.toString()
// '<p>Markup is <em>awesome</em>!</p>'

isResettableInterface

Check whether a handler or processors is resettable.

See also: ResettableInterface

Mixin

An approach to use TypeScript mixins slightly altered from Mixin classes.

Supports extending abstract classes and correctly type-checks super() calls for the tradeoff of having to wrap the mixin in an additional function call:

// Mixin definition:
const WriteAccess = Mixin(
  _ =>
    class extends _ {
      write(file: string, content: string) {
        // Do some write action
      }
    }
)

// Mixin usage:
class User {
  constructor(protected name: string) {}
}

class PrivilegedUser extends WriteAccess(User) {
  constructor(name: string, protected role: 'editor' | 'admin') {
    super(name) // <- type-hinted!
  }

  otherMethod() {
    this.write('/some/file/path', 'some content') // <- type-hinted!
  }
}

Timer

A cross-runtime performance timer implementation:

const { Timer } = require('@livy/util/lib/timer')

const timer = new Timer()

// Start the timer
timer.start()

// ... do some work ...

// Get number of milliseconds elapsed since timer.start()
timer.get()

// ... do some work ...

// Still get number of milliseconds elapsed since timer.start()
timer.get()

// Stop and reset the timer
timer.reset()

Formatter-Related Utilities

IncludedRecordProperties

A simple TypeScript type which represents an object with all LogRecord properties mapped to boolean values.

This can be useful as type of a formatter's option that determines which parts of a log record should be represented in the formatted output — see for example the LineFormatter implementation.

AbstractBatchFormatter

A base class for formatters to extend which implements formatBatch as a series of format calls, joined by a delimiter (which by default is the EOL determined by the environment, can be changed by overriding the batchDelimiter property):

const { AbstractBatchFormatter } = require('@livy/util/lib/abstract-batch-formatter')

class QuestionableFormatter extends AbstractBatchFormatter {
  format(record) {
    return '?'
  }
}

const q = new QuestionableFormatter()
q.format({ ... }) // '?'
q.formatBatch([{ ... }, { ... }, { ... }]) // '?\n?\n?'

See also: FormatterInterface

LineFomatter

This formatter — because it's very ubiquitous throughout the project — is implemented here to remove complexity from the dependency graph (i.e. to avoid a mutual dependency with @livy/line-formatter).

See @livy/line-formatter for documentation.

Handler-Related Utilities

This includes various base classes, mixins and check functions for implementing handlers.

isClosableHandlerInterface

Check whether a handler is closable.

isFormattableHandlerInterface

Checks whether a handler implements the FormattableHandlerInterface

isProcessableHandlerInterface

Check whether a handler can use processors.

isSyncHandlerInterface

Check whether a handler can be invoked synchronously.

MirrorSyncHandlerMixin

Implements the mandatory asynchronous handler methods handle and handleBatch by replicating the behavior of their corresponding synchronous methods:

const SomeBaseClass = require('SomeBaseClass')
const {
  MirrorSyncHandlerMixin
} = require('@livy/util/lib/handlers/mirror-sync-handler-mixin')

class Handler extends MirrorSyncHandlerMixin(SomeBaseClass) {
  handleSync(record) {
    // ...
  }

  handleBatchSync(record) {
    // ...
  }
}

const handler = new Handler()
handler.handle()      // calls handler.handleSync()
handler.handleBatch() // calls handler.handleBatchSync()

See also: SyncHandlerInterface

ProcessableHandlerMixin

Makes a handler able to work with processors, implementing the ProcessableHandlerInterface.

It adds:

  • a public processors set.
  • an internal processRecord method which your handler may call with a log record to run all registered processors on it.
  • an internal resetProcessors method which resets all resettable processors.
  • a basic reset method which calls resetProcessors, thus making the handler resettable

RespectLevelMixin

Adds a public level property which defaults to 'debug', as well as a isHandling implementation based on that level.

See also: HandlerInterface

FormattableHandlerMixin

Adds a formatter property to the applied-to class with support for an implicit default formatter:

const SomeBaseClass = require('SomeBaseClass')
const SomeFormatter = require('SomeFormatter')
const {
  FormattableHandlerMixin
} = require('@livy/util/lib/handlers/formattable-handler-mixin')

class Handler extends FormattableHandlerMixin(SomeBaseClass) {
  /**
   * Allow setting a formatter through a handler option
   */
  constructor({ formatter, ...options }) {
    // Pass other options up
    super(options)

    // Set the `this.explicitFormatter` property.
    // If the user provides no `formatter` option, it will be undefined
    // and `this.formatter` will return the default formatter
    this.explicitFormatter = formatter
  }

  /**
   * Define the default formatter (required)
   */
  get defaultFormatter() {
    return new SomeFormatter()
  }

  handle(record) {
    // ...
  }
}

See also: FormattableHandlerInterface

AbstractBatchHandler

This is a base handler class that implements the handleBatch and handleBatchSync methods by sequentially executing handle/handleSync for each passed record.

See also: HandlerInterface

AbstractLevelBubbleHandler

Base handler class (extending the AbstractBatchHandler) which adds a level and a bubble option and implements the isHandling method based on the configured level:

const {
  AbstractLevelBubbleHandler
} = require('@livy/util/lib/handlers/abstract-level-bubble-handler')

class Handler extends AbstractLevelBubbleHandler {
  handle(record) {
    // ...do something with the record...

    // Indicate bubbling behavior based on the `bubble` option:
    return !this.bubble
  }
}

See also:

AbstractFormattingProcessingHandler

Base handler class extending the AbstractLevelBubbleHandler with the FormattableHandlerMixin and ProcessableHandlerMixin. It completely abstracts the nitty gritty details of writing a handler with formatter and processor support away from you so you only have to implement a write method:

const {
  AbstractFormattingProcessingHandler
} = require('@livy/util/lib/handlers/abstract-formatting-processing-handler')

class FileHandler extends AbstractFormattingProcessingHandler {
  async write(record, formattedRecord) {
    await someFileHandler.write(formattedRecord)
  }
}

There's also AbstractSyncFormattingProcessingHandler to implement a synchronous handler by implementing writeSync:

const {
  AbstractSyncFormattingProcessingHandler
} = require('@livy/util/lib/handlers/abstract-formatting-processing-handler')

class SyncFileHandler extends AbstractSyncFormattingProcessingHandler {
  writeSync(record, formattedRecord) {
    someFileHandler.writeSync(formattedRecord)
  }

  // You can still implement your own asynchronous `write` method,
  // but if you omit it, it will just fall back to `writeSync` instead
  async write(record, formattedRecord) {
    await someFileHandler.write(formattedRecord)
  }
}