From d8c7d27872ffef18d8372620bd2292014f1c4981 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Sun, 27 Nov 2022 00:53:19 +0000 Subject: [PATCH] feat: add new prefer-nothing rule (#140) add new prefer-nothing rule --- README.md | 1 + docs/rules/prefer-nothing.md | 43 +++++++++++++++++++ src/rules/prefer-nothing.ts | 52 +++++++++++++++++++++++ src/test/rules/prefer-nothing_test.ts | 59 +++++++++++++++++++++++++++ 4 files changed, 155 insertions(+) create mode 100644 docs/rules/prefer-nothing.md create mode 100644 src/rules/prefer-nothing.ts create mode 100644 src/test/rules/prefer-nothing_test.ts diff --git a/README.md b/README.md index e126971..948810c 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ If you want more fine-grained configuration, you can instead add a snippet like - [lit/no-template-map](docs/rules/no-template-map.md) - [lit/no-useless-template-literals](docs/rules/no-useless-template-literals.md) - [lit/no-value-attribute](docs/rules/no-value-attribute.md) +- [lit/prefer-nothing](docs/rules/prefer-nothing.md) - [lit/quoted-expressions](docs/rules/quoted-expressions.md) diff --git a/docs/rules/prefer-nothing.md b/docs/rules/prefer-nothing.md new file mode 100644 index 0000000..2f301fe --- /dev/null +++ b/docs/rules/prefer-nothing.md @@ -0,0 +1,43 @@ +# Enforces use of `nothing` constant over empty templates (prefer-nothing) + +`nothing` is a constant provided by lit which may be used to render +nothing. This is far more efficient than creating an empty template. + +This means you can do something like: + +```ts +_render() { + if (!condition) { + return nothing; + } + + return html`Hello there`; +} +``` + +## Rule Details + +This rule enforces the use of `nothing` rather than empty templates. + +The following patterns are considered warnings: + +```ts +html``; +const tpl = html``; + +function render() { + return html``; +} +``` + +The following patterns are not warnings: + +```ts +html`foo`; +html` `; // whitespace +``` + +## When Not To Use It + +If you prefer using empty templates or don't yet have lit 2.x (which provides +the `nothing` constant), you should not use this rule. diff --git a/src/rules/prefer-nothing.ts b/src/rules/prefer-nothing.ts new file mode 100644 index 0000000..01f5358 --- /dev/null +++ b/src/rules/prefer-nothing.ts @@ -0,0 +1,52 @@ +/** + * @fileoverview Enforces use of `nothing` constant over empty templates + * @author James Garbutt + */ + +import {Rule} from 'eslint'; +import * as ESTree from 'estree'; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +const rule: Rule.RuleModule = { + meta: { + docs: { + description: 'Enforces use of `nothing` constant over empty templates', + category: 'Best Practices', + url: 'https://github.com/43081j/eslint-plugin-lit/blob/master/docs/rules/prefer-nothing.md' + }, + schema: [], + messages: { + preferNothing: + '`nothing` is preferred over empty templates when you want to render' + + ' nothing' + } + }, + + create(context): Rule.RuleListener { + return { + TaggedTemplateExpression: (node: ESTree.Node): void => { + if ( + node.type === 'TaggedTemplateExpression' && + node.tag.type === 'Identifier' && + node.tag.name === 'html' + ) { + if ( + node.quasi.expressions.length === 0 && + node.quasi.quasis.length === 1 && + node.quasi.quasis[0].value.raw === '' + ) { + context.report({ + node, + messageId: 'preferNothing' + }); + } + } + } + }; + } +}; + +export = rule; diff --git a/src/test/rules/prefer-nothing_test.ts b/src/test/rules/prefer-nothing_test.ts new file mode 100644 index 0000000..a482aad --- /dev/null +++ b/src/test/rules/prefer-nothing_test.ts @@ -0,0 +1,59 @@ +/** + * @fileoverview Enforces use of `nothing` constant over empty templates + * @author James Garbutt + */ + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +import rule = require('../../rules/prefer-nothing'); +import {RuleTester} from 'eslint'; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ + parserOptions: { + sourceType: 'module', + ecmaVersion: 2015 + } +}); + +ruleTester.run('prefer-nothing', rule, { + valid: ['html`foo`', 'css``', 'nonsense``', 'html`${x}`', 'html` `'], + + invalid: [ + { + code: 'html``', + errors: [ + { + messageId: 'preferNothing', + line: 1, + column: 1 + } + ] + }, + { + code: 'const x = html``;', + errors: [ + { + messageId: 'preferNothing', + line: 1, + column: 11 + } + ] + }, + { + code: 'function render() { return html``; }', + errors: [ + { + messageId: 'preferNothing', + line: 1, + column: 28 + } + ] + } + ] +});