Navigation Menu

Skip to content

Commit

Permalink
feat: convert to native ESM module (#1038)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: _lint-staged_ is now a pure ESM module, and thus
requires Node.js version `^12.20.0 || ^14.13.1 || >=16.0.0`.

To update your Node.js integration, please use:

```js
// const lintStaged = require('lint-staged')
import lintStaged from 'lint-staged'
```
  • Loading branch information
iiroj committed Nov 13, 2021
1 parent 64e4364 commit 7240f61
Show file tree
Hide file tree
Showing 51 changed files with 3,566 additions and 3,411 deletions.
15 changes: 0 additions & 15 deletions .babelrc

This file was deleted.

26 changes: 21 additions & 5 deletions .eslintrc.json
Expand Up @@ -6,19 +6,35 @@
"experimentalObjectRestSpread": true
},
"requireConfigFile": false,
"sourceType": "script"
"sourceType": "module"
},
"env": {
"es6": true,
"node": true
},
"extends": ["eslint:recommended", "prettier"],
"extends": ["eslint:recommended", "plugin:import/recommended", "prettier"],
"plugins": ["node", "import", "prettier"],
"rules": {
"import/order": [
"error",
{
"groups": [
"builtin",
"external",
"internal",
"parent",
"sibling",
"index",
"object",
"type"
],
"newlines-between": "always"
}
],
"no-console": "off",
"node/no-unsupported-features/node-builtins": "off",
"node/no-unsupported-features/es-syntax": ["error", { "version": ">=10.13.0" }],
"node/no-unsupported-features/es-builtins": ["error", { "version": ">=10.13.0" }],
"node/no-unsupported-features/es-builtins": "error",
"node/no-unsupported-features/es-syntax": ["error", { "ignores": ["modules"] }],
"node/no-unsupported-features/node-builtins": "error",
"prettier/prettier": "error"
}
}
5 changes: 1 addition & 4 deletions .github/workflows/codeql.yml
Expand Up @@ -4,10 +4,7 @@ on:
push:
# Run on pushes to specific branches
branches:
- master
- next
- beta
- alpha
- "*"
# Do not run on tags
tags-ignore:
- "*"
Expand Down
16 changes: 10 additions & 6 deletions .github/workflows/main.yml
Expand Up @@ -60,12 +60,6 @@ jobs:
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}
# Print current Node.js version
- run: node --version
# Print current npm version
- run: npm --version
# Print current Git version
- run: git --version
# Install node_modules
- uses: actions/cache@v2
id: cache-node_modules
Expand All @@ -76,6 +70,16 @@ jobs:
${{ matrix.os }}-${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }}
- if: steps.cache-node_modules.outputs.cache-hit != 'true'
run: npm ci
# Print current Node.js version
- run: node --version
# Print current npm version
- run: npm --version
# Print current Git version
- run: git --version
# Print lint-staged version
- run: node bin/lint-staged.js --version
# Print lint-staged help text
- run: node bin/lint-staged.js --help
# Run tests
- run: npm test
# Upload coverage artifact from Node.js LTS
Expand Down
3 changes: 3 additions & 0 deletions babel.config.cjs
@@ -0,0 +1,3 @@
module.exports = {
presets: [['@babel/preset-env', { modules: 'cjs', targets: { node: 'current' } }]],
}
37 changes: 14 additions & 23 deletions bin/lint-staged.js
@@ -1,36 +1,27 @@
#!/usr/bin/env node

'use strict'
import fs from 'fs'

const fs = require('fs')
import cmdline from 'commander'
import debug from 'debug'
import supportsColor from 'supports-color'

import lintStaged from '../lib/index.js'
import { CONFIG_STDIN_ERROR } from '../lib/messages.js'

// Force colors for packages that depend on https://www.npmjs.com/package/supports-color
const supportsColor = require('supports-color')
if (supportsColor.stdout) {
process.env.FORCE_COLOR = supportsColor.stdout.level.toString()
}

// Do not terminate main Listr process on SIGINT
process.on('SIGINT', () => {})

const pkg = require('../package.json')
require('please-upgrade-node')(
Object.assign({}, pkg, {
engines: {
node: '>=12.13.0', // First LTS release of 'Erbium'
},
})
)

const cmdline = require('commander')
const debugLib = require('debug')
const lintStaged = require('../lib')
const { CONFIG_STDIN_ERROR } = require('../lib/messages')

const debug = debugLib('lint-staged:bin')
const packageJson = JSON.parse(fs.readFileSync('package.json'))
const version = packageJson.version

