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 3 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
10 changes: 10 additions & 0 deletions docs/user-guide/configure.md
Expand Up @@ -234,6 +234,16 @@ To use one, add a `"plugins"` array to your config, containing "locaters" identi
- npm module name
- absolute path
- path relative to the invoking configuration file
- stylelint plugin object of format

```js
{
ruleName: "plugin-name",
rule: function plugin(opts) { /* Plugin Code */ }
}
```

> Read more about writing [Stylint Plugins here](../developer-guide/plugins.md).
Copy link
Member

Choose a reason for hiding this comment

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

Let's revert this change and then change the preceding paragraph so we don't mix terms like locators and functions:

"To use one, add a "plugins" array to your config, containing either plugin functions or "locaters" identifying the plugins you want to use. As with extends, above, a "locater" can be either a:"

Copy link
Member

Choose a reason for hiding this comment

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

I also agree with @jeddy3's suggestion. Furthermore, "plugin objects" may be more accurate than "plugin functions" because a Stylelint plugin is an object:

module.exports = function createPlugin(ruleName, rule) {
return {
ruleName,
rule,
};
};


Once the plugin is declared, within your `"rules"` object _you'll need to add options_ for the plugin's rule(s), just like any standard rule. Look at the plugin's documentation to know what the rule name should be.

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