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

curated-linter

v1.1.2

Published

Creates curated linters, like standard

Downloads

4

Readme

Build Status Standard - JavaScript Style Guide codecov

curated-linter (WIP)

Makes curated ESLint linters, like standard

Work in progress

Not all documented features are implemented.

Feel free to contribute.

Table of contents

What is a curated linter?

Example

In this example we create our curated linter as an npm package.

package.json:

{
	"name": "nofoobar",
	"main": "index.js",
	"bin": { "nofoobar": "index.js" }
}

Yes, the CLI is the same module as the API.

index.js

For instantiation, we do not provide an config object—we provide a function that will return a new config object with each call—a getter.

#!/usr/bin/env node

const CuratedLinter = require('curated-linter')

// `config` getter function
const getConfig = () => ({
  name: 'nofoobar', // CLI name and `package.json` config key
  packageJson: true, // read end user config from `package.json`
  gitIgnore: true, // (also) ignore what git ignores
  formatter: (results, config) => { // customize your CLI error output
    return `${config.name}: Nope. Do not use \`foo\` or \`bar\``
    // or… something more real than this
  },
  CLIEngineOptions: { // options for ESLint’s `CLIEngine`
    ignore: false,
    useEslintrc: false,
    rules: { // http://eslint.org/docs/rules/
      'id-blacklist': ['foo', 'bar'] // http://eslint.org/docs/rules/id-blacklist
      // your usage may include all your favorite rules!
    }
    // for more `CLIEngine` options: http://eslint.org/docs/developer-guide/nodejs-api#cliengine
  }
  // not all curated-linter configuration options are used in this example
})

const noFoobar = new CuratedLinter(getConfig)

// The API is ready. Now just export it!
module.exports = noFoobar

This example hopefully provided you with a basic understanding. Read below for the API and some awesome features.

API

new CuratedLinter(getConfig)

Constructs a curated linter

This is the main export of this package.

getConfig must be a function that returns a new config object with each call.

config

Contains all of the configuration, policy and behavior of a desired curated linter

The config object is provided to the curated linter instance firstly via the getConfig constructor argument.

It can also be provided to the lintText and lintFiles methods, for the sake of possibly allowing the end users to override or extend the curated configuration.

Following are all of the possible properties of config:

name

Machine name of the curated linter

Must be provided if the CLI feature is to be used.

bugs

URL where the end-user should report bugs

Must be provided if the CLI feature is to be used.

packageJson

Whether to allow end user configuration via package.json

gitIgnore

Whether to (also) ignore according to .gitignore

This determines whether, in addition to any other ignore configuration, to ignore files that are ignored by a possibly existing .gitignore.

The .gitignore that may be read is the one that may be at the same directory as the package.json.

ignore

List of glob file patterns to ignore

cwd

Relative file paths will be resolved to this

Defaults to process.cwd().

curatedExtensions

List of official curated extensions

CLIEngineOptions

Will be passed to CLIEngine

This is where you may define your rules, plugins, etc.

Tip: if you can’t find a certain property on this interface, take a look at the baseConfig property.

Caveat: For the sake of the config.gitIgnore feature, CuratedLinter does its own file deglobbing and serves ESLint absolute file paths. Therefore, instead of using config.CLIEngineOptions.ignore(*) options, it is recommended that you set config.CLIEngineOptions.ignore to false and use config.ignore, instead.

formatter

Formats the CLI error messages

If this is a string, it must represent a built-in ESLint formatter.

Otherwise, it must be a function. It will be called as formatter(results, config). Except for the config argument, the signature is identical to ESLint formatters.

The config provided will be post user overrides.

defaultFiles

Files to lint by default

Whether via the CLI or via #lintFiles, if no files provided, these will be linted.

An array of globs.

End user API

#lintText(text, config)

Lints provided text

#lintFiles(files, config)

Lints files

The ESLint results object

Resolved value of promises returned by #lintFiles and #lintText

Documentation of the ESLint results object can be found in ESLint’s #executeOnFiles documentation.

End user CLI

To provide end users with a CLI, the config.name property must be provided.

Also, there must be a package.json bin property, like so:

{
  "name": "nofoobar",
  "bin": {
    "nofoobar": "index.js"
  }
}

The value of the property under bin (here "index.js") must be a module where CuratedLinter is instantiated. No further method calling required. Thus your main export and your bin can be the same module.

To allow this unified main/bin "magic" , the property under the bin property must be identical to your config.name.

The module must start with the Node.js shebang (#!/usr/bin/env node).

End user configuration via package.json

If config.packageJson is true, then a config from a certain property of the end user’s package.json will be read and applied as explained in user overrides. That certain property is config.name.

For example if config.name === 'nofoobar':

{
  "name": "the-users-package",
  "nofoobar": {
    "ignore": ["**/*.test.js"]
  }
}

End user overrides

This is about implementing a policy regarding whether, what and how the end user of the curated linter is allowed to override or extend, the curated config.

You may implement whatever policy you like, by having your getConfig return a version of config that is protected using proxies.

Whether from end user config in package.json and/or from the end user passing config to lintText or lintFiles, those user configs will be merged into the config that your getConfig returned, using deep assignment. This means that, if your getConfig provides an unprotected config, the user will be able to override any property in that tree.

Overrides occur on method invocation (the CLI also uses those methods). On each such invocation, your curated config is retrieved by calling your getConfig. Thus, overrides applied on one method call will not persist on the instance.

Example of protected config using proxies

The only allowed override is that the id-blacklist rule can be added more identifiers:

const CuratedLinter = require('curated-linter')

const frozen = {
  set: () => false
}

const append = {
  set: (target, property, value) => {
    target.push(value) // convert setting into appending
    return true
  }
}

const getConfig = () => (new Proxy({
  CLIEngineOptions: new Proxy({
    name: 'nofoobar',
    rules: new Proxy({
      'id-blacklist': new Proxy([
        'foo',
        'bar'
      ], append)
    }, frozen)
  }, frozen)
}, frozen))

const noFooBar = new CuratedLinter(getConfig)
module.exports = noFooBar

As you can see, using proxies, it is possible to implement any override/extension policy.

Curated extensions

This feature allows official, curated extensions to be automatically used if the end user has any of them installed.

An official, curated extension is a separate ESLint sharable configuration package.

Each member of a provided config.curatedExtensions array is expected to be a name of an ESLint shareable configuration. The eslint-config- prefix may be omitted. Each such package, if the end user has it installed, will be pushed to the end of the config.CLIEngineOptions.baseConfig.extends array (will be created if undefined and will be made into an array if false).