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

@statoscope/stats-validator

v5.28.1

Published

Statoscope stats validator

Downloads

69,518

Readme

Statoscope Stats Validator

npm version Financial Contributors on Open Collective

This package contains a toolkit to validate stats.

API

new Validator(config: Config, rootDir?: string)

Create the Validator instance with config (see below), relative rootDir-directory (current working directory by default)

validate(input: string, reference?: string): Promise<Result>

Apply rules to input and reference (if specified) files.

input-file is a current stats (e.g. stats of current branch).

reference-file is a stats to compare with (e.g. stats of master branch).

Returns validation results (see below).

Config

type Config = {
  plugins?: Array<string | [string, string]>;
  rules: Record<string, RuleDesc<unknown>>;
  reporters?: ReporterConfig[];
  warnAsError?: boolean;
};

plugins

List of plugins (see more about plugins API below).

The main goal of a plugin is providing some rules for validation.

There is a plugin to validate webpack stats (need to be installed)

npm install --save-dev @statoscope/stats-validator-plugin-webpack

statoscope.config.js:

module.export = {
  validate: {
    plugins: ['@statoscope/webpack'],
    rules: {
      '@statoscope/webpack/no-modules-deopts': ["error"]
    }
  }
};

Plugin path resolution

There are a few ways to how you can specify a plugin name:

  • full package name
  • short package name (please see example below)
  • relative or absolute path

Here are the examples with all possible ways:

statoscope.config.js:

module.export = {
  validate: {
    plugins: [
      'statoscope-stats-validator-plugin-foo', // full package name
      '@statoscope/webpack', // short package name, resolves to @statoscope/stats-validator-plugin-webpack
      '@foo/my-validator', // short package name, resolves to @foo/statoscope-stats-validator-plugin-my-validator
      'webpack', // short package name, resolves to statoscope-stats-validator-plugin-webpack
      ['./my/plugin.js', 'my-plugin'], // relative path (relative config path)
      [require.resolve('./my/another/plugin.js'), 'my-another-plugin'] // absolute path
    ],
    rules: {
      'statoscope-stats-validator-plugin-foo/some-rule': ['error'],
      '@statoscope/webpack/no-modules-deopts': ['error'],
      'foo/some-rule': ['error'],
      'my-plugin/some-rule': ['error'],
      'my-another-plugin/some-rule': ['error'],
    }
  }
};

To use short package name, its name must have statoscope-stats-validator-plugin--prefix or @statoscope/stats-validator-plugin--prefix.

Note that relative or absolute path should be specified with an alias

rules

List of rules (see more about rules API below).

Rule validates some part of a bundle.

Every item of the list contains: rule name, execution mode and rule options (optional).

Execution modes:

  • error - rules messages have treated as an error
  • warn - rules messages have treated as a warning
  • off - rules messages have ignored

statoscope.config.js:

module.export = {
  validate: {
    plugins: [
      '@statoscope/webpack',
    ],
    rules: {
      '@statoscope/webpack/restricted-packages': ['error', ['lodash']],
    }
  }
};

reporters

List of reporters (see more about reporters API below).

Reporter handles validation results.

There are two builtin reporters:

statoscope.config.js:

module.export = {
  validate: {
    plugins: [
      '@statoscope/webpack',
    ],
    reporters: [
      'statoscope-stats-validator-reporter-foo', // full package name
      '@statoscope/stats-report', // short package name, resolves to @statoscope/stats-validator-reporter-stats-report
      'stats-report', // short package name, resolves to @statoscope/stats-validator-reporter-stats-report or statoscope-stats-validator-reporter-stats-report
      ['./my/plugin.js', 'my-report'], // relative path (relative config path)
      [require.resolve('./my/another/report.js'), 'my-another-report'] // absolute path
    ],
    rules: {
      '@statoscope/webpack/restricted-packages': ['error', ['lodash']],
    }
  }
};

To use short package name, its name must have statoscope-stats-validator-reporter--prefix or @statoscope/stats-validator-reporter--prefix.

ConsoleReporter has used by default.

warnAsError

Treat warn-messages from rules as errors.

Plugins API

Plugin is a function that must return a plugin descriptor:

const myPlugin = () => {
  return {
    prepare(files) {
      return doSomethingWithFiles(files);
    },
    rules: {
      foo: fooRule,
      bar: barRule,
    }
  };
};

prepare

prepare-function of every plugin will be called for input and reference files.

rules

List of rules that plugin provides.

Rules API

Rule is a function that validates some part of bundle:

