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

techdebt

v2.1.1

Published

An attempt to show technical debt to sponsors

Downloads

17

Readme

techdebt

Utils function to compute technical debt metrics and display them on the support of your choice.

Install

npm install --save-dev techdebt

Get started

This package is nothing more than an aggregation of helpers to get, save and display metrics.

It helps you to easily write a small script that computes metrics representing your technical debt. A good idea would be to run this script during continuous integration so that it updates a technical debt dashboard or Slack channel.

Simple example: display the todo comments in Slack

const techdebt = require('techdebt')
const slackClient = require('techdebt/clients/slack')
const fsHelper = require('techdebt/helpers/fs')

slackClient.initialize({
  hookUrl: 'https://hooks.slack.com/services/xx/xx/xx',
  channel: '#techdebt',
  username: 'Techdebt bot'
})

techdebt.run([
  {
    get: () => fsHelper.getRegexMatches('src', /todo(.*)/gi),
    format: (matches) => ({
      title: 'Todos in code',
      text: matches.length > 0 : matches.join('\n') : 'No todos in code ☀️',
      color: matches.length > 0 : 'warning' : 'good'
    })
  },
])
.then(formatedMetrics => slackClient.post('Techdebt report', formatedMetrics))
.then(() => {
  return process.exit()
})
.catch(error => {
  console.error(error)
  return process.exit(1)
})

example result

More complex example: display the historic of todos count in Slack

Sometimes it's useful to get the history of a metric and display it as a graph. To save a metric you can use any API that you like. The simplest API I found is datadog that allows to save metrics and take a snapshot of a graph of the metric.

const techdebt = require('techdebt')
const slackClient = require('techdebt/clients/slack')
const fsHelper = require('techdebt/helpers/fs')

slackClient.initialize({
  hookUrl: 'https://hooks.slack.com/services/xx/xx/xx',
  channel: '#techdebt',
  username: 'Techdebt bot'
})
datadogClient.initialize({
  api_key: 'xxx',
  app_key: 'xxx'
})

techdebt.run([
  {
    get: () => {
      const count = fsHelper.countRegex('src', /todo/gi)
      return count
    },
    save: (count) => datadogClient.post('techdebt.todos', count),
    format: (count) => datadogClient.get('techdebt.todos', 3600 * 24 * 30)
      .then(snapshotUrl => ({ text: 'Todos in code', image_url: snapshotUrl }))
  }
])
.then(formatedMetrics => slackClient.post('Techdebt report', formatedMetrics))
.then(() => {
  return process.exit()
})
.catch(error => {
  console.error(error)
  return process.exit(1)
})

example result

API doc

main

techdebt.run(metrics)

Takes an array of metrics and return a promise of formated metrics.

Example:

const techdebt = require('techdebt')

techdebt.run(metrics)
.then(formatedMetrics => {
  // do whatever you want with formated metrics
})

Metric

{

  get: Function
  save: Function
  format: Function
}

get()

