Skip to content

Bump cosmiconfig version and conditionally support mjs config #3747

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

Merged
merged 15 commits into from
Nov 10, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions @commitlint/load/fixtures/config/.commitlintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
extends:
- './first-extended'
rules:
zero: [0, 'never']
6 changes: 6 additions & 0 deletions @commitlint/load/fixtures/config/.commitlintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
extends: ['./first-extended'],
rules: {
zero: [0, 'never'],
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ module.exports = {
rules: {
zero: [0, 'never'],
},
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
"rules": {
"zero": [0, "never"]
}
}
}
6 changes: 6 additions & 0 deletions @commitlint/load/fixtures/config/.commitlintrc.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
extends: ['./first-extended'],
rules: {
zero: [0, 'never'],
},
};
4 changes: 4 additions & 0 deletions @commitlint/load/fixtures/config/.commitlintrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
extends:
- './first-extended'
rules:
zero: [0, 'never']
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
extends:
- './first-extended'
rules:
zero: [0, 'never']
zero: [0, 'never']
6 changes: 6 additions & 0 deletions @commitlint/load/fixtures/config/commitlint.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
extends: ['./first-extended'],
rules: {
zero: [0, 'never'],
},
};
6 changes: 6 additions & 0 deletions @commitlint/load/fixtures/config/commitlint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
extends: ['./first-extended'],
rules: {
zero: [0, 'never'],
},
};
6 changes: 6 additions & 0 deletions @commitlint/load/fixtures/config/commitlint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
extends: ['./first-extended'],
rules: {
zero: [0, 'never'],
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
]
}
}
}
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

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

const Configuration: UserConfig = {
extends: ['./first-extended'],
extends: ['./first-extended/index.ts'],
rules: {
zero: [0, 'never', 'zero']
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type {UserConfig} from '../types';
module.exports = {
extends: ['./second-extended'],
extends: ['./second-extended/index.ts'],
rules: {
one: [1, 'never', 'one']
}
Expand Down

This file was deleted.

This file was deleted.

96 changes: 27 additions & 69 deletions @commitlint/load/src/load.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ jest.mock('@scope/commitlint-plugin-example', () => scopedPlugin, {
});

import path from 'path';
import {readFileSync, writeFileSync} from 'fs';
import resolveFrom from 'resolve-from';
import {fix, git, npm} from '@commitlint/test';

import load from './load';
import {isDynamicAwaitSupported} from './utils/load-config';

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

test('recursive extends', async () => {
const cwd = await gitBootstrap('fixtures/recursive-extends');
const actual = await load({}, {cwd});

expect(actual).toMatchObject({
formatter: '@commitlint/format',
extends: ['./first-extended'],
plugins: {},
rules: {
zero: [0, 'never'],
one: [1, 'always'],
two: [2, 'never'],
},
});
});
const mjsConfigFiles = isDynamicAwaitSupported()
Copy link
Contributor Author

@joberstein joberstein Nov 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New set of tests for each config type. I removed the older tests and their fixture data, but verified they were still passing in an older commit.

? ['commitlint.config.mjs', '.commitlintrc.mjs']
: [];

test.each(
[
'commitlint.config.cjs',
'commitlint.config.js',
'package.json',
'.commitlintrc',
'.commitlintrc.cjs',
'.commitlintrc.js',
'.commitlintrc.json',
'.commitlintrc.yml',
'.commitlintrc.yaml',
...mjsConfigFiles,
].map((configFile) => [configFile])
)('recursive extends with %s', async (configFile) => {
const cwd = await gitBootstrap(`fixtures/recursive-extends-js-template`);
const configPath = path.join(__dirname, `../fixtures/config/${configFile}`);
const config = readFileSync(configPath);

writeFileSync(path.join(cwd, configFile), config);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test.each writes a config file from fixtures/config to the template directory and then loads the found config from the current working directory. Everything except ts files should be supported by the template directory.


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

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

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

expect(actual).toMatchObject({
formatter: '@commitlint/format',
extends: ['./first-extended'],
plugins: {},
rules: {
zero: [0, 'never'],
one: [1, 'never'],
two: [2, 'always'],
},
});
});

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

expect(actual).toMatchObject({
formatter: '@commitlint/format',
extends: ['./first-extended'],
plugins: {},
rules: {
zero: [0, 'never'],
one: [1, 'never'],
two: [2, 'always'],
},
});
});

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

expect(actual).toMatchObject({
formatter: '@commitlint/format',
extends: ['./first-extended'],
plugins: {},
rules: {
zero: [0, 'never'],
one: [1, 'never'],
two: [2, 'never'],
},
});
});

