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 support for plugin objects as config values #6481

Merged
merged 7 commits into from Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion docs/user-guide/configure.md
Expand Up @@ -229,7 +229,7 @@ For example, [stylelint-scss](https://github.com/stylelint-scss/stylelint-scss)

You'll find more in [awesome stylelint](https://github.com/stylelint/awesome-stylelint#plugins).

To use one, add a `"plugins"` array to your config, containing "locaters" identifying the plugins you want to use. As with `extends`, above, a "locater" can be either a:
To use one, add a `"plugins"` array to your config, containing either [plugin objects](../developer-guide/plugins.md) or "locaters" identifying the plugins you want to use. As with `extends`, above, a "locater" can be either a:

- npm module name
- absolute path
Expand Down
42 changes: 42 additions & 0 deletions lib/__tests__/plugins.test.js
Expand Up @@ -39,6 +39,14 @@ const configRelativeAndExtendRelative = {
},
};

const configPluginRequire = {
plugins: [require('./fixtures/plugin-warn-about-foo')],
rules: {
'plugin/warn-about-foo': 'always',
'block-no-empty': true,
},
};

const processorRelative = postcss().use(
stylelint({ config: configRelative, configBasedir: __dirname }),
);
Expand All @@ -52,6 +60,7 @@ const processorRelativeAndExtendRelative = postcss().use(
configBasedir: __dirname,
}),
);
const processorPluginRequire = postcss().use(stylelint({ config: configPluginRequire }));

it('one plugin runs', async () => {
const result = await processorRelative.process(cssWithFoo, { from: undefined });
Expand Down Expand Up @@ -108,6 +117,39 @@ it('config with its own plugins extending another config that invokes a plugin w
expect(result.warnings()[0].node).toBeTruthy();
});

it('plugin with CJS require()', async () => {
const result = await processorPluginRequire.process(cssWithFoo, { from: undefined });

expect(result.warnings()).toHaveLength(2);
expect(result.warnings()[0].text).toBe('found .foo (plugin/warn-about-foo)');
phoenisx marked this conversation as resolved.
Show resolved Hide resolved
expect(result.warnings()[1].text).toBe('Unexpected empty block (block-no-empty)');
expect(result.warnings()[0].node).toBeTruthy();
});

it('plugin with ESM import()', async () => {
const result = await postcss()
.use(
stylelint({
config: {
// Following object mocks `await import()` style imports, since
// jest without node --experimental-vm-modules enabled fails to
// support dynamic ESM imports.
plugins: [{ default: require('./fixtures/plugin-warn-about-foo') }], // Similar to `await import()`
rules: {
'plugin/warn-about-foo': 'always',
'block-no-empty': true,
},
},
}),
)
.process(cssWithFoo, { from: undefined });

expect(result.warnings()).toHaveLength(2);
expect(result.warnings()[0].text).toBe('found .foo (plugin/warn-about-foo)');
phoenisx marked this conversation as resolved.
Show resolved Hide resolved
expect(result.warnings()[1].text).toBe('Unexpected empty block (block-no-empty)');
expect(result.warnings()[0].node).toBeTruthy();
});

describe('plugin using exposed rules via stylelint.rules', () => {
const cssWithDirectiveLower = '/** @@check-color-hex-case */ a { color: #eee; }';
const cssWithDirectiveUpper = '/** @@check-color-hex-case */ a { color: #EEE; }';
Expand Down
16 changes: 14 additions & 2 deletions lib/augmentConfig.js
Expand Up @@ -150,7 +150,13 @@ function absolutizePaths(config, configDir, cwd) {
}

if (config.plugins) {
config.plugins = [config.plugins].flat().map((lookup) => getModulePath(configDir, lookup, cwd));
config.plugins = [config.plugins].flat().map((lookup) => {
if (typeof lookup === 'string') {
return getModulePath(configDir, lookup, cwd);
}

return lookup;
});
}

if (config.processors) {
Expand Down Expand Up @@ -322,7 +328,13 @@ function addPluginFunctions(config) {
const pluginFunctions = {};

for (const pluginLookup of normalizedPlugins) {
let pluginImport = require(pluginLookup);
let pluginImport;

if (typeof pluginLookup === 'string') {
pluginImport = require(pluginLookup);
} else {
pluginImport = pluginLookup;
}

// Handle either ES6 or CommonJS modules
pluginImport = pluginImport.default || pluginImport;
Expand Down
5 changes: 4 additions & 1 deletion types/stylelint/index.d.ts
Expand Up @@ -7,7 +7,10 @@ declare module 'stylelint' {
export type Severity = 'warning' | 'error';

export type ConfigExtends = string | string[];
export type ConfigPlugins = string | string[];
export type PluginType =
| { default?: { ruleName: string; rule: Rule } }
| { ruleName: string; rule: Rule };
export type ConfigPlugins = string | PluginType | (string | PluginType)[];
export type ConfigProcessor = string | [string, Object];
export type ConfigProcessors = string | ConfigProcessor[];
export type ConfigIgnoreFiles = string | string[];
Expand Down