Skip to content

Commit

Permalink
Port to new ESLint API (#275)
Browse files Browse the repository at this point in the history
* Validate engine versions + dependency list

* Probably make all pass

* Fix failing tests

* Fix Node 12 support

* Remove leftover todo comment

* Improve naming of "results" post refactoring

* Extract `hasErrors` and `hasWarnings` variables

* Add coverage report

* Exclude tests from type checks

As else it checks `tmp/standard/`, which doesn't pass

* Tweak type format

* Extract utility methods

* Remove non-needed @ts-ignore

* Add unit tests for utils

* We need to ensure we run the clone test first

* Rename `build` to `lint`

* Rename `Linter` to `StandardEngine`

* Update README + CHANGELOG

* Sync `dependabot.yml` with standard/standard repo

See standard/standard#1752

* Update CHANGELOG.md

Co-authored-by: Linus Unnebäck <linus@folkdatorn.se>
  • Loading branch information
voxpelli and LinusU committed Nov 30, 2021
1 parent 606f80a commit 5f66f04
Show file tree
Hide file tree
Showing 18 changed files with 417 additions and 155 deletions.
24 changes: 16 additions & 8 deletions .github/dependabot.yml
@@ -1,13 +1,21 @@
# For more information see: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
- package-ecosystem: 'github-actions'
directory: '/'
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: 'daily'
interval: "daily"
labels:
- "dependency"
# Always increase the version requirement to match the new version.
versioning-strategy: increase

- package-ecosystem: 'npm'
directory: '/'
- package-ecosystem: "github-actions"
directory: "/"
ignore:
- dependency-name: "actions/*"
update-types:
["version-update:semver-minor", "version-update:semver-patch"]
schedule:
interval: 'daily'
interval: "daily"
labels:
- "github-actions"
41 changes: 41 additions & 0 deletions .github/workflows/lint.yml
@@ -0,0 +1,41 @@
name: 'linting'

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
lint:
runs-on: 'ubuntu-latest'

strategy:
matrix:
node-version: ['lts/*']
fail-fast: false

steps:
- name: 'Checkout Project'
uses: 'actions/checkout@v2'
with:
fetch-depth: 0

- name: Use Node.js ${{ matrix.node-version }}
uses: 'actions/setup-node@v2'
with:
node-version: ${{ matrix.node-version }}

- name: 'Cache Node dependencies'
uses: 'actions/cache@v2'
with:
path: '~/.npm'
key: ${{ runner.os }}-node-${{ hashFiles('**/package.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: 'Install Dependencies'
run: 'npm install'

- name: 'Run Tests'
run: 'npm run check'
8 changes: 4 additions & 4 deletions .github/workflows/nodejs.yml
Expand Up @@ -17,17 +17,17 @@ jobs:

steps:
- name: 'Checkout Project'
uses: 'actions/checkout@v2.4.0'
uses: 'actions/checkout@v2'
with:
fetch-depth: 0

- name: Use Node.js ${{ matrix.node-version }}
uses: 'actions/setup-node@v2.4.1'
uses: 'actions/setup-node@v2'
with:
node-version: ${{ matrix.node-version }}

- name: 'Cache Node dependencies'
uses: 'actions/cache@v2.1.7'
uses: 'actions/cache@v2'
with:
path: '~/.npm'
key: ${{ runner.os }}-node-${{ hashFiles('**/package.json') }}
Expand All @@ -38,4 +38,4 @@ jobs:
run: 'npm install'

- name: 'Run Tests'
run: 'npm test'
run: 'npm run test-ci'
1 change: 1 addition & 0 deletions .gitignore
@@ -1,2 +1,3 @@
node_modules/
tmp/
coverage/
61 changes: 61 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,67 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## 15.0.0 YYYY-MM-DD

- **BREAKING CHANGE:** To avoid confusion with ESLint exports and types, our `Linter` class has been renamed to `StandardEngine` and `cli()` now takes a `standardEngine` key instead of a `linter` key if a custom engine wants to be provided. #275
- **BREAKING CHANGE:** Removed use of ESLint's deprecated `CLIEngine` API. This affects the `eslintConfig` option to our `StandardEngine` (formerly called `Linter`) constructor. #275
- **BREAKING CHANGE:** Print additional label on warnings (to separate them from errors) b7c1e17
- **BREAKING CHANGE:** Drop support for Node 10.x. Now require ESM-compatible Node.js versions: `^12.20.0 || ^14.13.1 || >=16.0.0` #252
- **BREAKING CHANGE:** the `parseOpts` option to the `StandardEngine` (formerly called `Linter`) constructor has been replaced with a new `resolveEslintConfig` one
- Change: make `--verbose` the default #232


## 14.0.1 2020-08-31

- _Missing release notes_

## 14.0.0 2020-08-29

- _Missing release notes_

## 13.0.0 2020-08-27

- _Missing release notes_

## 12.1.1 2020-05-21

- Enhancement: Allow passing in a custom linter to `cli`

## 12.0.1 2020-04-30

- Enhancements: Add ts-standard to README linters list
- Fixes: Bump deglob & minimist dependencies

## 12.0.0 2019-08-19

- **BREAKING CHANGE:** Remove `bundle.js` from the list of default ignored files
- **BREAKING CHANGE:** Ignore patterns from `.git/info/exclude` in addition to `.gitignore`
- Enhancement: Update deglob to 4.x

## 11.0.1 2019-07-12

- _Missing release notes_

## 11.0.0 2019-07-11

- _Missing release notes_

## 10.0.0 2018-08-30

- _Missing release notes_

## 9.0.0 2018-05-15

- _Missing release notes_

## 8.0.1 2018-03-02

- _Missing release notes_

## 8.0.0 2018-02-18

- _Missing release notes_

## 7.2.0 2017-11-07

- New Feature: `noDefaultIgnore` option to can now be used to turn off default ignores.
Expand Down
18 changes: 7 additions & 11 deletions README.md
Expand Up @@ -42,9 +42,9 @@ Create the files below and fill in your own values for `options.js`.

```js
// programmatic usage
const { Linter } = require('standard-engine')
const { StandardEngine } = require('standard-engine')
const opts = require('./options.js')
module.exports = new Linter(opts)
module.exports = new StandardEngine(opts)
```

### `cli.js`
Expand All @@ -64,6 +64,7 @@ const eslint = require('eslint')
const path = require('path')
const pkg = require('./package.json')

/** @type {import('standard-engine').StandardEngineOptions} **/
module.exports = {
// homepage, version and bugs pulled from package.json
version: pkg.version,
Expand All @@ -73,7 +74,7 @@ module.exports = {
cmd: 'pocketlint', // should match the "bin" key in your package.json
tagline: 'Live by your own standards!', // displayed in output --help
eslintConfig: {
configFile: path.join(__dirname, 'eslintrc.json')
overrideConfigFile: path.join(__dirname, 'eslintrc.json')
},
cwd: '' // current working directory, passed to eslint
}
Expand Down Expand Up @@ -293,13 +294,13 @@ module.exports = {
}
```

This function is called with the current ESLint config (the options passed to [ESLint's `CLIEngine`](http://eslint.org/docs/developer-guide/nodejs-api#cliengine)), the options object (`opts`), any options extracted from the project's `package.json` (`packageOpts`), and the directory that contained that `package.json` file (`rootDir`, equivalent to `opts.cwd` if no file was found).
This function is called with the current ESLint config (the options passed to the [`ESLint`](https://eslint.org/docs/developer-guide/nodejs-api#-new-eslintoptions) constructor), the options object (`opts`), any options extracted from the project's `package.json` (`packageOpts`), and the directory that contained that `package.json` file (`rootDir`, equivalent to `opts.cwd` if no file was found).

Modify and return `eslintConfig`, or return a new object with the eslint config to be used.

## API Usage

### `engine.lintText(text, [opts])`
### `async engine.lintText(text, [opts])`

Lint the provided source `text` to enforce your defined style. An `opts` object may
be provided:
Expand Down Expand Up @@ -348,12 +349,7 @@ const results = {
}
```

### `results = engine.lintTextSync(text, [opts])`

Synchronous version of `engine.lintText()`. If an error occurs, an exception is
thrown. Otherwise, a `results` object is returned.

### `engine.lintFiles(files, [opts], callback)`
### `async engine.lintFiles(files, [opts])`

Lint the provided `files` globs. An `opts` object may be provided:

Expand Down
36 changes: 18 additions & 18 deletions bin/cmd.js
Expand Up @@ -5,15 +5,15 @@ const getStdin = require('get-stdin')

/**
* @typedef StandardCliOptions
* @property {import('../').Linter} [linter]
* @property {import('../').StandardEngine} [standardEngine]
* @property {string} [cmd]
* @property {string} [tagline]
* @property {string} [homepage]
* @property {string} [bugs]
*/

/**
* @param {Omit<import('../').LinterOptions, 'cmd'> & StandardCliOptions} rawOpts
* @param {Omit<import('../').StandardEngineOptions, 'cmd'> & StandardCliOptions} rawOpts
* @returns {void}
*/
function cli (rawOpts) {
Expand All @@ -24,7 +24,7 @@ function cli (rawOpts) {
...rawOpts
}

const standard = rawOpts.linter || new (require('../').Linter)(opts)
const standard = rawOpts.standardEngine || new (require('../').StandardEngine)(opts)

const argv = minimist(process.argv.slice(2), {
alias: {
Expand Down Expand Up @@ -118,11 +118,11 @@ Flags (advanced):
}

Promise.resolve(argv.stdin ? getStdin() : '').then(async stdinText => {
/** @type {import('eslint').CLIEngine.LintReport} */
let result
/** @type {import('eslint').ESLint.LintResult[]} */
let results

try {
result = argv.stdin
results = argv.stdin
? await standard.lintText(stdinText, lintOpts)
: await standard.lintFiles(argv._, lintOpts)
} catch (err) {
Expand All @@ -141,29 +141,29 @@ Flags (advanced):
return
}

if (!result) throw new Error('expected a result')
if (!results) throw new Error('expected a results')

if (outputFixed) {
if (result.results[0] && result.results[0].output) {
if (results[0] && results[0].output) {
// Code contained fixable errors, so print the fixed code
process.stdout.write(result.results[0].output)
process.stdout.write(results[0].output)
} else {
// Code did not contain fixable errors, so print original code
process.stdout.write(stdinText)
}
}

if (!result.errorCount && !result.warningCount) {
const hasErrors = results.some(item => item.errorCount !== 0)
const hasWarnings = results.some(item => item.warningCount !== 0)

if (!hasErrors && !hasWarnings) {
process.exitCode = 0
return
}

console.error('%s: %s (%s)', opts.cmd, opts.tagline, opts.homepage)

// Are any warnings present?
const isSomeWarnings = result.results.some(item => item.messages.some(message => message.severity === 1))

if (isSomeWarnings) {
if (hasWarnings) {
const homepage = opts.homepage != null ? ` (${opts.homepage})` : ''
console.error(
'%s: %s',
Expand All @@ -173,17 +173,17 @@ Flags (advanced):
}

// Are any fixable rules present?
const isSomeFixable = result.results.some(item => item.messages.some(message => !!message.fix))
const hasFixable = results.some(item => item.messages.some(message => !!message.fix))

if (isSomeFixable) {
if (hasFixable) {
console.error(
'%s: %s',
opts.cmd,
'Run `' + opts.cmd + ' --fix` to automatically fix some problems.'
)
}

for (const item of result.results) {
for (const item of results) {
for (const message of item.messages) {
log(
' %s:%d:%d: %s%s%s',
Expand All @@ -197,7 +197,7 @@ Flags (advanced):
}
}

process.exitCode = result.errorCount ? 1 : 0
process.exitCode = hasErrors ? 1 : 0
})
.catch(err => process.nextTick(() => { throw err }))
}
Expand Down

0 comments on commit 5f66f04

Please sign in to comment.