mirror of
https://github.com/snachodog/just-the-docs.git
synced 2025-09-13 13:23:32 -06:00
Initial commit
This commit is contained in:
37
node_modules/stylelint/docs/developer-guide/formatters.md
generated
vendored
Normal file
37
node_modules/stylelint/docs/developer-guide/formatters.md
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# Writing formatters
|
||||
|
||||
A formatter is a function that accepts *an array of these stylelint result objects* and outputs a string:
|
||||
|
||||
```js
|
||||
// A stylelint result object
|
||||
{
|
||||
source: "path/to/file.css", // The filepath or PostCSS identifier like <input css 1>
|
||||
errored: true, // This is `true` if at least one rule with an "error"-level severity triggered a warning
|
||||
warnings: [ // Array of rule violation warning objects, each like the following ...
|
||||
{
|
||||
line: 3,
|
||||
column: 12,
|
||||
rule: "block-no-empty",
|
||||
severity: "error",
|
||||
text: "You should not have an empty block (block-no-empty)"
|
||||
},
|
||||
..
|
||||
],
|
||||
deprecations: [ // Array of deprecation warning objects, each like the following ...
|
||||
{
|
||||
text: "Feature X has been deprecated and will be removed in the next major version.",
|
||||
reference: "https://stylelint.io/docs/feature-x.md"
|
||||
}
|
||||
],
|
||||
invalidOptionWarnings: [ // Array of invalid option warning objects, each like the following ...
|
||||
{
|
||||
text: "Invalid option X for rule Y",
|
||||
}
|
||||
],
|
||||
ignored: false // This is `true` if the file's path matches a provided ignore pattern
|
||||
}
|
||||
```
|
||||
|
||||
## `stylelint.formatters`
|
||||
|
||||
stylelint's internal formatters are exposed publicly in `stylelint.formatters`.
|
142
node_modules/stylelint/docs/developer-guide/plugins.md
generated
vendored
Normal file
142
node_modules/stylelint/docs/developer-guide/plugins.md
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
# Writing plugins
|
||||
|
||||
Plugins are rules and sets of rules built by the community.
|
||||
|
||||
We recommend familiarising yourself and adhering to stylelint's [conventions for writing rules](rules.md), including those for names, options, messages, tests and docs.
|
||||
|
||||
## The anatomy of a plugin
|
||||
|
||||
```js
|
||||
// Abbreviated example
|
||||
var stylelint = require("stylelint")
|
||||
|
||||
var ruleName = "plugin/foo-bar"
|
||||
var messages = stylelint.utils.ruleMessages(ruleName, {
|
||||
expected: "Expected ...",
|
||||
})
|
||||
|
||||
module.exports = stylelint.createPlugin(ruleName, function(primaryOption, secondaryOptionObject) {
|
||||
return function(postcssRoot, postcssResult) {
|
||||
var validOptions = stylelint.utils.validateOptions(postcssResult, ruleName, { .. })
|
||||
if (!validOptions) { return }
|
||||
// ... some logic ...
|
||||
stylelint.utils.report({ .. })
|
||||
}
|
||||
})
|
||||
|
||||
module.exports.ruleName = ruleName
|
||||
module.exports.messages = messages
|
||||
```
|
||||
|
||||
Your plugin's rule name must be namespaced, e.g. `your-namespace/your-rule-name`. If your plugin provides only a single rule or you can't think of a good namespace, you can simply use `plugin/my-rule`. This namespace ensures that plugin rules will never clash with core rules. *Make sure you document your plugin's rule name (and namespace) for users, because they will need to use it in their config.*
|
||||
|
||||
`stylelint.createPlugin(ruleName, ruleFunction)` ensures that your plugin will be setup properly alongside other rules.
|
||||
|
||||
In order for your plugin rule to work with the [standard configuration format](../user-guide/configuration.md#rules), `ruleFunction` should accept 2 arguments: the primary option and, optionally, an secondary options object.
|
||||
|
||||
`ruleFunction` should return a function that is essentially a little [PostCSS plugin](https://github.com/postcss/postcss/blob/master/docs/writing-a-plugin.md): it takes 2 arguments: the PostCSS Root (the parsed AST), and the PostCSS LazyResult. You'll have to [learn about the PostCSS API](https://github.com/postcss/postcss/blob/master/docs/api.md).
|
||||
|
||||
## `stylelint.utils`
|
||||
|
||||
stylelint exposes some utilities that are useful. *For details about the APIs of these functions, please look at comments in the source code and examples in the standard rules.*
|
||||
|
||||
### `stylelint.utils.report`
|
||||
|
||||
Adds warnings from your plugin to the list of warnings that stylelint will report to the user.
|
||||
|
||||
*Do not use PostCSS's `node.warn()` method directly.* When you use `stylelint.utils.report`, your plugin will respect disabled ranges and other possible future features of stylelint, providing a better user-experience, one that better fits the standard rules.
|
||||
|
||||
### `stylelint.utils.ruleMessages`
|
||||
|
||||
Tailors your messages to the format of standard stylelint rules.
|
||||
|
||||
### `stylelint.utils.validateOptions`
|
||||
|
||||
Validates the options for your rule.
|
||||
|
||||
### `stylelint.utils.checkAgainstRule`
|
||||
|
||||
Checks CSS against a standard stylelint rule *within your own rule*. This function provides power and flexibility for plugins authors who wish to modify, constrain, or extend the functionality of existing stylelint rules.
|
||||
|
||||
Accepts an options object and a callback that is invoked with warnings from the specified rule. The options are:
|
||||
- `ruleName`: The name of the rule you are invoking.
|
||||
- `ruleSettings`: Settings for the rule you are invoking, formatting in the same way they would be in a `.stylelintrc` configuration object.
|
||||
- `root`: The root node to run this rule against.
|
||||
|
||||
Use the warning to create a *new* warning *from your plugin rule* that you report with `stylelint.utils.report`.
|
||||
|
||||
For example, imagine you want to create a plugin that runs `at-rule-no-unknown` with a built-in list of exceptions for at-rules provided by your preprocessor-of-choice:
|
||||
|
||||
```js
|
||||
const allowableAtRules = [..]
|
||||
|
||||
function myPluginRule(primaryOption, secondaryOptions) {
|
||||
return (root, result) => {
|
||||
const defaultedOptions = Object.assign({}, secondaryOptions, {
|
||||
ignoreAtRules: allowableAtRules.concat(options.ignoreAtRules || []),
|
||||
})
|
||||
|
||||
stylelint.utils.checkAgainstRule({
|
||||
ruleName: 'at-rule-no-unknown',
|
||||
ruleSettings: [primaryOption, defaultedOptions],
|
||||
root: root
|
||||
}, (warning) => {
|
||||
stylelint.utils.report({
|
||||
message: myMessage,
|
||||
ruleName: myRuleName,
|
||||
result: result,
|
||||
node: warning.node,
|
||||
line: warning.line,
|
||||
column: warning.column,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## `stylelint.rules`
|
||||
|
||||
All of the rule functions are available at `stylelint.rules`. This allows you to build on top of existing rules for your particular needs.
|
||||
|
||||
A typical use-case is to build in more complex conditionals that the rule's options allow for. For example, maybe your codebase uses special comment directives to customize rule options for specific stylesheets. You could build a plugin that checks those directives and then runs the appropriate rules with the right options (or doesn't run them at all).
|
||||
|
||||
All rules share a common signature. They are a function that accepts two arguments: a primary option and a secondary options object. And that functions returns a function that has the signature of a PostCSS plugin, expecting a PostCSS root and result as its arguments.
|
||||
|
||||
Here's a simple example of a plugin that runs `color-hex-case` only if there is a special directive `@@check-color-hex-case` somewhere in the stylesheet:
|
||||
|
||||
```js
|
||||
export default stylelint.createPlugin(ruleName, function (expectation) {
|
||||
const runColorHexCase = stylelint.rules["color-hex-case"](expectation)
|
||||
return (root, result) => {
|
||||
if (root.toString().indexOf("@@check-color-hex-case") === -1) return
|
||||
runColorHexCase(root, result)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Allow primary option arrays
|
||||
|
||||
If your plugin can accept an array as its primary option, you must designate this by setting the property `primaryOptionArray = true` on your rule function. For more information, check out the ["Working on rules"](rules.md#primary) doc.
|
||||
|
||||
## External helper modules
|
||||
|
||||
In addition to the standard parsers mentioned in the ["Working on rules"](rules.md) doc, there are other external modules used within stylelint that we recommend using. These include:
|
||||
|
||||
- [normalize-selector](https://github.com/getify/normalize-selector): Normalize CSS selectors.
|
||||
- [postcss-resolve-nested-selector](https://github.com/davidtheclark/postcss-resolve-nested-selector): Given a (nested) selector in a PostCSS AST, return an array of resolved selectors.
|
||||
- [style-search](https://github.com/davidtheclark/style-search): Search CSS (and CSS-like) strings, with sensitivity to whether matches occur inside strings, comments, and functions.
|
||||
|
||||
Have a look through [stylelint's internal utils](https://github.com/stylelint/stylelint/tree/master/lib/utils) and if you come across one that you need in your plugin, then please consider helping us extract it out into a external module.
|
||||
|
||||
## Testing plugins
|
||||
|
||||
For testing your plugin, you might consider using the same rule-testing function that stylelint uses internally: [`stylelint-test-rule-tape`](https://github.com/stylelint/stylelint-test-rule-tape).
|
||||
|
||||
## Plugin packs
|
||||
|
||||
To make a single module provide multiple rules, simply export an array of plugin objects (rather than a single object).
|
||||
|
||||
## Sharing plugins and plugin packs
|
||||
|
||||
- Use the `stylelint-plugin` keyword within your `package.json`.
|
||||
- Once your plugin is published, please send us a Pull Request to add your plugin to [the list](../user-guide/plugins.md).
|
39
node_modules/stylelint/docs/developer-guide/processors.md
generated
vendored
Normal file
39
node_modules/stylelint/docs/developer-guide/processors.md
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# Writing processors
|
||||
|
||||
Processors are functions that hook into stylelint's pipeline, modifying code on its way into stylelint and modifying results on their way out.
|
||||
|
||||
*Processors can only be used with the CLI and the Node API, not with the PostCSS plugin.*
|
||||
|
||||
Processor modules are functions that accept an options object and return an object with the following the functions, which hook into the processing of each file:
|
||||
|
||||
- **code**: A function that accepts two arguments, the file's code and the file's path, and returns a string for stylelint to lint.
|
||||
- **result**: A function that accepts two arguments, the file's stylelint result object and the file's path, and either mutates the result object (returning nothing) or returns a new one.
|
||||
|
||||
```js
|
||||
// my-processor.js
|
||||
module.exports = function(options) {
|
||||
return {
|
||||
code: function(input, filepath) {
|
||||
// ...
|
||||
return transformedCode;
|
||||
},
|
||||
result: function(stylelintResult, filepath) {
|
||||
// ...
|
||||
return transformedResult;
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Processors can enable stylelint to lint the CSS within non-stylesheet files. For example, let's say you want to lint the CSS within `<style>` tags in HTML. If you just feed stylelint your HTML code, you'll run into problems, because PostCSS does not parse HTML. Instead, you can create a processor that does the following:
|
||||
|
||||
- In the `code` processor function, extract CSS from the `<style>` tags in the HTML code. Return a CSS string containing all that extracted CSS, which is what stylelint will inspect.
|
||||
- Build a sourcemap while performing the extraction, so warning positions can be tailored to match the original source HTML.
|
||||
- In the `result` processor function, modify the line/column position of each warning using your sourcemap.
|
||||
|
||||
*Processor options must be JSON-friendly*, because users will need to include them in `.stylelintrc` files.
|
||||
|
||||
## Sharing processors
|
||||
|
||||
- Use the `stylelint-processor` keyword within your `package.json`.
|
||||
- Once your processor is published, please send us a Pull Request to add your processor to [the list](../user-guide/processors.md).
|
88
node_modules/stylelint/docs/developer-guide/rule-testers.md
generated
vendored
Normal file
88
node_modules/stylelint/docs/developer-guide/rule-testers.md
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
# Rule testers
|
||||
|
||||
stylelint rules require *a lot* of tests. So we've built a specialized stylelint rule testing format to speed up the mass production of consistent, effective rule tests.
|
||||
|
||||
There is a schema for describing tests, and a function for creating "rule testers" that interpret that schema using a test framework (e.g. tape or Mocha).
|
||||
|
||||
When developing plugins, you can use the following rule testers or create your own.
|
||||
|
||||
- stylelint-test-rule-tape
|
||||
- stylelint-test-rule-mocha
|
||||
- stylelint-test-rule-ava
|
||||
|
||||
## Using a rule tester
|
||||
|
||||
To use the rule tester of your choice, do the following:
|
||||
|
||||
```js
|
||||
// `testRule` = the imported rule tester
|
||||
testRule(rule, testGroupDescription)
|
||||
```
|
||||
|
||||
`rule` is just the rule that you are testing (a function).
|
||||
|
||||
`testGroupDescription` is an object fitting the following schema.
|
||||
|
||||
### The test group schema
|
||||
|
||||
Each test group object describes a set of test-cases for a certain rule with a certain configuration.
|
||||
|
||||
Required properties:
|
||||
|
||||
- `ruleName` {string}: The name of the rule. Used in generated test-case descriptions.
|
||||
- `config` {any}: The rule's configuration for this test group. Should match the rule configuration format you'd use in `.stylelintrc`.
|
||||
- `accept` {array}: An array of objects describing test cases that *should not violate the rule*. Each object has these properties:
|
||||
- `code` {string}: The source CSS to check.
|
||||
- `description` {string}: *Optional.* A description of the case.
|
||||
- `only` {boolean}: If `true`, run only this test case.
|
||||
- `reject` {array}: An array of objects describing test cases that *should violate the rule once*. Each object has these properties:
|
||||
- `code` {string}: The source CSS to check.
|
||||
- `message` {string}: The message of the expected violation.
|
||||
- `line` {number}: *Optional but recommended.* The expected line number of the violation. If this is left out, the line won't be checked.
|
||||
- `column` {number}: *Optional but recommended.* The expected column number of the violation. If this is left out, the column won't be checked.
|
||||
- `description` {string}: *Optional.* A description of the case.
|
||||
- `only` {boolean}: If `true`, run only this test case.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- `syntax` {"css"|"less"|"scss"|"sugarss"}: Defaults to `"css"`. Other settings use special parsers.
|
||||
- `skipBasicChecks` {boolean}: Defaults to `false`. If `true`, a few rudimentary checks (that should almost always be included) will not be performed. You can check those out in `lib/testUtils/basicChecks.js`.
|
||||
- `preceedingPlugins` {array}: An array of PostCSS plugins that should be run before the CSS is tested.
|
||||
|
||||
## Creating a rule tester
|
||||
|
||||
stylelint itself exposes a means of creating rule testers with just about any testing framework.
|
||||
|
||||
```js
|
||||
var testRule = stylelint.createRuleTester(equalityCheck)
|
||||
```
|
||||
|
||||
Pass in an `equalityCheck` function. Given some information, this checker should use whatever test runner you like to perform equality checks.
|
||||
|
||||
The `equalityCheck` function should accept two arguments:
|
||||
|
||||
- `processCss` {Promise}: A Promise that resolves with an array of comparisons that you need to check (documented below).
|
||||
- `context` {object}: An object that contains additional information you may need:
|
||||
- `caseDescription` {string}: A description of the test case as whole. It will end up printing like something this:
|
||||
```bash
|
||||
> rule: value-list-comma-space-before
|
||||
> config: "always-single-line"
|
||||
> code: "a { background-size: 0 ,0;\n}"
|
||||
```
|
||||
- `comparisonCount` {number}: The number of comparisons that will need to be performed (e.g. useful for tape).
|
||||
- `completeAssertionDescription` {string}: While each individual comparison may have its own description, this is a description of the whole assertion (e.g. useful for Mocha).
|
||||
- `only` {boolean}: If `true`, the test runner should only run this test case (e.g. `test.only` in tape, `describe.only` in Mocha).
|
||||
|
||||
`processCss` is a Promise that resolves with an array of comparisons. Each comparison has the following properties:
|
||||
|
||||
- `actual` {any}: Some actual value.
|
||||
- `expected` {any}: Some expected value.
|
||||
- `description` {string}: A (possibly empty) description of the comparison.
|
||||
|
||||
Within the `equalityCheck` function, you need to ensure that you do the following:
|
||||
|
||||
- Set up the test case.
|
||||
- When `processCss` resolves, loop through every comparison.
|
||||
- For each comparison, make an assertion checking that `actual === expected`.
|
||||
|
||||
A `testRule` function (as described above) is returned.
|
260
node_modules/stylelint/docs/developer-guide/rules.md
generated
vendored
Normal file
260
node_modules/stylelint/docs/developer-guide/rules.md
generated
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
# Working on rules
|
||||
|
||||
**Please help us create, enhance, and debug stylelint rules!**
|
||||
|
||||
There are well over a hundred rules already, so stylelint *needs* community contributions to continue to improve.
|
||||
|
||||
If you like stylelint and open source software (since you're reading this, you almost certainly do), please consider taking some time to pitch in. Not only will you help stylelint thrive, you will also learn a thing or two — about CSS, PostCSS, Node, ES2015, unit testing, open source software, and more.
|
||||
|
||||
**We want to do everything we can to encourage contributions!** So if you want to participate but don't end up doing it for one reason or another, please file an issue and give us feedback about what we could do to better encourage you.
|
||||
|
||||
Also: we hope that your participation in the project isn't a one-off. *We'd love to add more members to the organization and see more regulars pop up in issues and pull requests!*
|
||||
|
||||
## Creating a new rule
|
||||
|
||||
First, open [an issue](https://github.com/stylelint/stylelint/issues/new) with your idea for the new rule.
|
||||
|
||||
Usually we have some discussion about the rule's purpose, name, options, and suitability as a rule.
|
||||
|
||||
### Criteria for inclusion
|
||||
|
||||
We discuss whether the rule meets the following criteria for inclusion in stylelint:
|
||||
|
||||
- Applicable to standard CSS syntax only.
|
||||
- Generally useful; not tied to idiosyncratic patterns.
|
||||
- Has a clear and unambiguous finished state.
|
||||
- Has a singular purpose.
|
||||
- Is standalone, and doesn't rely on another rule.
|
||||
- Does not contain functionality that overlaps with another rule.
|
||||
|
||||
Otherwise, it should be a plugin. However, plugins should also try to adhere to the latter three criteria.
|
||||
|
||||
### Naming a rule
|
||||
|
||||
Have a look at the [rules user guide](../user-guide/about-rules.md) to familiarize yourself the rule naming conventions.
|
||||
|
||||
We take care to ensure that all the rules are named accurately and consistently. Our goals in that effort are to ensure that rules are easy to find and understand, and to prevent us from wanting to change the name later.
|
||||
|
||||
*Rules are named to encourage explicit, rather than implicit, options.* For example, `color-hex-case: "upper"|"lower"` rather than `color-hex-uppercase: "always"|"never"`. As `color-hex-uppercase: "never"` *implies* always lowercase, whereas `color-hex-case: "lower"` makes it *explicit*.
|
||||
|
||||
### Determining options
|
||||
|
||||
#### Primary
|
||||
|
||||
Every rule *must have* a **primary option**.
|
||||
|
||||
- In `"color-hex-case": "upper"`, the primary option is `"upper"`.
|
||||
- In `"indentation": [2, { "except": ["block"] }]`, the primary option is `2`.
|
||||
|
||||
If your rule can accept an array as its primary option, you must designate this by setting the property `primaryOptionArray = true` on your rule function. For example:
|
||||
|
||||
```js
|
||||
function rule(primary, secondary) {
|
||||
return (root, result) => {..}
|
||||
}
|
||||
rule.primaryOptionArray = true
|
||||
export default rule
|
||||
// or, for plugins: stylelint.createPlugin(ruleName, rule)
|
||||
```
|
||||
|
||||
There is one caveat here: If your rule accepts a primary option array, it cannot also accept a primary option object. Whenever possible, if you want your rule to accept a primary option array, you should just make an array the only possibility, instead of allowing for various data structures.
|
||||
|
||||
#### Secondary
|
||||
|
||||
Some rules require extra flexibility to address a variety of use-cases. These can use an **optional secondary options object**.
|
||||
|
||||
- In `"color-hex-case": "upper"`, there is no secondary options object.
|
||||
- In `"indentation": [2, { "except": ["block"] }]`, the secondary options object is `{ "except": ["block"] }`.
|
||||
|
||||
The most typical secondary options are `"ignore": []` and `"except": []`; but anything is possible.
|
||||
|
||||
A rule's secondary option can be anything if you're not ignoring or making exceptions. As an example, `resolveNestedSelectors: true|false` is used within some `selector-*` rules to change how the rule processes nested selectors.
|
||||
|
||||
##### Keyword `"ignore"` and `"except"`
|
||||
|
||||
`"ignore"` and `"except"` accept an array of predefined keyword options e.g. `["relative", "first-nested", "descendant"]`.
|
||||
|
||||
- Use `"ignore"` when you want the rule to simply skip-over a particular pattern.
|
||||
- Use `"except"` when you want to invert the primary option for a particular pattern.
|
||||
|
||||
##### User-defined `"ignore*"`
|
||||
|
||||
Use a more specific secondary option name when accepting a *user-defined* list of things to ignore. This takes the form of `"ignore<Things>": []` e.g. use `"ignoreAtRules": []` if a rule checks at-rules and you want to allow a user to specify which particular at-rule types to ignore.
|
||||
|
||||
### Determine warning messages
|
||||
|
||||
Messages take one of these forms:
|
||||
|
||||
- "Expected \[something\] \[in some context\]".
|
||||
- "Unexpected \[something\] \[in some context\]."
|
||||
|
||||
Look at the messages of other rules to glean more conventions and patterns.
|
||||
|
||||
### Write the rule
|
||||
|
||||
*When writing the rule, always look to other similar rules for conventions and patterns to start from and mimic.*
|
||||
|
||||
You will use the simple [PostCSS API](http://api.postcss.org/) to navigate and analyze the CSS syntax tree. We recommend using the `walk` iterators (e.g. `walkDecls`), rather than using `forEach` to loop through the nodes.
|
||||
|
||||
Depending on the rule, we also recommend using [postcss-value-parser](https://github.com/TrySound/postcss-value-parser) and [postcss-selector-parser](https://github.com/postcss/postcss-selector-parser). There are significant benefits to using these parsers instead of regular expressions or `indexOf` searches (even if they aren't always the most performant method).
|
||||
|
||||
stylelint has a number of [utility functions](https://github.com/stylelint/stylelint/tree/master/lib/utils) that are used in existing rules and might prove useful to you, as well. Please look through those so that you know what's available. (And if you have a new function that you think might prove generally helpful, let's add it to the list!)
|
||||
|
||||
In particular, you will definitely want to use `validateOptions()` so that users are warned about invalid options. (Looking at other rules for examples of options validation will help a lot.)
|
||||
|
||||
### Write tests
|
||||
|
||||
Each rule must be accompanied by tests that contain:
|
||||
|
||||
- All patterns that are considered warnings.
|
||||
- All patterns that should *not* be considered warnings.
|
||||
|
||||
It is easy to write stylelint tests, so *write as many as you can stand to*.
|
||||
|
||||
#### Checklist
|
||||
|
||||
Please run through this checklist and ensure each point is covered by your tests. Especially *consider the edge-cases*. These are where the bugs and shortcomings of rules always arise.
|
||||
|
||||
##### Best practices
|
||||
|
||||
- Ensure you are testing errors in multiple positions, not the same place every time.
|
||||
- Ensure you use realistic (if simple) CSS, and avoid the use of ellipses.
|
||||
- Ensure you use standard CSS syntax by default, and only swap parsers when testing a specific piece of non-standard syntax.
|
||||
- When accessing raw strings from the PostCSS AST, use `node.raws` instead of `node.raw()`. This will ensure string corresponds exactly to the original.
|
||||
|
||||
##### Commonly overlooked edge-cases
|
||||
|
||||
- How does your rule handle variables (`$sass`, `@less`, or `var(--custom-property)`)?
|
||||
- How does your rule handle CSS strings (e.g. `content: "anything goes";`)?
|
||||
- How does your rule handle CSS comments (e.g. `/* anything goes */`)?
|
||||
- How does your rule handle `url()` functions, including data URIs (e.g. `url(anything/goes.jpg)`)?
|
||||
- How does your rule handle vendor prefixes (e.g. `@-webkit-keyframes name {}`)?
|
||||
- How does your rule handle case sensitivity (e.g. `@KEYFRAMES name {}`)?
|
||||
- How does your rule handle a pseudo-class *combined* with a pseudo-element (e.g. `a:hover::before`)?
|
||||
- How does your rule handle nesting (e.g. do you resolve `& a {}`, or check it as is?)?
|
||||
- How does your rule handle whitespace and punctuation (e.g. comparing `rgb(0,0,0)` with `rgb(0, 0, 0)`)?
|
||||
|
||||
#### Running tests
|
||||
|
||||
You can run the tests via:
|
||||
|
||||
```console
|
||||
npm test
|
||||
```
|
||||
|
||||
However, this runs all 25,000+ unit tests and also linting.
|
||||
|
||||
You can use the interactive testing prompt to run tests for just a chosen set of rules (which you'll want to do during development). For example, to run the tests for just the `color-hex-case` and `color-hex-length` rules:
|
||||
|
||||
1. Use `npm run watch` to start the prompt.
|
||||
2. Press `p` to filter by a filename regex pattern.
|
||||
3. Enter `color-hex-case|color-hex-length` i.e. each rule name separated by the pipe symbol (`|`).
|
||||
|
||||
### Write the README
|
||||
|
||||
Each rule must be accompanied by a README, fitting the following format:
|
||||
|
||||
1. Rule name.
|
||||
2. Single line description.
|
||||
3. Prototypical code example.
|
||||
4. Expanded description (if necessary).
|
||||
5. Options.
|
||||
6. Example patterns that are considered warnings (for each option value).
|
||||
7. Example patterns that are *not* considered warnings (for each option value).
|
||||
8. Optional options (if applicable).
|
||||
|
||||
Look at the READMEs of other rules to glean more conventional patterns.
|
||||
|
||||
#### Single line descriptions
|
||||
|
||||
Take the form of:
|
||||
|
||||
- "Disallow ..." (for `no` rules).
|
||||
- "Limit ..." (for `max` rules).
|
||||
- "Require ..." (for rules that accept `"always"` and `"never"` options).
|
||||
- "Specify ..." (for everything else).
|
||||
|
||||
#### Example patterns
|
||||
|
||||
- Use complete CSS patterns i.e. avoid ellipses (`...`)
|
||||
- Use standard CSS syntax (and use `css` code fences) by default.
|
||||
- Use the minimum amount of code possible to communicate the patten e.g. if the rule targets selectors then use an empty rule e.g. `{}`.
|
||||
- Use `{}`, rather than `{ }` for empty rules.
|
||||
- Use the `a` type selector by default.
|
||||
- Use the `@media` at-rules by default.
|
||||
- Use the `color` property by default.
|
||||
- Use *foo*, *bar* and *baz* for names e.g. `.foo`, `#bar` `--baz`
|
||||
|
||||
### Wire up the rule
|
||||
|
||||
The final step is to add references to the new rule in the following places:
|
||||
|
||||
- [The rules `index.js` file](https://github.com/stylelint/stylelint/blob/master/lib/rules/index.js)
|
||||
- [The list of rules](../user-guide/rules.md)
|
||||
- [The example config](../user-guide/example-config.md)
|
||||
|
||||
Once you have something to show, you'll create a [pull request](https://github.com/stylelint/stylelint/compare) to continue the conversation.
|
||||
|
||||
## Adding a option to an existing rule
|
||||
|
||||
First, open [an issue](https://github.com/stylelint/stylelint/issues/new) about the option you wish to add. We'll discuss its functionality and name there.
|
||||
|
||||
Once we've agreed on the direction, you can work on a pull request. Here are the steps you'll need to take:
|
||||
|
||||
1. Change the rule's validation to allow for the new option.
|
||||
2. Add to the rule some logic (as little as possible) to make the option work.
|
||||
3. Add new unit tests to test the option.
|
||||
4. Add documentation about the new option.
|
||||
|
||||
## Fixing a bug in an existing rule
|
||||
|
||||
Fixing bugs is usually very easy. Here is a process that works:
|
||||
|
||||
1. Write failing unit tests that exemplify the bug.
|
||||
2. Fiddle with the rule until those new tests pass.
|
||||
|
||||
That's it! **If you are unable to figure out how to fix the bug yourself, it is still *extremely* helpful to submit a pull request with your failing test cases.** It means that somebody else can jump right in and help out with the rule's logic.
|
||||
|
||||
## Improving the performance of a new or an existing rule
|
||||
|
||||
There's a simple way to run benchmarks on any given rule with any valid config for it:
|
||||
|
||||
```shell
|
||||
npm run benchmark-rule -- [rule-name] [config]
|
||||
```
|
||||
|
||||
If the `config` argument is anything other than a string or a boolean, it must be valid JSON wrapped in quotation marks.
|
||||
|
||||
```shell
|
||||
npm run benchmark-rule -- selector-combinator-space-after never
|
||||
```
|
||||
|
||||
```shell
|
||||
npm run benchmark-rule -- selector-combinator-space-after always
|
||||
```
|
||||
|
||||
```shell
|
||||
npm run benchmark-rule -- selector-no-combinator true
|
||||
```
|
||||
|
||||
```shell
|
||||
npm run benchmark-rule -- block-opening-brace-space-before "[\"always\", {\"ignoreAtRules\": [\"else\"]}]"
|
||||
```
|
||||
|
||||
The script loads Bootstrap's CSS (from its CDN) and runs it through the configured rule.
|
||||
|
||||
It will end up printing some simple stats like this:
|
||||
|
||||
```shell
|
||||
Warnings: 1441
|
||||
Mean: 74.17598357142856 ms
|
||||
Deviation: 16.63969674310928 ms
|
||||
```
|
||||
|
||||
What can you do with this? **When writing new rules or refactoring existing rules, use these measurements to determine the efficiency of your code.**
|
||||
|
||||
A stylelint rule can repeat it's core logic many, many times (e.g. checking every value node of every declaration in a vast CSS codebase). So it's worth paying attention to performance and doing what we can to improve it!
|
||||
|
||||
**This is a great way to contribute if you just want a quick little project.** Try picking a rule and seeing if there's anything you can do to speed it up.
|
||||
|
||||
Make sure to include benchmark measurements in your PR's!
|
Reference in New Issue
Block a user