Skip to content

Commit 3423735

Browse files
JounQinmarcalexiei
authored andcommitted
feat!: migrate to pure ESM (#3850)
BREAKING CHANGE: migrate to pure ESM * feat: migrate to pure ESM * chore: update snapshot * fix: load `parserPreset` with another `await` * test: migrate to vitest * test: remove no replacement `--runInBand` test-ci script * chore: fix code reviews * refactor(load): rewrite resolve logic * fix(config-nx-scopes): fix syntax error * feat(resolve-extends): add resolveFrom and loadParserPreset * feat(load): use resolveFrom and loadParserPreset from resolve-extends * test: include only @commitlint/* packages src in coverage * test: explicit import vitest utilities * test: remove @jest/globals from dependencies * fix(resolve-extends): `resolveFrom` output should be platform aware * test: restore NO_COLOR to test script * chore: fix linting issues * fix: should use fileURLToPath instead of pathname for Windows compatibility * Apply suggestions from code review * fix: should reuse `cli` instead call `yargs()` * feat(cli): set terminalWidth as wrap to avoid work break on help * Update .eslintrc.cjs * feat: migrate @commitlint/config-conventional to pure ESM --------- Co-authored-by: Marco Pasqualetti <[email protected]>
1 parent 93fa15e commit 3423735

File tree

225 files changed

+3258
-3352
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

225 files changed

+3258
-3352
lines changed

.eslintrc.js .eslintrc.cjs

+3-4
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ module.exports = {
3131
'import/no-extraneous-dependencies': [
3232
'error',
3333
{
34-
devDependencies: ['**/*.test.js', '**/*.test.ts'],
34+
devDependencies: ['**/*.test.js', '**/*.test.ts', 'vitest'],
3535
},
3636
],
3737
},
@@ -61,15 +61,14 @@ module.exports = {
6161
},
6262
{
6363
files: ['*.test.ts', '*.test.js'],
64-
env: {
65-
jest: true,
66-
},
6764
extends: ['plugin:jest/recommended'],
6865
rules: {
6966
'@typescript-eslint/no-explicit-any': 'off',
7067
'@typescript-eslint/no-var-requires': 'off',
7168
// disallow non-import statements appearing before import statements
7269
'import/first': 'off',
70+
'import/no-extraneous-dependencies': 'off',
71+
'jest/no-deprecated-functions': 'off'
7372
},
7473
},
7574
],

.github/workflows/CI.yml

+3-4
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ jobs:
2929
run: yarn build
3030

3131
- name: Test
32-
run: yarn test-ci
32+
run: yarn test
3333

3434
nodeJsBaselineAptCompatibility:
3535
name: NodeJS installed from stock Ubuntu-LTS packages (not external sources)
3636
runs-on: ubuntu-22.04
3737
container:
38-
image: "ubuntu:24.04"
38+
image: 'ubuntu:24.04'
3939
steps:
4040
- uses: actions/checkout@v4
4141

@@ -55,5 +55,4 @@ jobs:
5555
run: yarn build
5656

5757
- name: Run Tests
58-
run: yarn test-ci
59-
58+
run: yarn test
+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = require('@commitlint/config-angular');
1+
export {default} from '@commitlint/config-angular';

@alias/commitlint-config-angular/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"name": "commitlint-config-angular",
3+
"type": "module",
34
"version": "18.6.1",
45
"description": "Shareable commitlint config enforcing the angular commit convention",
56
"files": [
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = require('@commitlint/config-lerna-scopes');
1+
export {default} from '@commitlint/config-lerna-scopes';

@alias/commitlint-config-lerna-scopes/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"name": "commitlint-config-lerna-scopes",
3+
"type": "module",
34
"version": "18.6.1",
45
"description": "Shareable commitlint config enforcing lerna package names as scopes",
56
"files": [
+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = require('@commitlint/config-nx-scopes');
1+
export {default} from '@commitlint/config-nx-scopes';

@alias/commitlint-config-nx-scopes/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"name": "commitlint-config-nx-scopes",
3+
"type": "module",
34
"version": "18.6.1",
45
"description": "Shareable commitlint config enforcing nx project names as scopes",
56
"files": [
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = require('@commitlint/config-patternplate');
1+
export {default} from '@commitlint/config-patternplate';

@alias/commitlint-config-patternplate/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"name": "commitlint-config-patternplate",
3+
"type": "module",
34
"version": "18.6.1",
45
"description": "Lint your commits, patternplate-style",
56
"files": [

@alias/commitlint/cli.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
#!/usr/bin/env node
2-
const pkgDir = require('@commitlint/cli');
3-
require(pkgDir);
2+
import '@commitlint/cli/cli.js';

@alias/commitlint/cli.test.js

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
import {test, expect} from 'vitest';
2+
import {createRequire} from 'module';
3+
import path from 'path';
4+
import {fileURLToPath} from 'url';
5+
16
import execa from 'execa';
27
import {fix} from '@commitlint/test';
38

9+
const require = createRequire(import.meta.url);
10+
11+
const __dirname = path.resolve(fileURLToPath(import.meta.url), '..');
12+
413
const bin = require.resolve('./cli.js');
514

615
function cli(args, options, input) {

@alias/commitlint/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"name": "commitlint",
3+
"type": "module",
34
"version": "18.6.1",
45
"description": "Lint your commit messages",
56
"files": [

@commitlint/cli/cli.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
#!/usr/bin/env node
2-
require('./lib/cli.js');
2+
import './lib/cli.js';

@commitlint/cli/fixtures/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "commonjs"
3+
}
File renamed without changes.

@commitlint/cli/package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
{
22
"name": "@commitlint/cli",
3+
"type": "module",
34
"version": "18.6.1",
45
"description": "Lint your commit messages",
56
"files": [
6-
"index.js",
7+
"index.cjs",
78
"cli.js",
89
"lib"
910
],
11+
"main": "index.cjs",
1012
"bin": {
1113
"commitlint": "./cli.js"
1214
},
@@ -39,7 +41,6 @@
3941
"devDependencies": {
4042
"@commitlint/test": "^18.0.0",
4143
"@commitlint/utils": "^18.6.1",
42-
"@types/lodash.isfunction": "^3.0.8",
4344
"@types/lodash.merge": "^4.6.8",
4445
"@types/node": "^18.11.9",
4546
"@types/yargs": "^17.0.29",
@@ -53,7 +54,6 @@
5354
"@commitlint/read": "^18.6.1",
5455
"@commitlint/types": "^18.6.1",
5556
"execa": "^5.0.0",
56-
"lodash.isfunction": "^3.0.9",
5757
"resolve-from": "5.0.0",
5858
"resolve-global": "1.0.0",
5959
"yargs": "^17.0.0"

@commitlint/cli/src/cli.test.ts

+28-30
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1+
import {describe, test, expect} from 'vitest';
2+
import {createRequire} from 'module';
3+
import path from 'path';
4+
import {fileURLToPath} from 'url';
5+
16
import {fix, git} from '@commitlint/test';
27
import execa from 'execa';
38
import fs from 'fs-extra';
49
import merge from 'lodash.merge';
5-
import path from 'path';
10+
11+
const require = createRequire(import.meta.url);
12+
13+
const __dirname = path.resolve(fileURLToPath(import.meta.url), '..');
614

715
const bin = require.resolve('../cli.js');
816

@@ -511,34 +519,24 @@ test('should print help', async () => {
511519
[input] reads from stdin if --edit, --env, --from and --to are omitted
512520
513521
Options:
514-
-c, --color toggle colored output [boolean] [default: true]
515-
-g, --config path to the config file [string]
516-
--print-config print resolved config
517-
[string] [choices: "", "text", "json"]
518-
-d, --cwd directory to execute in
519-
[string] [default: (Working Directory)]
520-
-e, --edit read last commit message from the specified file or
521-
fallbacks to ./.git/COMMIT_EDITMSG [string]
522-
-E, --env check message in the file at path given by environment
523-
variable value [string]
524-
-x, --extends array of shareable configurations to extend [array]
525-
-H, --help-url help url in error message [string]
526-
-f, --from lower end of the commit range to lint; applies if
527-
edit=false [string]
528-
--git-log-args additional git log arguments as space separated string,
529-
example '--first-parent --cherry-pick' [string]
530-
-o, --format output format of the results [string]
531-
-p, --parser-preset configuration preset to use for
532-
conventional-commits-parser [string]
533-
-q, --quiet toggle console output [boolean] [default: false]
534-
-t, --to upper end of the commit range to lint; applies if
535-
edit=false [string]
536-
-V, --verbose enable verbose output for reports without problems
537-
[boolean]
538-
-s, --strict enable strict mode; result code 2 for warnings, 3 for
539-
errors [boolean]
540-
-v, --version display version information [boolean]
541-
-h, --help Show help [boolean]"
522+
-c, --color toggle colored output [boolean] [default: true]
523+
-g, --config path to the config file [string]
524+
--print-config print resolved config [string] [choices: "", "text", "json"]
525+
-d, --cwd directory to execute in [string] [default: (Working Directory)]
526+
-e, --edit read last commit message from the specified file or fallbacks to ./.git/COMMIT_EDITMSG [string]
527+
-E, --env check message in the file at path given by environment variable value [string]
528+
-x, --extends array of shareable configurations to extend [array]
529+
-H, --help-url help url in error message [string]
530+
-f, --from lower end of the commit range to lint; applies if edit=false [string]
531+
--git-log-args additional git log arguments as space separated string, example '--first-parent --cherry-pick' [string]
532+
-o, --format output format of the results [string]
533+
-p, --parser-preset configuration preset to use for conventional-commits-parser [string]
534+
-q, --quiet toggle console output [boolean] [default: false]
535+
-t, --to upper end of the commit range to lint; applies if edit=false [string]
536+
-V, --verbose enable verbose output for reports without problems [boolean]
537+
-s, --strict enable strict mode; result code 2 for warnings, 3 for errors [boolean]
538+
-v, --version display version information [boolean]
539+
-h, --help Show help [boolean]"
542540
`);
543541
});
544542

@@ -600,7 +598,7 @@ describe('should print config', () => {
600598
const actual = await cli(['--print-config=json', '--no-color'], {cwd})();
601599

602600
expect(actual.stdout).toMatchInlineSnapshot(
603-
`"{"extends":[],"formatter":"@commitlint/format","plugins":{},"rules":{"type-enum":[2,"never",["foo"]]},"helpUrl":"https://github.com/conventional-changelog/commitlint/#what-is-commitlint\","prompt":{}}"`
601+
`"{"extends":[],"formatter":"@commitlint/format","plugins":{},"rules":{"type-enum":[2,"never",["foo"]]},"helpUrl":"https://github.com/conventional-changelog/commitlint/#what-is-commitlint","prompt":{}}"`
604602
);
605603
});
606604
});

@commitlint/cli/src/cli.ts

+44-26
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,45 @@
1-
import execa, {ExecaError} from 'execa';
2-
import load from '@commitlint/load';
3-
import lint from '@commitlint/lint';
4-
import read from '@commitlint/read';
5-
import isFunction from 'lodash.isfunction';
6-
import resolveFrom from 'resolve-from';
7-
import resolveGlobal from 'resolve-global';
8-
import yargs, {Arguments} from 'yargs';
1+
import {createRequire} from 'module';
2+
import path from 'path';
3+
import {fileURLToPath, pathToFileURL} from 'url';
94
import util from 'util';
105

11-
import {CliFlags} from './types';
12-
import {
6+
import lint from '@commitlint/lint';
7+
import load from '@commitlint/load';
8+
import read from '@commitlint/read';
9+
import type {
10+
Formatter,
1311
LintOptions,
1412
LintOutcome,
15-
ParserOptions,
1613
ParserPreset,
1714
QualifiedConfig,
18-
Formatter,
1915
UserConfig,
2016
} from '@commitlint/types';
21-
import {CliError} from './cli-error';
17+
import type {Options} from 'conventional-commits-parser';
18+
import execa, {ExecaError} from 'execa';
19+
import resolveFrom from 'resolve-from';
20+
import resolveGlobal from 'resolve-global';
21+
import yargs, {type Arguments} from 'yargs';
22+
23+
import {CliFlags} from './types.js';
24+
25+
import {CliError} from './cli-error.js';
26+
27+
const require = createRequire(import.meta.url);
28+
29+
const __dirname = path.resolve(fileURLToPath(import.meta.url), '..');
30+
31+
const dynamicImport = async <T>(id: string): Promise<T> => {
32+
const imported = await import(
33+
path.isAbsolute(id) ? pathToFileURL(id).toString() : id
34+
);
35+
return ('default' in imported && imported.default) || imported;
36+
};
2237

23-
const pkg = require('../package');
38+
const pkg: typeof import('../package.json') = require('../package.json');
2439

2540
const gitDefaultCommentChar = '#';
2641

27-
const cli = yargs
42+
const cli = yargs(process.argv.slice(2))
2843
.options({
2944
color: {
3045
alias: 'c',
@@ -131,6 +146,12 @@ const cli = yargs
131146
)
132147
.strict();
133148

149+
/**
150+
* avoid description words to be divided in new lines when there is enough space
151+
* @see https://github.com/conventional-changelog/commitlint/pull/3850#discussion_r1472251234
152+
*/
153+
cli.wrap(cli.terminalWidth());
154+
134155
main(cli.argv).catch((err) => {
135156
setTimeout(() => {
136157
if (err.type === pkg.name) {
@@ -215,7 +236,7 @@ async function main(args: MainArgs): Promise<void> {
215236
'[input] is required: supply via stdin, or --env or --edit or --from and --to',
216237
pkg.name
217238
);
218-
yargs.showHelp('log');
239+
cli.showHelp('log');
219240
console.log(err.message);
220241
throw err;
221242
}
@@ -225,7 +246,7 @@ async function main(args: MainArgs): Promise<void> {
225246
file: flags.config,
226247
});
227248
const parserOpts = selectParserOpts(loaded.parserPreset);
228-
const opts: LintOptions & {parserOpts: ParserOptions} = {
249+
const opts: LintOptions & {parserOpts: Options} = {
229250
parserOpts: {},
230251
plugins: {},
231252
ignores: [],
@@ -243,7 +264,7 @@ async function main(args: MainArgs): Promise<void> {
243264
if (loaded.defaultIgnores === false) {
244265
opts.defaultIgnores = false;
245266
}
246-
const format = loadFormatter(loaded, flags);
267+
const format = await loadFormatter(loaded, flags);
247268

248269
// If reading from `.git/COMMIT_EDIT_MSG`, strip comments using
249270
// core.commentChar from git configuration, falling back to '#'.
@@ -431,21 +452,18 @@ function selectParserOpts(parserPreset: ParserPreset | undefined) {
431452
return parserPreset.parserOpts;
432453
}
433454

434-
function loadFormatter(config: QualifiedConfig, flags: CliFlags): Formatter {
455+
function loadFormatter(
456+
config: QualifiedConfig,
457+
flags: CliFlags
458+
): Promise<Formatter> {
435459
const moduleName = flags.format || config.formatter || '@commitlint/format';
436460
const modulePath =
437461
resolveFrom.silent(__dirname, moduleName) ||
438462
resolveFrom.silent(flags.cwd, moduleName) ||
439463
resolveGlobal.silent(moduleName);
440464

441465
if (modulePath) {
442-
const moduleInstance = require(modulePath);
443-
444-
if (isFunction(moduleInstance.default)) {
445-
return moduleInstance.default;
446-
}
447-
448-
return moduleInstance;
466+
return dynamicImport<Formatter>(modulePath);
449467
}
450468

451469
throw new Error(`Using format ${moduleName}, but cannot find the module.`);

@commitlint/config-angular-type-enum/index.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ const types = [
1111
'test',
1212
];
1313

14-
module.exports.rules = {
15-
'type-enum': [2, 'always', types],
14+
export default {
15+
rules: {
16+
'type-enum': [2, 'always', types],
17+
},
18+
value: () => types,
1619
};
17-
18-
module.exports.value = () => types;

@commitlint/config-angular-type-enum/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"name": "@commitlint/config-angular-type-enum",
3+
"type": "module",
34
"version": "18.6.1",
45
"description": "Shareable commitlint config enforcing the angular commit convention types",
56
"files": [

@commitlint/config-angular/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
const typeEnum = require('@commitlint/config-angular-type-enum');
1+
import typeEnum from '@commitlint/config-angular-type-enum';
22

3-
module.exports = {
3+
export default {
44
parserPreset: {parserOpts: {headerPattern: /^(\w*)(?:\((.*)\))?!?: (.*)$/}},
55
rules: {
66
'subject-exclamation-mark': [2, 'never'],

0 commit comments

Comments
 (0)