From a1273ca2d0b881ae318b6ffed03d59df91857ba1 Mon Sep 17 00:00:00 2001 From: JD Huntington Date: Thu, 1 Oct 2020 13:13:19 -0700 Subject: [PATCH] More docs and configuration examples --- packages/docs/src/.vuepress/config.js | 2 +- packages/docs/src/docs/configuration.md | 44 +++++++- packages/docs/src/docs/custom-rule.md | 142 ++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 packages/docs/src/docs/custom-rule.md diff --git a/packages/docs/src/.vuepress/config.js b/packages/docs/src/.vuepress/config.js index d5d02c62..8863fb8d 100755 --- a/packages/docs/src/.vuepress/config.js +++ b/packages/docs/src/.vuepress/config.js @@ -42,7 +42,7 @@ module.exports = { editLinkText: "", lastUpdated: false, displayAllHeaders: true, - sidebar: { "/docs/": ["", "configuration", "runner", "disabling", "rules"], "/api/": apiFiles, "/": "auto" }, + sidebar: { "/docs/": ["", "configuration", "runner", "disabling", "rules", "custom-rule"], "/api/": apiFiles, "/": "auto" }, nav: [ { text: "Get started", diff --git a/packages/docs/src/docs/configuration.md b/packages/docs/src/docs/configuration.md index 8936b91e..2cc18524 100644 --- a/packages/docs/src/docs/configuration.md +++ b/packages/docs/src/docs/configuration.md @@ -1,3 +1,45 @@ # Configuration -See [configuration type](../api/interfaces/configdefinition) +Boll is configured by way of the `.boll.config.js` file in the root of a given package. + +Each boll configuration must load rules to be run across the repository. It may either +extend an existing configuration or fabricate a new configuration. + +## Extending an existing configuration + +To extend an configuration, first make sure rules are loaded, then export an object with +an `extends` key. + +```js +"use strict"; +const { bootstrapRecommendedConfiguration } = require('@boll/recommended'); +bootstrapRecommendedConfiguration(); +module.exports = { + extends: "boll:recommended" +}; +``` + +## Creating a new configuration + +A configuration is a list of `RuleSet` objects. Each `RuleSet` must define a `fileLocator` +and a set of checks to run against all matched files. + +The following example loads a specific TypeScript check from the TypeScript package, registers it, then creates a +ruleset to run that check only. + +```js +"use strict"; +const { RuleRegistryInstance, TypescriptSourceGlob } = require("@boll/core"); +const { SrcDetector } = require("@boll/rules-typescript"); + +RuleRegistryInstance.register("SrcDetector", () => new SrcDetector()); + +module.exports = { + ruleSets: [{ + fileLocator: new TypescriptSourceGlob(), + checks: [{rule: "SrcDetector"}] + }] +}; +``` + +`@boll/core` provides several `fileLocator` implementations (see [FileGlob](../api/core/interfaces/fileglob)) out of the box. \ No newline at end of file diff --git a/packages/docs/src/docs/custom-rule.md b/packages/docs/src/docs/custom-rule.md new file mode 100644 index 00000000..615c898d --- /dev/null +++ b/packages/docs/src/docs/custom-rule.md @@ -0,0 +1,142 @@ +# Advanced configuration: Custom rules + +In this walkthrough, we will create a new file locator and rule from scratch. + +Our task will be to verify that prettier is configured to enforce single quotes (the `singleQuote` directive in prettier's configuration). + +## File locator + +The locator must implement the [`FileGlob`](../api/core/interfaces/fileglob) interface. In short, it must +expose properties `include` and `exclude` (both string arrays) that can be set at runtime based on user configuration. +It must also expose `findFiles()`, which returns a promise that resolves to a list of filenames. + +Since we know the name of the file we want to find and the expected location (`.prettierrc` in the root of the pacakge), +there's no need to search for any files. We can simply return a resolved promise. + +```js +"use strict"; + +const prettierRcLocator = { + findFiles: () => { + return new Promise((resolve) => { + resolve(['.prettierrc']); + }); + } +} + +module.exports = { + ruleSets: [{ + fileLocator: prettierRcLocator, + checks: [] + }] +}; +``` + +## Check for singleQuote + +Next we will verify that the prettier configuration meets expectations. + +### Create the rule + +Our rule must expose a `name` attribute and a `check` method. + +The name is used when printing errors, so should be a unique and descriptive label that will be useful in CI output. + +The check method will be passed 1 [`FileContext`](../api/core/classes/filecontext) object at a time, and must return a promise that resolves to a list of `Result` objects ([`Success`](../api/core/classes/success) and [`Failure`](../api/core/classes/failure) being the most common). + +```js +const { Success, Failure } = require('@boll/core'); + +const prettierRcSingleQuoteChecker = { + name: "PrettierRcSingleQuoteChecker", + check: (file) => { + return new Promise((resolve) => { + const contents = JSON.parse(file.content); + if(contents.singleQuote) { + resolve([new Success()]); + } + else { + resolve([new Failure("PrettierRcSingleQuoteChecker", file.filename, 0, "Expected singleQuote to be true, but wasn't!")]); + } + }); + } +} +``` + +### Register the rule + +The rule must be registered with boll so that it can be invoked during the run. + +```js +const { RuleRegistryInstance } = require("@boll/core"); +RuleRegistryInstance.register("PrettierRcSingleQuoteChecker", () => prettierRcSingleQuoteChecker); +``` + +### Putting it altogether + +With the locator and check in place, we just need to mention the rule inside the `checks` block of the exported config. The entire `.boll.config.js` looks this way after adding this last bit of config. + +```js +"use strict"; + +const { RuleRegistryInstance, Success, Failure } = require('@boll/core'); + +const prettierRcSingleQuoteChecker = { + name: "PrettierRcSingleQuoteChecker", + check: (file) => { + return new Promise((resolve) => { + const contents = JSON.parse(file.content); + if(contents.singleQuote) { + resolve([new Success()]); + } + else { + resolve([new Failure("PrettierRcSingleQuoteChecker", file.filename, 0, "Expected singleQuote to be true, but wasn't!")]); + } + }); + } +}; + +const prettierRcLocator = { + findFiles: () => { + return new Promise((resolve) => { + resolve(['.prettierrc']); + }); + } +} + +RuleRegistryInstance.register("PrettierRcSingleQuoteChecker", () => prettierRcSingleQuoteChecker); + +module.exports = { + ruleSets: [{ + fileLocator: prettierRcLocator, + checks: [{rule: "PrettierRcSingleQuoteChecker"}] + }] +}; +``` + +Now, running with an incorrect `.prettierrc`: + +```json +{ + "singleQuote": false +} +``` + +```sh +[/tmp/sample-project]# ./node_modules/.bin/boll run +[PrettierRcSingleQuoteChecker] /private/tmp/sample-project/.prettierrc:0 Expected singleQuote to be true, but wasn't! +@boll/cli detected lint errors +``` + +However, after fixing: +```json +{ + "singleQuote": true +} +``` + +```sh +[/tmp/sample-project]# ./node_modules/.bin/boll run +[/tmp/sample-project]# echo $? +0 +``` \ No newline at end of file