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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@sdlcforge/format-and-lint

v1.0.0-alpha.30

Published

Pre-configured formatting and style tool combining prettier and eslint.

Downloads

250

Readme

@sdlcforge/format-and-lint

coverage: 97%

Pre-configured formatting and lint tool combining the best of prettier and eslint. Aka, fandl.

Install

npm i @sdlcforge/format-and-lint

Usage

Note this is an ESM only package. We would like to support CJS in the production release.

CLI

npx fandl lint # runs lint checks only with no changes to files
npx fandl # fixes what it can and reports on the rest
npx fandl --files '**/weird-src/**/*.{js,mjs,cjs,jsx}' # specify files pattern

API

import { formatAndLint } from '@sdlcforge/format-and-lint'

// in the API, we provide actual file paths, which may be relative or absolute
const files = ['index.js', 'src/foo.js', 'src/bar.js']
const { eslint, lintResults } = formatAndLint({ files })
// process the results; the following is essentially what the fandl CLI does
const formatter = await eslint.loadFormatter('stylish')
const resultText = formatter.format(lintResults)

stdout.write(resultText)
// if we had something to say, then that indicates an error/warning in the source
if (resultText !== '') {
  process.exit(1)
}

API reference

API generated with dmd-readme-api.

  • formatAndLint(): Parses, lints, and (when check is false) reformats the files text.
  • linebreakTypesExcept(): A helper function used to sanely build 'blankline' entries in the '@stylistic/padding-line-between-statements' rule.

formatAndLint(options)Promise.<{eslint: object, lintResults: Array.<object>}> source code global index

Parses, lints, and (when check is false) reformats the files text. By default, this function will update the files in-place.

| Param | Type | Default | Description | | --- | --- | --- | --- | | options | object | | The input options. | | [options.check] | boolean | false | If true then the files are linted, but not reformatted. | | [options.noWrite] | boolean | false | If true, then the files are not updated in placed. Has no effect when check = false, but when combined with check = true, means that the text is reformatted and attached to the LintResults, but the files themselves are not updated. You can access reformatted text as part of the result.lintResults[0].output. Unlike results directly from ESLint, output is always present on the LintResult object (rather than only being set if the text is changed. | | [options.eslintConfig] | object | <default eslint config> | A flat (9.x) style array of eslint configuration object to be used in place of the default, out of the box configuration. This may not be specified along with eslintConfigComponents. | | [options.eslintConfigComponents] | object | | An object with zero or more keys corresponding to the base, jsdoc, jsx, test, or additional as discussed in the component based configuration. This may not be specified along with eslintConfig. | | [options.prettierConfig] | object | <default prettier config> | A prettier options object. | | [options.eslint] | object | | A pre-configured ESLint instance. If this is defined, then eslintConfig and eslintConfigComponents will be ignored. | | [options.outputDir] | string | | If provided, then output files (whether reformatted or not) will be written to the specified directory relative to their location in the source. With src/index.mjs => <outputDir>/src/index.mjs, src/foo/bar.mjs => <outputDir>/src/foo/bar.mjs. This option has no effect if check = true or noWrite = true. The relative starting point is controlled with the relativeStem option. | | [options.relativeStem] | string | process.cwd() | Controls the starting point for determining the relative position of files when emitting to outputDir rather than updating in place. Impossible stems will result in an error. E.g., given file src/index.mjs, relativeStem = 'src/foo' is invalid. |

Returns: Promise.<{eslint: object, lintResults: Array.<object>}> - Resolves to an object with two fields. eslint points to the an instance of ESLint. lintResults points to an array of LintResults.

linebreakTypesExcept(...types)Array.<string> source code global index

A helper function used to sanely build 'blankline' entries in the '@stylistic/padding-line-between-statements' rule. Basically, what we often want is to say "we want a blank line between expression type A and all other expression except for B, C, and D." This is useful because the '@stylistic/padding-line-between-statements' rule requires you specify each type where a blank line is required, but it's generally easier to specify a set of expression types for which a blank line is NOT required.E.g.:

'@stylistic/padding-line-between-statements' : [
  'error',
  { blankLine : 'always', prev : '*', next : 'class' },
  {
    blankLine : 'always',
    prev      : linebreakTypesExcept('cjs-export', 'export'),
    next      : 'export',
  },
]

Would require (and/or add) a blank line between a class declaration and anything else, and a blank line between import statements and all other statements except import or cjs-import statements. That way, all your import statements would be grouped together, but would have a blank line between the last import and whatever the next non-import statement is.

| Param | Type | Description | | --- | --- | --- | | ...types | string | A list of the types to exclude from the rule (meaning all other known types are included). |

Returns: Array.<string> - - An array of the non-excluded types.

Component based configuration

Fandl breaks up the configuration into 5 components:

  • 'base' which applies to all Javascript src files,
  • 'jsdoc' which defines JSDoc specific configuration and rules for all src files,
  • 'jsx' which defines additional configuration and rules for JSX files,
  • 'test' which defines additional configuration and rules for test files, and
  • 'additional' which is just a catch all for whatever else you might want to add.

Rather than being forced to redefine the entire default configuration, you can override any one of the components individually by specifying options.eslintConfigComponents.

Note, the component structure is essentially a prototype at this point. Future versions will:

  • Break up 'base' (which is very large) into different semantic types such "correctness", "complexity", and "style".
  • Support arbitrary additional configuration components.
  • Support turning off individual configuration components.

Reformatting process overview

  • The code is run through prettier first mainly because it does a much better job properly indenting code and fitting it within a target width (80 chars).[^1]
  • The partially reformatted code is then reformatted by eslint because prettier (purposely) has very few options and we don't agree with all of them. Specifically, our out of the box configuration:
    • places operators at the beginning of the next line rather than the end of the previous line in multi-line expressions; e.g.:
    const foo = bar // fandl style; generally accepted as easier to read
      && baz
    // vs
    const foo = bar && // prettier style
      baz
    • places else if/else/catch, etc. on a newline; e.g.:
    const foo = bar // fandl style; generally accepted as easier to read
      && baz
    // vs
    const foo = bar && // prettier style
      baz
    • places else if/else/catch, etc. on a newline; e.g.:
    if (a === 1) { // fandl style (Stroustrup); more consistent IMO
      ...
    }
    else { // and easier to scan the page
    ...
    }
    // vs
    if (a === 1) { // prettier default style ("one true brace style")
      ...
    } else { // IMO it's odd to have lexical overhead preceed the flow control keyword
    ...
    }
    • aligns the colons in object declarations; e.g.:
    { // fandl style; easier to read, like a table
      foo           : 'hey',
      longFieldName : 'how are you?',
    }
    // vs
    { // prettier style
      foo : 'hey',
      longFieldName : 'how are you?',
    }

[^1]: I perhaps falsely remember eslint actually doing a better re indenting code, but in any case there are two issue with the latest eslint based reformatting. First, it miscounts the correct indention level where '('s were involved in boolean expressions. Second, eslint failed automatically break up long lines. (As of @stylistic/eslint-plugin: 2.6.4, eslint: 8.50.0; have since upgraded but not retested since it's working as is.)