cmdline
.version(pkg.version)
.version(version)
.option('--allow-empty', 'allow empty commits when tasks revert all staged changes', false)
.option('-c, --config [path]', 'path to configuration file, or - to read from stdin')
.option('-d, --debug', 'print additional debug information', false)
Expand All @@ -50,11 +41,11 @@ cmdline
)
.parse(process.argv)

const debugLog = debug('lint-staged:bin')
if (cmdline.debug) {
debugLib.enable('lint-staged*')
debug.enable('lint-staged*')
}

debug('Running `lint-staged@%s`', pkg.version)
debugLog('Running `lint-staged@%s`', version)

/**
* Get the maximum length of a command-line argument string based on current platform
Expand Down Expand Up @@ -89,7 +80,7 @@ const options = {
verbose: !!cmdlineOptions.verbose,
}

debug('Options parsed from command-line:', options)
debugLog('Options parsed from command-line:', options)

if (options.configPath === '-') {
delete options.configPath
Expand Down
15 changes: 15 additions & 0 deletions jest.config.js
@@ -0,0 +1,15 @@
const config = {
collectCoverage: true,
collectCoverageFrom: ['lib/**/*.js'],
moduleDirectories: ['node_modules'],
setupFiles: ['./testSetup.js'],
snapshotSerializers: ['jest-snapshot-serializer-ansi'],
testEnvironment: 'node',
transform: {
'\\.[jt]sx?$': 'babel-jest',
},
/** Also transform ESM packages in `node_modules` */
transformIgnorePatterns: [],
}

export default config
19 changes: 10 additions & 9 deletions lib/chunkFiles.js
@@ -1,16 +1,17 @@
'use strict'
import path from 'path'

const debug = require('debug')('lint-staged:chunkFiles')
const normalize = require('normalize-path')
const path = require('path')
import debug from 'debug'
import normalize from 'normalize-path'

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

