Skip to content

Commit a2b65fc

Browse files
authored
feat: bump cosmiconfig version and conditionally support mjs config (#3747)
* feat(load): use cosmiconfig-typescript-loader v5 to remove ts-node dependency for @commitlint/load * feat: conditionally support loading mjs config based on the node version * chore: update 'test-ci' command * chore: add yarn cache to ci * chore: swap node and checkout order. Remove ownership workaround * chore(load): remove duplicate tests * docs: add mjs config files to README
1 parent f33be70 commit a2b65fc

File tree

26 files changed

+123
-119
lines changed

26 files changed

+123
-119
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
extends:
2+
- './first-extended'
3+
rules:
4+
zero: [0, 'never']
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
extends: ['./first-extended'],
3+
rules: {
4+
zero: [0, 'never'],
5+
},
6+
};

@commitlint/load/fixtures/recursive-extends-js/.commitlintrc.js renamed to @commitlint/load/fixtures/config/.commitlintrc.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ module.exports = {
33
rules: {
44
zero: [0, 'never'],
55
},
6-
};
6+
};

@commitlint/load/fixtures/recursive-extends-json/.commitlintrc.json renamed to @commitlint/load/fixtures/config/.commitlintrc.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
"rules": {
44
"zero": [0, "never"]
55
}
6-
}
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
extends: ['./first-extended'],
3+
rules: {
4+
zero: [0, 'never'],
5+
},
6+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
extends:
2+
- './first-extended'
3+
rules:
4+
zero: [0, 'never']
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
extends:
22
- './first-extended'
33
rules:
4-
zero: [0, 'never']
4+
zero: [0, 'never']
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
extends: ['./first-extended'],
3+
rules: {
4+
zero: [0, 'never'],
5+
},
6+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
extends: ['./first-extended'],
3+
rules: {
4+
zero: [0, 'never'],
5+
},
6+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
extends: ['./first-extended'],
3+
rules: {
4+
zero: [0, 'never'],
5+
},
6+
};

@commitlint/load/fixtures/recursive-extends-package/package.json renamed to @commitlint/load/fixtures/config/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@
1010
]
1111
}
1212
}
13-
}
13+
}

@commitlint/load/fixtures/recursive-extends-js/first-extended/index.js

-6
This file was deleted.

@commitlint/load/fixtures/recursive-extends-js/first-extended/second-extended/index.js

-5
This file was deleted.

@commitlint/load/fixtures/recursive-extends-package/first-extended/index.js

-6
This file was deleted.

@commitlint/load/fixtures/recursive-extends-package/first-extended/second-extended/index.js

-5
This file was deleted.

@commitlint/load/fixtures/recursive-extends-ts/commitlint.config.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {UserConfig} from './types';
22

33
const Configuration: UserConfig = {
4-
extends: ['./first-extended'],
4+
extends: ['./first-extended/index.ts'],
55
rules: {
66
zero: [0, 'never', 'zero']
77
}

@commitlint/load/fixtures/recursive-extends-ts/first-extended/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type {UserConfig} from '../types';
22
module.exports = {
3-
extends: ['./second-extended'],
3+
extends: ['./second-extended/index.ts'],
44
rules: {
55
one: [1, 'never', 'one']
66
}

@commitlint/load/fixtures/recursive-extends-yaml/first-extended/index.js

-6
This file was deleted.

@commitlint/load/fixtures/recursive-extends-yaml/first-extended/second-extended/index.js

-5
This file was deleted.

@commitlint/load/src/load.test.ts

+27-69
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ jest.mock('@scope/commitlint-plugin-example', () => scopedPlugin, {
77
});
88

99
import path from 'path';
10+
import {readFileSync, writeFileSync} from 'fs';
1011
import resolveFrom from 'resolve-from';
1112
import {fix, git, npm} from '@commitlint/test';
1213

1314
import load from './load';
15+
import {isDynamicAwaitSupported} from './utils/load-config';
1416

1517
const fixBootstrap = (name: string) => fix.bootstrap(name, __dirname);
1618
const gitBootstrap = (name: string) => git.bootstrap(name, __dirname);
@@ -186,24 +188,30 @@ test('respects cwd option', async () => {
186188
});
187189
});
188190