A function that fetch the metric value. It returns a value of any type (you'll have to handle the value).

It can return a value or the promise of a value.

Example:

get: () => fsHelper.countRegex('src', /todo/gi)

save(metricValue) (optional)

A function that save the value on a third party tool such as Datadog, Google Spreadsheet etc.

If it returns a promise, the format function will wait for this promise to be resolved before execution.

Example:

const save = (metricValue) => datadogClient.post('techdebt.my_metric', metricValue)

format(metricValue)

A function that format the value as expected.

Example:

format = (metricValue) => ({
  title: 'Todos count in code',
  text: metricValue
})

Clients

Slack

slackClient.initialize(options)

Initialize the client with options

Example:

const slackClient = require('techdebt/clients/slack')

slackClient.initialize({
  hookUrl: 'https://hooks.slack.com/services/xx/xx/xx', // required
  channel: '#techdebt', // required
  username: 'Techdebt bot' // optional
})
slackClient.post(title, attachments)

Post attachments to Slack.

Datadog

Using this client requires to install dogapi package:

npm install --save-dev dogapi
datadogClient.initialize(options)
const datadogClient = require('techdebt/clients/datadog')

datadogClient.initialize({
  api_key: 'xxx', //required
  app_key: 'xxx' // required
})

Codecov

codecovClient.initialize(options)
const codecovClient = require('techdebt/clients/codecov')

codecovClient.initialize({
  accessToken: 'xxx', //required
  repo: 'owner/repo', // required
  branch: 'xxx' // required
})
codecovClient.get()

Return a promise on the last code coverage ratio.

codecovClient.get()
.then(({ timestamp, ratio }) => {
  // ratio between 0 and 100
})
datadogClient.post(metricName, metricValue, timestamp)

Post a metric value that will be saved to datadog and wait for the metric to be fetchable (datadog has a delay in serving posted metrics).

The timestamp attribute is optional (default is now)

It returns a promise that resolves when the metric is saved.

datadogClient.get(metricName, period)

Get the snapshot of a graph of a metric.

It returns a promise of the URL of the snapshot image.

missing a client? Trello, Google sheet ? Please write an issue

Helpers

packages

This helper requires to install npm-check

npm install --save-dev npm-check

This helper allow you to know which of your dependencies are unused or need upgrades

packages.get(type)

type can be one of major, minor, unused, upToDate.

It returns a promise of the list of packages corresponding to the type.

packages.slackFormat(type, packages)

Returns a predefined Slack attachment format

Example:

const slackClient = require('techdebt/clients/slack')
const packages = require('techdebt/helpers/packages')
const techdebt = require('techdebt')

slackClient.initialize({
  hookUrl: 'https://hooks.slack.com/services/xx/xx/xx',
  channel: '#techdebt',
  username: 'Techdebt bot'
})

techdebt.run([
  {
    get: () => packages.get('major'),
    format: (items) => packages.slackFormat('major', items)
  },
  {
    get: () => packages.get('minor'),
    format: (items) => packages.slackFormat('minor', items)
  },
  {
    get: () => packages.get('unused'),
    format: (items) => packages.slackFormat('unused', items)
  },
  {
    get: () => packages.get('upToDate'),
    format: (items) => packages.slackFormat('upToDate', items)
  }
])
.then(formatedMetrics => {
  return slackClient.post('Techdebt report', formatedMetrics)
})
.then(() => {
  return process.exit()
})
.catch(error => {
  console.error(error)
  return process.exit(1)
})

example result

fsHelper

A librairy of helper functions to analyse source files.

fsHelper.readRecursively(root)

Get the recursive list of files in a directory.

Example:

fsHelper.readRecursively('src')
fsHelper.countLines(root, options)

Sum the lines of files in a directory (recursively). You can specify an extension in the options. The returned value is a promise of the line count.

Example:

fsHelper.countLines('src', { extension: 'js' }).then(lineCount => ...)
fsHelper.countRegex(root, regex, options)

Sum the number of occurence if a regex in a directory (recursively). You can specify an extension in the options. The returned value is a promise of the count.

Example:

fsHelper.countRegex('src', /todo/gi, { extension: 'js' }).then(count => ...)
const slackClient = require('techdebt/clients/slack')
const datadogClient = require('techdebt/clients/datadog')
const fsHelper = require('techdebt/helpers/fs')
const techdebt = require('techdebt')

slackClient.initialize({
  hookUrl: 'https://hooks.slack.com/services/xx/xx/xx',
  channel: '#techdebt',
  username: 'Techdebt bot'
})
datadogClient.initialize({
  api_key: 'xxx',
  app_key: 'xxx'
})

techdebt.run([
  {
    get: () => {
      const count = fsHelper.countRegex('src', /todo/gi)
      return count
    },
    save: (value) => datadogClient.post('techdebt.todos', value),
    format: (count) => datadogClient.get('techdebt.todos', 3600 * 24 * 30).then(snapshotUrl => ({
      text: 'Todos in code',
      image_url: snapshotUrl
    }))
  },
  {
    get: () => fsHelper.getRegexMatches('src', /todo(.*)/gi),
    format: (matches) => ({
      title: 'Todos in code',
      text: matches.join('\n'),
      color: 'warning'
    })
  }
])
.then(formatedMetrics => {
  return slackClient.post('Techdebt report', formatedMetrics)
})
.then(() => {
  return process.exit()
})
.catch(error => {
  console.error(error)
  return process.exit(1)
})
fsHelper.getRegexMatches(root, regex, options)

Get the matches of a regex in a directory (recursively). You can specify an extension in the options. The returned value is a promise of the matches.

Example:

fsHelper.getRegexMatches('src', /todo(.*)/gi, { extension: 'js' }).then(matches => ...)