/**
* Chunk array into sub-arrays
* @param {Array} arr
* @param {Number} chunkCount
* @retuns {Array<Array>}
*/
function chunkArray(arr, chunkCount) {
const chunkArray = (arr, chunkCount) => {
if (chunkCount === 1) return [arr]
const chunked = []
let position = 0
Expand All @@ -32,21 +33,21 @@ function chunkArray(arr, chunkCount) {
* @param {Boolean} [opts.relative] whether files are relative to `gitDir` or should be resolved as absolute
* @returns {Array<Array<String>>}
*/
module.exports = function chunkFiles({ files, baseDir, maxArgLength = null, relative = false }) {
export const chunkFiles = ({ files, baseDir, maxArgLength = null, relative = false }) => {
const normalizedFiles = files.map((file) =>
normalize(relative || !baseDir ? file : path.resolve(baseDir, file))
)

if (!maxArgLength) {
debug('Skip chunking files because of undefined maxArgLength')
debugLog('Skip chunking files because of undefined maxArgLength')
return [normalizedFiles] // wrap in an array to return a single chunk
}

const fileListLength = normalizedFiles.join(' ').length
debug(
debugLog(
`Resolved an argument string length of ${fileListLength} characters from ${normalizedFiles.length} files`
)
const chunkCount = Math.min(Math.ceil(fileListLength / maxArgLength), normalizedFiles.length)
debug(`Creating ${chunkCount} chunks for maxArgLength of ${maxArgLength}`)
debugLog(`Creating ${chunkCount} chunks for maxArgLength of ${maxArgLength}`)
return chunkArray(normalizedFiles, chunkCount)
}
16 changes: 7 additions & 9 deletions lib/execGit.js
@@ -1,18 +1,19 @@
'use strict'
import debug from 'debug'
import execa from 'execa'

const debug = require('debug')('lint-staged:git')
const execa = require('execa')
const debugLog = debug('lint-staged:execGit')

/**
* Explicitly never recurse commands into submodules, overriding local/global configuration.
* @see https://git-scm.com/docs/git-config#Documentation/git-config.txt-submodulerecurse
*/
const NO_SUBMODULE_RECURSE = ['-c', 'submodule.recurse=false']

const GIT_GLOBAL_OPTIONS = [...NO_SUBMODULE_RECURSE]
// exported for tests
export const GIT_GLOBAL_OPTIONS = [...NO_SUBMODULE_RECURSE]

module.exports = async function execGit(cmd, options = {}) {
debug('Running git command', cmd)
export const execGit = async (cmd, options = {}) => {
debugLog('Running git command', cmd)
try {
const { stdout } = await execa('git', GIT_GLOBAL_OPTIONS.concat(cmd), {
...options,
Expand All @@ -24,6 +25,3 @@ module.exports = async function execGit(cmd, options = {}) {
throw new Error(all)
}
}

// exported for tests
module.exports.GIT_GLOBAL_OPTIONS = GIT_GLOBAL_OPTIONS
14 changes: 6 additions & 8 deletions lib/figures.js
@@ -1,10 +1,8 @@
const { blue, redBright, yellow } = require('colorette')
const { figures } = require('listr2')
import { blue, redBright, yellow } from 'colorette'
import { figures } from 'listr2'

const { arrowRight, cross, warning } = figures
export const info = blue(figures.arrowRight)

module.exports = {
info: blue(arrowRight),
error: redBright(cross),
warning: yellow(warning),
}
export const error = redBright(figures.cross)

export const warning = yellow(figures.warning)
38 changes: 14 additions & 24 deletions lib/file.js
@@ -1,26 +1,22 @@
'use strict'
import { promises as fs } from 'fs'

const debug = require('debug')('lint-staged:file')
const fs = require('fs')
const { promisify } = require('util')
import debug from 'debug'

const fsReadFile = promisify(fs.readFile)
const fsUnlink = promisify(fs.unlink)
const fsWriteFile = promisify(fs.writeFile)
const debugLog = debug('lint-staged:file')

/**
* Read contents of a file to buffer
* @param {String} filename
* @param {Boolean} [ignoreENOENT=true] — Whether to throw if the file doesn't exist
* @returns {Promise<Buffer>}
*/
const readFile = async (filename, ignoreENOENT = true) => {
debug('Reading file `%s`', filename)
export const readFile = async (filename, ignoreENOENT = true) => {
debugLog('Reading file `%s`', filename)
try {
return await fsReadFile(filename)
return await fs.readFile(filename)
} catch (error) {
if (ignoreENOENT && error.code === 'ENOENT') {
debug("File `%s` doesn't exist, ignoring...", filename)
debugLog("File `%s` doesn't exist, ignoring...", filename)
return null // no-op file doesn't exist
} else {
throw error
Expand All @@ -33,13 +29,13 @@ const readFile = async (filename, ignoreENOENT = true) => {
* @param {String} filename
* @param {Boolean} [ignoreENOENT=true] — Whether to throw if the file doesn't exist
*/
const unlink = async (filename, ignoreENOENT = true) => {
debug('Removing file `%s`', filename)
export const unlink = async (filename, ignoreENOENT = true) => {
debugLog('Removing file `%s`', filename)
try {
await fsUnlink(filename)
await fs.unlink(filename)
} catch (error) {
if (ignoreENOENT && error.code === 'ENOENT') {
debug("File `%s` doesn't exist, ignoring...", filename)
debugLog("File `%s` doesn't exist, ignoring...", filename)
} else {
throw error
}
Expand All @@ -51,13 +47,7 @@ const unlink = async (filename, ignoreENOENT = true) => {
* @param {String} filename
* @param {Buffer} buffer
*/
const writeFile = async (filename, buffer) => {
debug('Writing file `%s`', filename)
await fsWriteFile(filename, buffer)
}

module.exports = {
readFile,
unlink,
writeFile,
export const writeFile = async (filename, buffer) => {
debugLog('Writing file `%s`', filename)
await fs.writeFile(filename, buffer)
}
18 changes: 8 additions & 10 deletions lib/generateTasks.js
@@ -1,10 +1,10 @@
'use strict'
import path from 'path'

const micromatch = require('micromatch')
const normalize = require('normalize-path')
const path = require('path')
import debug from 'debug'
import micromatch from 'micromatch'
import normalize from 'normalize-path'

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

/**
* Generates all task commands, and filelist
Expand All @@ -16,8 +16,8 @@ const debug = require('debug')('lint-staged:gen-tasks')
* @param {boolean} [options.files] - Staged filepaths
* @param {boolean} [options.relative] - Whether filepaths to should be relative to gitDir
*/
const generateTasks = ({ config, cwd = process.cwd(), gitDir, files, relative = false }) => {
debug('Generating linter tasks')
export const generateTasks = ({ config, cwd = process.cwd(), gitDir, files, relative = false }) => {
debugLog('Generating linter tasks')

const absoluteFiles = files.map((file) => normalize(path.resolve(gitDir, file)))
const relativeFiles = absoluteFiles.map((file) => normalize(path.relative(cwd, file)))
Expand Down Expand Up @@ -47,10 +47,8 @@ const generateTasks = ({ config, cwd = process.cwd(), gitDir, files, relative =
const fileList = matches.map((file) => normalize(relative ? file : path.resolve(cwd, file)))

const task = { pattern, commands, fileList }
debug('Generated task: \n%O', task)
debugLog('Generated task: \n%O', task)

return task
})
}

module.exports = generateTasks

0 comments on commit 7240f61

Please sign in to comment.