const myRule = (params, data, api) => {
  if (!isOK(data)) {
    api.message('Something is wrong');
  }
}
  • params - options from config (e.g. 'my-plugin/my-rule': ['error', { foo: 'bar'}])
  • data - input and reference files content
  • api - rule API instance

api.message(text: string, options?: APIFnOptions): void

Add validation message from the rule.

options.filename?: string

File name that the message has associated with

options.compilation?: string

Compilation id that the message has associated with

options.related?: RelatedItem[]

Entities that the message has associated with

api.message(
  'Something is wrong with module ./foo.js',
  {
    related: [
      { type: 'module', id: './foo.js' }
    ]
  }
);

There are several types of related items:

  • module
  • package
  • package-instance
  • resource
  • entry
  • compilation

options.details?: Details

Details for reporters

There are several types of details:

text

Used by text-reporters

api.message(
  'Something is wrong with module ./foo.js',
  {
    details: [
      { 
        type: 'text',
        content: [
          'Here are the module reasons:',
          ...module.resons.map(r => r.name)
        ]
      }
    ]
  }
);
❌ Something is wrong with module ./foo.js
  Here are the module reasons:
  ./bar.js
  ./baz.js

content might be string | string[] | (() => string | string[])

tty

Used by TTY-reporters (e.g. ConsoleReporter)

import chalk from 'chalk';

api.message(
  'Something is wrong with module ./foo.js',
  {
    details: [
      { 
        type: 'tty',
        content: [
          chalk.cyan('Here are the module reasons:'),
          ...module.resons.map(r => chalk.yellow(r.name))
        ]
      }
    ]
  }
);

content might be string | string[] | (() => string | string[])

discovery

Used by discovery-reporters (e.g. StatsReportReporter)

The main idea around this type of details is passing some data to stats report viewer (based on DiscoveryJS).

It helps to discover validation message with flexible UI.

api.message(`Module ${module.name} should not be used`, {
  details: [
    {
      type: 'discovery',
      query: `
      $input: resolveInputFile();
      { module: #.module.resolveModule(#.compilation) }
      `,
      payload: {
        context: {
          compilation: compilation.hash,
          module: module.name,
        },
      },
      view: {
        view: 'module-item',
        data: `{ module }`
      }
    },
  ],
});

See examples at Stats Validator Webpack Plugin

api.getStorage(): Storage

Get list of validation messages (results) that was emitted by the rule.

const items = api.getStorage();

for (const item of items) {
  console.log(item.message);
}

Every storage item has the following format:

type Item = {
  message: string; // item message
  filename?: string; // file name that the message has associated with
  compilation?: string; // compilation id that the message has associated with
  details?: Details; // rule's details (see api.message method for more info)
  related?: RelatedItem[]; // rule's related entities (see api.message method for more info)
};

api.setRuleDescriptor(descriptor: RuleDescriptor): void

Set rule meta-data.

api.setRuleDescriptor({
  description: `My pretty cool rule`,
  package: {
    name: 'my-package-with-validator-plugin',
    version: '7.7.7',
  },
});

api.getRuleDescriptor(): RuleDescriptor | null

Get rule meta-data

Reporters API

Reporter is a class with run method:

interface Reporter {
  run(result: Result): Promise<void>;
}

Example:

class MyConsoleReporter {
  run(result) {
    for (const rule of result.rules) {
      const ruleDescriptor = rule.api.getRuleDescriptor();
      console.log(`Rule name: ${rule.name}`);
      console.log(`Rule description: ${ruleDescriptor.description}`);

      const items = rule.api.getStorage();

      for (const item of items) {
        console.log(item.message);

        for (const detail of item.details) {
          if (detail.type === 'tty') {
            console.log(detail.content);
          }
        }
      }
    }
  }
}

Custom Plugin Example

Create custom plugin script:

my-custom-stats-validator-plugin.js:

module.exports = () => {
  return {
    rules: {
      'my-rule': (ruleParams, data, api) => {
        const result = data.query('some jora query', data.files, {ruleParams});

        if(result.notOk) {
          api.message(':(')
        }
      }
    }
  }
}

Add this plugin to statoscope config:

statoscope.config.js:

module.exports = {
  validate: {
    plugins: ['@statoscope/webpack', ['./my-custom-stats-validator-plugin.js', 'my-plugin']],
    rules: {
      '@statoscope/webpack/restricted-packages': ['error', ['foo']],
      'my-plugin/my-rule': ['error', 'rule params'],
    },
  }
}

For more rule examples, please see existing rule sources