Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop Node.js v14, run tests for 20, update dependencies #1289

Merged
merged 17 commits into from
Aug 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ on:
- alpha
# Do not run on tags
tags-ignore:
- "*"
- '*'
pull_request:
# Run on to branches with an open PR
branches:
- "*"
- '*'

permissions:
contents: read
Expand All @@ -26,7 +26,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
node-version: 20
# Install node_modules
- uses: actions/cache@v3
id: cache-node_modules
Expand All @@ -42,11 +42,11 @@ jobs:
test:
strategy:
matrix:
# Test with Node.js v14 (LTS), v16 (LTS), and 18 (Current)
# Test with Node.js v16 (LTS), v18 (LTS), and v20 (Current)
node:
- 14
- 16
- 18
- 20
# Test with Ubuntu, macOS, and Windows
os:
- ubuntu-latest
Expand Down Expand Up @@ -124,7 +124,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18 # release using Node.js LTS
node-version: 20
# Release using semantic-release.
# While this runs on all branches, it will only release latest from master
- uses: codfish/semantic-release-action@v2
Expand Down
3 changes: 2 additions & 1 deletion .prettierrc.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"printWidth": 100,
"singleQuote": true,
"semi": false
"semi": false,
"trailingComma": "es5"
}
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ See [Releases](https://github.com/okonet/lint-staged/releases).

### Migration

#### v14

- Since `v14.0.0` _lint-staged_ no longer supports Node.js 14. Please upgrade your Node.js version to at least `16.14.0`.

#### v13

- Since `v13.0.0` _lint-staged_ no longer supports Node.js 12. Please upgrade your Node.js version to at least `14.13.1`, or `16.0.0` onward.
Expand Down Expand Up @@ -218,11 +222,11 @@ If necessary, you can limit the concurrency using `--concurrent <number>` or dis
Linter commands work on a subset of all staged files, defined by a _glob pattern_. lint-staged uses [micromatch](https://github.com/micromatch/micromatch) for matching files with the following rules:

- If the glob pattern contains no slashes (`/`), micromatch's `matchBase` option will enabled, so globs match a file's basename regardless of directory:
- **`"*.js"`** will match all JS files, like `/test.js` and `/foo/bar/test.js`
- **`"!(*test).js"`**. will match all JS files, except those ending in `test.js`, so `foo.js` but not `foo.test.js`
- `"*.js"` will match all JS files, like `/test.js` and `/foo/bar/test.js`
- `"!(*test).js"` will match all JS files, except those ending in `test.js`, so `foo.js` but not `foo.test.js`
- If the glob pattern does contain a slash (`/`), it will match for paths as well:
- **`"./*.js"`** will match all JS files in the git repo root, so `/test.js` but not `/foo/bar/test.js`
- **`"foo/**/*.js"`** will match all JS files inside the `/foo` directory, so `/foo/bar/test.js` but not `/test.js`
- `"./*.js"` will match all JS files in the git repo root, so `/test.js` but not `/foo/bar/test.js`
- `"foo/**/*.js"` will match all JS files inside the `/foo` directory, so `/foo/bar/test.js` but not `/test.js`

When matching, lint-staged will do the following

Expand Down Expand Up @@ -624,9 +628,7 @@ See more on [this blog post](https://medium.com/@tomchentw/imagemin-lint-staged-
const path = require('path')

const buildEslintCommand = (filenames) =>
`next lint --fix --file ${filenames
.map((f) => path.relative(process.cwd(), f))
.join(' --file ')}`
`next lint --fix --file ${filenames.map((f) => path.relative(process.cwd(), f)).join(' --file ')}`

module.exports = {
'*.{js,jsx,ts,tsx}': [buildEslintCommand],
Expand Down
22 changes: 9 additions & 13 deletions bin/lint-staged.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#!/usr/bin/env node

import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import fs from 'node:fs/promises'

import { supportsColor } from 'chalk'
import { Option, program } from 'commander'
Expand All @@ -19,8 +17,7 @@ if (supportsColor) {
// Do not terminate main Listr process on SIGINT
process.on('SIGINT', () => {})

const packageJsonPath = path.join(fileURLToPath(import.meta.url), '../../package.json')
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath))
const packageJson = JSON.parse(await fs.readFile(new URL('../package.json', import.meta.url)))
const version = packageJson.version

const debugLog = debug('lint-staged:bin')
Expand Down Expand Up @@ -113,7 +110,7 @@ debugLog('Options parsed from command-line:', options)
if (options.configPath === '-') {
delete options.configPath
try {
options.config = fs.readFileSync(process.stdin.fd, 'utf8').toString().trim()
options.config = await fs.readFile(process.stdin.fd, 'utf8').toString().trim()
} catch {
console.error(CONFIG_STDIN_ERROR)
process.exit(1)
Expand All @@ -126,10 +123,9 @@ if (options.configPath === '-') {
}
}

lintStaged(options)
.then((passed) => {
process.exitCode = passed ? 0 : 1
})
.catch(() => {
process.exitCode = 1
})
try {
const passed = await lintStaged(options)
process.exitCode = passed ? 0 : 1
} catch {
process.exitCode = 1
}
5 changes: 3 additions & 2 deletions lib/chunkFiles.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import path from 'node:path'

import debug from 'debug'
import normalize from 'normalize-path'

import { normalizePath } from './normalizePath.js'

const debugLog = debug('lint-staged:chunkFiles')

Expand Down Expand Up @@ -35,7 +36,7 @@ const chunkArray = (arr, chunkCount) => {
*/
export const chunkFiles = ({ files, baseDir, maxArgLength = null, relative = false }) => {
const normalizedFiles = files.map((file) =>
normalize(relative || !baseDir ? file : path.resolve(baseDir, file))
normalizePath(relative || !baseDir ? file : path.resolve(baseDir, file))
)

if (!maxArgLength) {
Expand Down
7 changes: 4 additions & 3 deletions lib/generateTasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import path from 'node:path'

import debug from 'debug'
import micromatch from 'micromatch'
import normalize from 'normalize-path'

import { normalizePath } from './normalizePath.js'

const debugLog = debug('lint-staged:generateTasks')

Expand All @@ -19,7 +20,7 @@ const debugLog = debug('lint-staged:generateTasks')
export const generateTasks = ({ config, cwd = process.cwd(), files, relative = false }) => {
debugLog('Generating linter tasks')

const relativeFiles = files.map((file) => normalize(path.relative(cwd, file)))
const relativeFiles = files.map((file) => normalizePath(path.relative(cwd, file)))

return Object.entries(config).map(([pattern, commands]) => {
const isParentDirPattern = pattern.startsWith('../')
Expand All @@ -42,7 +43,7 @@ export const generateTasks = ({ config, cwd = process.cwd(), files, relative = f
strictBrackets: true,
})

const fileList = matches.map((file) => normalize(relative ? file : path.resolve(cwd, file)))
const fileList = matches.map((file) => normalizePath(relative ? file : path.resolve(cwd, file)))

const task = { pattern, commands, fileList }
debugLog('Generated task: \n%O', task)
Expand Down
64 changes: 50 additions & 14 deletions lib/getRenderer.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,64 @@
const getMainRendererOptions = ({ debug, quiet }, env) => {
if (quiet) return { renderer: 'silent' }
import { EOL } from 'node:os'
import { Writable } from 'node:stream'

import { ListrLogger, ProcessOutput } from 'listr2'

const EOLRegex = new RegExp(EOL + '$')

const bindLogger = (consoleLogMethod) =>
new Writable({
write: function (chunk, encoding, next) {
consoleLogMethod(chunk.toString().replace(EOLRegex, ''))
next()
},
})

const getMainRendererOptions = ({ debug, quiet }, logger, env) => {
if (quiet) {
return {
renderer: 'silent',
}
}

if (env.NODE_ENV === 'test') {
return {
renderer: 'test',
rendererOptions: {
logger: new ListrLogger({
processOutput: new ProcessOutput(bindLogger(logger.log), bindLogger(logger.error)),
}),
},
}
}

// Better support for dumb terminals: https://en.wikipedia.org/wiki/Computer_terminal#Dumb_terminals
const isDumbTerminal = env.TERM === 'dumb'
if (debug || isDumbTerminal || env.NODE_ENV === 'test') return { renderer: 'verbose' }
return { renderer: 'update', rendererOptions: { dateFormat: false } }
}
if (debug || env.TERM === 'dumb') {
return {
renderer: 'verbose',
}
}

const getFallbackRenderer = ({ renderer }, { FORCE_COLOR }) => {
if (renderer === 'silent') {
return 'silent'
return {
renderer: 'update',
rendererOptions: {
formatOutput: 'truncate',
},
}
}

// If colors are being forced, then also force non-fallback rendering
if (Number(FORCE_COLOR) > 0) {
const getFallbackRenderer = ({ renderer }, { FORCE_COLOR }) => {
if (renderer === 'silent' || renderer === 'test' || Number(FORCE_COLOR) > 0) {
return renderer
}

return 'verbose'
}

export const getRenderer = (options, env = process.env) => {
const mainRendererOptions = getMainRendererOptions(options, env)
export const getRenderer = (options, logger, env = process.env) => {
const mainRendererOptions = getMainRendererOptions(options, logger, env)

return {
...mainRendererOptions,
nonTTYRenderer: getFallbackRenderer(mainRendererOptions, env),
fallbackRenderer: getFallbackRenderer(mainRendererOptions, env),
}
}
5 changes: 2 additions & 3 deletions lib/getStagedFiles.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import path from 'node:path'

import normalize from 'normalize-path'

import { execGit } from './execGit.js'
import { getDiffCommand } from './getDiffCommand.js'
import { normalizePath } from './normalizePath.js'
import { parseGitZOutput } from './parseGitZOutput.js'

export const getStagedFiles = async ({ cwd = process.cwd(), diff, diffFilter } = {}) => {
try {
const lines = await execGit(getDiffCommand(diff, diffFilter), { cwd })
if (!lines) return []

return parseGitZOutput(lines).map((file) => normalize(path.resolve(cwd, file)))
return parseGitZOutput(lines).map((file) => normalizePath(path.resolve(cwd, file)))
} catch {
return null
}
Expand Down
25 changes: 2 additions & 23 deletions lib/makeCmdTasks.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,10 @@
import cliTruncate from 'cli-truncate'
import debug from 'debug'

import { configurationError } from './messages.js'
import { resolveTaskFn } from './resolveTaskFn.js'

const debugLog = debug('lint-staged:makeCmdTasks')

const STDOUT_COLUMNS_DEFAULT = 80

const listrPrefixLength = {
update: ` X `.length, // indented task title where X is a checkmark or a cross (failure)
verbose: `[STARTED] `.length, // verbose renderer uses 7-letter STARTED/SUCCESS prefixes
}

/**
* Get length of title based on the number of available columns prefix length
* @param {string} renderer The name of the Listr renderer
* @returns {number}
*/
const getTitleLength = (renderer, columns = process.stdout.columns) => {
const prefixLength = listrPrefixLength[renderer] || 0
return (columns || STDOUT_COLUMNS_DEFAULT) - prefixLength
}

/**
* Creates and returns an array of listr tasks which map to the given commands.
*
Expand All @@ -31,11 +13,10 @@ const getTitleLength = (renderer, columns = process.stdout.columns) => {
* @param {string} options.cwd
* @param {Array<string>} options.files
* @param {string} options.gitDir
* @param {string} options.renderer
* @param {Boolean} shell
* @param {Boolean} verbose
*/
export const makeCmdTasks = async ({ commands, cwd, files, gitDir, renderer, shell, verbose }) => {
export const makeCmdTasks = async ({ commands, cwd, files, gitDir, shell, verbose }) => {
debugLog('Creating listr tasks for commands %o', commands)
const commandArray = Array.isArray(commands) ? commands : [commands]
const cmdTasks = []
Expand All @@ -60,10 +41,8 @@ export const makeCmdTasks = async ({ commands, cwd, files, gitDir, renderer, she
)
}

// Truncate title to single line based on renderer
const title = cliTruncate(command, getTitleLength(renderer))
const task = resolveTaskFn({ command, cwd, files, gitDir, isFn, shell, verbose })
cmdTasks.push({ title, command, task })
cmdTasks.push({ title: command, command, task })
}
}

Expand Down
7 changes: 3 additions & 4 deletions lib/messages.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { inspect } from 'node:util'

import chalk from 'chalk'
import inspect from 'object-inspect'

import { error, info, warning } from './figures.js'

export const configurationError = (opt, helpMsg, value) =>
`${chalk.redBright(`${error} Validation Error:`)}

Invalid value for '${chalk.bold(opt)}': ${chalk.bold(
inspect(value, { inlineCharacterLimit: Number.POSITIVE_INFINITY })
)}
Invalid value for '${chalk.bold(opt)}': ${chalk.bold(inspect(value))}

${helpMsg}`

Expand Down