Skip to content

Commit

Permalink
Add support for loading custom formatter from package (#6228)
Browse files Browse the repository at this point in the history
* Add support for loading custom formatter from package when using PnP (fix #6100)

* Update lib/__tests__/resolveCustomFormatter.test.js

* Apply suggestions from code review

* Update lib/__tests__/resolveCustomFormatter.test.js

* Update lib/__tests__/resolveCustomFormatter.test.js

* Update lib/__tests__/resolveCustomFormatter.test.js

* Apply suggestions from code review

Co-authored-by: Masafumi Koba <473530+ybiquitous@users.noreply.github.com>

* Added cli test and updated doc

* Updated doc and added test with module

Co-authored-by: JounQin <admin@1stg.me>
Co-authored-by: Masafumi Koba <473530+ybiquitous@users.noreply.github.com>
  • Loading branch information
3 people committed Jul 29, 2022
1 parent 3a277b1 commit e271601
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ node_modules
.eslintcache
yarn.lock
.vscode/settings.json
.idea
2 changes: 1 addition & 1 deletion docs/user-guide/usage/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Options are:
- `unix` - generates messages like a C compiler, so that tools like Emacs' _Compilation mode_ can hyperlink them
- `verbose` - extends `string` to include a list of checked files and a tally for each rule

The `formatter` Node.js API option can also accept a function, whereas the `--custom-formatter` CLI flag accepts a path to a JS file exporting one. The function in both cases must fit the signature described in the [Developer Guide](../../developer-guide/formatters.md).
The `formatter` Node.js API option can also accept a function, whereas the `--custom-formatter` CLI flag accepts a path (either a filesystem path or a dependency) to a JS file exporting one. The function in both cases must fit the signature described in the [Developer Guide](../../developer-guide/formatters.md).

## `cache`

Expand Down
1 change: 1 addition & 0 deletions lib/__tests__/__mocks__/stylelint-test-custom-formatter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../fixtures/formatters/customFormatter');
1 change: 1 addition & 0 deletions lib/__tests__/__snapshots__/cli.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ exports[`CLI --help 1`] = `
--custom-formatter
Path to a JS file exporting a custom formatting function.
The file can either be a filesystem path, a module name, or a file to load from a dependency.
--quiet, -q
Expand Down
28 changes: 28 additions & 0 deletions lib/__tests__/cli.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,4 +333,32 @@ describe('CLI', () => {

expect(process.stdout.write).toHaveBeenCalledTimes(0);
});

it('--custom-formatter with filesystem path', async () => {
await cli([
`--custom-formatter=${fixturesPath('formatters/customFormatter')}`,
'--config',
fixturesPath('default-severity-warning.json'),
fixturesPath('empty-block.css'),
]);

expect(process.stdout.write).toHaveBeenCalledTimes(1);
const output = process.stdout.write.mock.calls[0][0];

expect(output).toBe('Custom formatter reports 1 warning(s).');
});

it('--custom-formatter with node module', async () => {
await cli([
`--custom-formatter=stylelint-test-custom-formatter`,
'--config',
fixturesPath('default-severity-warning.json'),
fixturesPath('empty-block.css'),
]);

expect(process.stdout.write).toHaveBeenCalledTimes(1);
const output = process.stdout.write.mock.calls[0][0];

expect(output).toBe('Custom formatter reports 1 warning(s).');
});
});
3 changes: 3 additions & 0 deletions lib/__tests__/fixtures/formatters/customFormatter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = function customFormatter(messages) {
return `Custom formatter reports ${messages.length} warning(s).`;
};
34 changes: 34 additions & 0 deletions lib/__tests__/resolveCustomFormatter.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
jest.mock('fs');
jest.mock('path');

const fs = require('fs');
const path = require('path');
const resolveCustomFormatter = require('../resolveCustomFormatter');

describe('resolveCustomFormatter', () => {
it('should return absolute path when provided path is a file path', () => {
const aRelativePath = 'a/relative/path';
const expected = `/cwd/${aRelativePath}`;

path.resolve.mockReturnValue(expected);
path.isAbsolute.mockReturnValue(false);
fs.existsSync.mockReturnValue(true);

const result = resolveCustomFormatter(aRelativePath);

expect(result).toEqual(expected);
});

it('should return provided path when path is neither absolute nor relative', () => {
const aModulePath = '@stylelint/prettier-config/index.js';

fs.existsSync.mockReturnValue(false);

const result = resolveCustomFormatter(aModulePath);

const realPathModule = jest.requireActual('path');
const expectedPath = realPathModule.join('node_modules', aModulePath);

expect(result.endsWith(expectedPath)).toBe(true);
});
});
6 changes: 3 additions & 3 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const printConfig = require('./printConfig');
const resolveFrom = require('resolve-from');
const standalone = require('./standalone');
const writeOutputFile = require('./writeOutputFile');
const resolveCustomFormatter = require('./resolveCustomFormatter');

const EXIT_CODE_ERROR = 2;

Expand Down Expand Up @@ -178,6 +179,7 @@ const meowOptions = {
--custom-formatter
Path to a JS file exporting a custom formatting function.
The file can either be a filesystem path, a module name, or a file to load from a dependency.
--quiet, -q
Expand Down Expand Up @@ -338,9 +340,7 @@ module.exports = async (argv) => {
let formatter = cli.flags.formatter;

if (cli.flags.customFormatter) {
const customFormatter = path.isAbsolute(cli.flags.customFormatter)
? cli.flags.customFormatter
: path.join(process.cwd(), cli.flags.customFormatter);
const customFormatter = resolveCustomFormatter(cli.flags.customFormatter);

formatter = require(customFormatter);
}
Expand Down
16 changes: 16 additions & 0 deletions lib/resolveCustomFormatter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const fs = require('fs');
const path = require('path');

/**
* @param {string} formatterPath
* @returns {string}
*/
module.exports = function resolveCustomFormatter(formatterPath) {
const resolvedPath = path.resolve(formatterPath);

if (fs.existsSync(resolvedPath)) {
return resolvedPath;
}

return require.resolve(formatterPath);
};

0 comments on commit e271601

Please sign in to comment.