// fails since a jest update: https://github.com/conventional-changelog/commitlint/pull/3362
// eslint-disable-next-line jest/no-disabled-tests
test.skip('recursive extends with ts file', async () => {
test('recursive extends with ts file', async () => {
const cwd = await gitBootstrap('fixtures/recursive-extends-ts');
const actual = await load({}, {cwd});

expect(actual).toMatchObject({
formatter: '@commitlint/format',
extends: ['./first-extended'],
extends: ['./first-extended/index.ts'],
plugins: {},
rules: {
zero: [0, 'never', 'zero'],
Expand Down
45 changes: 42 additions & 3 deletions @commitlint/load/src/utils/load-config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import {cosmiconfig, type Loader} from 'cosmiconfig';
import {
cosmiconfig,
defaultLoadersSync,
Options,
type Loader,
} from 'cosmiconfig';
import {TypeScriptLoader} from 'cosmiconfig-typescript-loader';
import path from 'path';

Expand All @@ -8,12 +13,12 @@ export interface LoadConfigResult {
isEmpty?: boolean;
}

const moduleName = 'commitlint';

export async function loadConfig(
cwd: string,
configPath?: string
): Promise<LoadConfigResult | null> {
const moduleName = 'commitlint';

let tsLoaderInstance: Loader | undefined;
const tsLoader: Loader = (...args) => {
if (!tsLoaderInstance) {
Expand All @@ -22,6 +27,8 @@ export async function loadConfig(
return tsLoaderInstance(...args);
};

const {searchPlaces, loaders} = getDynamicAwaitConfig();

const explorer = cosmiconfig(moduleName, {
searchPlaces: [
// cosmiconfig overrides default searchPlaces if any new search place is added (For e.g. `*.ts` files),
Expand All @@ -41,10 +48,14 @@ export async function loadConfig(
`.${moduleName}rc.cts`,
`${moduleName}.config.ts`,
`${moduleName}.config.cts`,

...(searchPlaces || []),
],
loaders: {
'.ts': tsLoader,
'.cts': tsLoader,

...(loaders || {}),
},
});

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

return null;
}

// See the following issues for more context:
// - Issue: https://github.com/nodejs/node/issues/40058
// - Resolution: https://github.com/nodejs/node/pull/48510 (Node v20.8.0)
export const isDynamicAwaitSupported = () => {
const [major, minor] = process.version
.replace('v', '')
.split('.')
.map((val) => parseInt(val));

return major >= 20 && minor >= 8;
};

// If dynamic await is supported (Node >= v20.8.0), support mjs config.
// Otherwise, don't support mjs and use synchronous js/cjs loaders.
export const getDynamicAwaitConfig = (): Partial<Options> =>
isDynamicAwaitSupported()
? {
searchPlaces: [`.${moduleName}rc.mjs`, `${moduleName}.config.mjs`],
loaders: {},
}
: {
searchPlaces: [],
loaders: {
'.cjs': defaultLoadersSync['.cjs'],
'.js': defaultLoadersSync['.js'],
},
};
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,12 @@ Check the [husky documentation](https://typicode.github.io/husky/#/?id=manual) o
- `.commitlintrc.yml`
- `.commitlintrc.js`
- `.commitlintrc.cjs`
- `.commitlintrc.mjs` (Node >= v20.8.0)
- `.commitlintrc.ts`
- `.commitlintrc.cts`
- `commitlint.config.js`
- `commitlint.config.cjs`
- `commitlint.config.mjs` (Node >= v20.8.0)
- `commitlint.config.ts`
- `commitlint.config.cts`
- `commitlint` field in `package.json`
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"publish": "lerna publish --conventional-commits",
"reinstall": "yarn clean && yarn install",
"start": "yarn watch",
"test": "cross-env HOME=$PWD jest",
"test-ci": "cross-env HOME=$PWD jest --runInBand",
"test": "cross-env HOME=$PWD NODE_OPTIONS=--experimental-vm-modules jest",
"test-ci": "yarn test --runInBand",
"postinstall": "yarn husky install"
},
"commitlint": {
Expand Down
12 changes: 6 additions & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3330,13 +3330,13 @@ cosmiconfig@^7.0.0:
yaml "^1.10.0"

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

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

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