189-
test('recursive extends', async () => {
190-
const cwd = await gitBootstrap('fixtures/recursive-extends');
191-
const actual = await load({}, {cwd});
192-
193-
expect(actual).toMatchObject({
194-
formatter: '@commitlint/format',
195-
extends: ['./first-extended'],
196-
plugins: {},
197-
rules: {
198-
zero: [0, 'never'],
199-
one: [1, 'always'],
200-
two: [2, 'never'],
201-
},
202-
});
203-
});
191+
const mjsConfigFiles = isDynamicAwaitSupported()
192+
? ['commitlint.config.mjs', '.commitlintrc.mjs']
193+
: [];
194+
195+
test.each(
196+
[
197+
'commitlint.config.cjs',
198+
'commitlint.config.js',
199+
'package.json',
200+
'.commitlintrc',
201+
'.commitlintrc.cjs',
202+
'.commitlintrc.js',
203+
'.commitlintrc.json',
204+
'.commitlintrc.yml',
205+
'.commitlintrc.yaml',
206+
...mjsConfigFiles,
207+
].map((configFile) => [configFile])
208+
)('recursive extends with %s', async (configFile) => {
209+
const cwd = await gitBootstrap(`fixtures/recursive-extends-js-template`);
210+
const configPath = path.join(__dirname, `../fixtures/config/${configFile}`);
211+
const config = readFileSync(configPath);
212+
213+
writeFileSync(path.join(cwd, configFile), config);
204214

205-
test('recursive extends with json file', async () => {
206-
const cwd = await gitBootstrap('fixtures/recursive-extends-json');
207215
const actual = await load({}, {cwd});
208216

209217
expect(actual).toMatchObject({
@@ -218,63 +226,13 @@ test('recursive extends with json file', async () => {
218226
});
219227
});
220228

221-
test('recursive extends with yaml file', async () => {
222-
const cwd = await gitBootstrap('fixtures/recursive-extends-yaml');
223-
const actual = await load({}, {cwd});
224-
225-
expect(actual).toMatchObject({
226-
formatter: '@commitlint/format',
227-
extends: ['./first-extended'],
228-
plugins: {},
229-
rules: {
230-
zero: [0, 'never'],
231-
one: [1, 'never'],
232-
two: [2, 'always'],
233-
},
234-
});
235-
});
236-
237-
test('recursive extends with js file', async () => {
238-
const cwd = await gitBootstrap('fixtures/recursive-extends-js');
239-
const actual = await load({}, {cwd});
240-
241-
expect(actual).toMatchObject({
242-
formatter: '@commitlint/format',
243-
extends: ['./first-extended'],
244-
plugins: {},
245-
rules: {
246-
zero: [0, 'never'],
247-
one: [1, 'never'],
248-
two: [2, 'always'],
249-
},
250-
});
251-
});
252-
253-
test('recursive extends with package.json file', async () => {
254-
const cwd = await gitBootstrap('fixtures/recursive-extends-package');
255-
const actual = await load({}, {cwd});
256-
257-
expect(actual).toMatchObject({
258-
formatter: '@commitlint/format',
259-
extends: ['./first-extended'],
260-
plugins: {},
261-
rules: {
262-
zero: [0, 'never'],
263-
one: [1, 'never'],
264-
two: [2, 'never'],
265-
},
266-
});
267-
});
268-
269-
// fails since a jest update: https://github.com/conventional-changelog/commitlint/pull/3362
270-
// eslint-disable-next-line jest/no-disabled-tests
271-
test.skip('recursive extends with ts file', async () => {
229+
test('recursive extends with ts file', async () => {
272230
const cwd = await gitBootstrap('fixtures/recursive-extends-ts');
273231
const actual = await load({}, {cwd});
274232

275233
expect(actual).toMatchObject({
276234
formatter: '@commitlint/format',
277-
extends: ['./first-extended'],
235+
extends: ['./first-extended/index.ts'],
278236
plugins: {},
279237
rules: {
280238
zero: [0, 'never', 'zero'],

@commitlint/load/src/utils/load-config.ts

+42-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import {cosmiconfig, type Loader} from 'cosmiconfig';
1+
import {
2+
cosmiconfig,
3+
defaultLoadersSync,
4+
Options,
5+
type Loader,
6+
} from 'cosmiconfig';
27
import {TypeScriptLoader} from 'cosmiconfig-typescript-loader';
38
import path from 'path';
49

@@ -8,12 +13,12 @@ export interface LoadConfigResult {
813
isEmpty?: boolean;
914
}
1015

16+
const moduleName = 'commitlint';
17+
1118
export async function loadConfig(
1219
cwd: string,
1320
configPath?: string
1421
): Promise<LoadConfigResult | null> {
15-
const moduleName = 'commitlint';
16-
1722
let tsLoaderInstance: Loader | undefined;
1823
const tsLoader: Loader = (...args) => {
1924
if (!tsLoaderInstance) {
@@ -22,6 +27,8 @@ export async function loadConfig(
2227
return tsLoaderInstance(...args);
2328
};
2429

30+
const {searchPlaces, loaders} = getDynamicAwaitConfig();
31+
2532
const explorer = cosmiconfig(moduleName, {
2633
searchPlaces: [
2734
// cosmiconfig overrides default searchPlaces if any new search place is added (For e.g. `*.ts` files),
@@ -41,10 +48,14 @@ export async function loadConfig(
4148
`.${moduleName}rc.cts`,
4249
`${moduleName}.config.ts`,
4350
`${moduleName}.config.cts`,
51+
52+
...(searchPlaces || []),
4453
],
4554
loaders: {
4655
'.ts': tsLoader,
4756
'.cts': tsLoader,
57+
58+
...(loaders || {}),
4859
},
4960
});
5061

@@ -59,3 +70,31 @@ export async function loadConfig(
5970

6071
return null;
6172
}
73+
74+
// See the following issues for more context:
75+
// - Issue: https://github.com/nodejs/node/issues/40058
76+
// - Resolution: https://github.com/nodejs/node/pull/48510 (Node v20.8.0)
77+
export const isDynamicAwaitSupported = () => {
78+
const [major, minor] = process.version
79+
.replace('v', '')
80+
.split('.')
81+
.map((val) => parseInt(val));
82+
83+
return major >= 20 && minor >= 8;
84+
};
85+
86+
// If dynamic await is supported (Node >= v20.8.0), support mjs config.
87+
// Otherwise, don't support mjs and use synchronous js/cjs loaders.
88+
export const getDynamicAwaitConfig = (): Partial<Options> =>
89+
isDynamicAwaitSupported()
90+
? {
91+
searchPlaces: [`.${moduleName}rc.mjs`, `${moduleName}.config.mjs`],
92+
loaders: {},
93+
}
94+
: {
95+
searchPlaces: [],
96+
loaders: {
97+
'.cjs': defaultLoadersSync['.cjs'],
98+
'.js': defaultLoadersSync['.js'],
99+
},
100+
};

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,12 @@ Check the [husky documentation](https://typicode.github.io/husky/#/?id=manual) o
142142
- `.commitlintrc.yml`
143143
- `.commitlintrc.js`
144144
- `.commitlintrc.cjs`
145+
- `.commitlintrc.mjs` (Node >= v20.8.0)
145146
- `.commitlintrc.ts`
146147
- `.commitlintrc.cts`
147148
- `commitlint.config.js`
148149
- `commitlint.config.cjs`
150+
- `commitlint.config.mjs` (Node >= v20.8.0)
149151
- `commitlint.config.ts`
150152
- `commitlint.config.cts`
151153
- `commitlint` field in `package.json`

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
"publish": "lerna publish --conventional-commits",
2020
"reinstall": "yarn clean && yarn install",
2121
"start": "yarn watch",
22-
"test": "cross-env HOME=$PWD jest",
23-
"test-ci": "cross-env HOME=$PWD jest --runInBand",
22+
"test": "cross-env HOME=$PWD NODE_OPTIONS=--experimental-vm-modules jest",
23+
"test-ci": "yarn test --runInBand",
2424
"postinstall": "yarn husky install"
2525
},
2626
"commitlint": {

yarn.lock

+6-6
Original file line numberDiff line numberDiff line change
@@ -3330,13 +3330,13 @@ cosmiconfig@^7.0.0:
33303330
yaml "^1.10.0"
33313331

33323332
cosmiconfig@^8.0.0:
3333-
version "8.1.3"
3334-
resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz#0e614a118fcc2d9e5afc2f87d53cd09931015689"
3335-
integrity sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==
3333+
version "8.3.6"
3334+
resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3"
3335+
integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==
33363336
dependencies:
3337-
import-fresh "^3.2.1"
3337+
import-fresh "^3.3.0"
33383338
js-yaml "^4.1.0"
3339-
parse-json "^5.0.0"
3339+
parse-json "^5.2.0"
33403340
path-type "^4.0.0"
33413341

33423342
cp-file@^7.0.0:
@@ -4886,7 +4886,7 @@ ignore@^5.0.4, ignore@^5.2.0, ignore@^5.2.4:
48864886
resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
48874887
integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==
48884888

4889-
import-fresh@^3.0.0, import-fresh@^3.2.1:
4889+
import-fresh@^3.0.0, import-fresh@^3.2.1, import-fresh@^3.3.0:
48904890
version "3.3.0"
48914891
resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
48924892
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==

0 commit comments

Comments
 (0)