Skip to content
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

Add resolveConfig to Node.js API #5734

Merged
merged 7 commits into from Nov 26, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 31 additions & 0 deletions docs/user-guide/usage/node-api.md
Expand Up @@ -171,3 +171,34 @@ stylelint
```

Note that the customSyntax option also accepts a string. [Refer to the options documentation for details](./options.md#customsyntax).

## Resolving the effective config for a file

If you want to find out what exact configuration will be used for a file without actually linting it, you can use the `resolveConfig()` function. Given a file path, it will return a Promise that resolves with the effective configuration object:

```js
const config = await stylelint.resolveConfig(filePath);

// config => {
// rules: {
// 'color-no-invalid-hex': true
// },
// extends: [
// 'stylelint-config-standard',
// 'stylelint-config-css-modules'
// ],
// plugins: [
// 'stylelint-scss'
// ],
// …
// }
```

If a configuration cannot be found for a file, `resolveConfig()` will return a Promise that resolves to `null`.

You can also pass the following subset of the [options that you would normally pass to `lint()`](#options):

- `cwd`
- `config`
- `configBasedir`
- `customSyntax`
44 changes: 44 additions & 0 deletions lib/__tests__/resolveConfig.test.js
@@ -0,0 +1,44 @@
'use strict';

const path = require('path');
const pluginWarnAboutFoo = require('./fixtures/plugin-warn-about-foo');
const replaceBackslashes = require('../testUtils/replaceBackslashes');
const stylelint = require('..');

it('resolveConfig uses getConfigForFile to retrieve the config', () => {
const filepath = replaceBackslashes(
path.join(__dirname, 'fixtures/getConfigForFile/a/b/foo.css'),
);

return stylelint.resolveConfig(filepath).then((result) => {
expect(result).toEqual({
plugins: [path.join(__dirname, '/fixtures/plugin-warn-about-foo.js')],
rules: {
'block-no-empty': [true],
'plugin/warn-about-foo': ['always'],
},
pluginFunctions: {
'plugin/warn-about-foo': pluginWarnAboutFoo.rule,
},
});
});
});

it('config overrides should apply', () => {
const filepath = replaceBackslashes(
path.join(__dirname, 'fixtures/config-overrides/testPrintConfig/style.css'),
);

return stylelint.resolveConfig(filepath).then((result) => {
adalinesimonian marked this conversation as resolved.
Show resolved Hide resolved
expect(result).toEqual({
rules: {
'block-no-empty': [true],
'color-named': ['never'],
},
});
});
});

it('resolveConfig with no path should resolve to null', () => {
return expect(stylelint.resolveConfig()).resolves.toBeNull();
});
adalinesimonian marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 2 additions & 0 deletions lib/index.js
Expand Up @@ -10,13 +10,15 @@ const ruleMessages = require('./utils/ruleMessages');
const rules = require('./rules');
const standalone = require('./standalone');
const validateOptions = require('./utils/validateOptions');
const resolveConfig = require('./resolveConfig');

/** @type {import('stylelint').PublicApi} */
const stylelint = Object.assign(postcssPlugin, {
lint: standalone,
rules,
formatters,
createPlugin,
resolveConfig,
createLinter: createStylelint,
utils: {
report,
Expand Down
24 changes: 4 additions & 20 deletions lib/printConfig.js
@@ -1,8 +1,7 @@
'use strict';

const createStylelint = require('./createStylelint');
const resolveConfig = require('./resolveConfig');
const globby = require('globby');
const path = require('path');

/** @typedef {import('stylelint').Config} StylelintConfig */

Expand Down Expand Up @@ -33,25 +32,10 @@ module.exports = function printConfig({
return Promise.reject(new Error('The --print-config option does not support globs.'));
}

const stylelint = createStylelint({
return resolveConfig(filePath, {
cwd: (globbyOptions && globbyOptions.cwd) || cwd,
config,
configFile,
configBasedir,
cwd,
});

const globCWD = (globbyOptions && globbyOptions.cwd) || cwd;
const absoluteFilePath = !path.isAbsolute(filePath)
? path.join(globCWD, filePath)
: path.normalize(filePath);

const configSearchPath = stylelint._options.configFile || absoluteFilePath;

return stylelint.getConfigForFile(configSearchPath, absoluteFilePath).then((result) => {
if (result === null) {
return result;
}

return result.config;
configFile,
});
};
47 changes: 47 additions & 0 deletions lib/resolveConfig.js
@@ -0,0 +1,47 @@
'use strict';

const createStylelint = require('./createStylelint');
const path = require('path');

/**
* Resolves the effective configuation for a given file. Resolves to `null` if
* no config is found.
* @param {string} filePath The path to the file to get the config for.
adalinesimonian marked this conversation as resolved.
Show resolved Hide resolved
* @param {Pick<
* import('stylelint').LinterOptions,
* | 'cwd'
* | 'config'
* | 'configBasedir'
* | 'configFile'
* >} options The options to use when creating the Stylelint instance.
adalinesimonian marked this conversation as resolved.
Show resolved Hide resolved
* @returns {Promise<import('stylelint').Config | null>}
*/
module.exports = function resolveConfig(
filePath,
{ cwd = process.cwd(), config, configBasedir, configFile } = {},
) {
if (!filePath) {
return Promise.resolve(null);
}

const stylelint = createStylelint({
config,
configFile,
configBasedir,
cwd,
});

const absoluteFilePath = !path.isAbsolute(filePath)
? path.join(cwd, filePath)
: path.normalize(filePath);

const configSearchPath = stylelint._options.configFile || absoluteFilePath;

return stylelint.getConfigForFile(configSearchPath, absoluteFilePath).then((result) => {
if (result === null) {
return result;
}

return result.config;
});
};
10 changes: 10 additions & 0 deletions types/stylelint/index.d.ts
Expand Up @@ -324,6 +324,16 @@ declare module 'stylelint' {
* @internal
*/
createLinter: (options: LinterOptions) => InternalApi;
/**
* Resolves the effective configuation for a given file. Resolves to
* `null` if no config is found.
adalinesimonian marked this conversation as resolved.
Show resolved Hide resolved
* @param filePath The path to the file to get the config for.
* @param options The options to use when creating the Stylelint instance.
adalinesimonian marked this conversation as resolved.
Show resolved Hide resolved
*/
resolveConfig: (
filePath: string,
options: Pick<LinterOptions, 'cwd' | 'config' | 'configBasedir' | 'configFile'>,
adalinesimonian marked this conversation as resolved.
Show resolved Hide resolved
) => Promise<stylelint.Config | null>;
utils: {
/**
* Report a problem.
Expand Down