UNPKG

21.6 kBMarkdownView Raw
1<h1 align="center">ts-lit-plugin</h1>
2<p align="center">
3 <b>Typescript plugin that adds type checking and code completion to lit-html</b></br>
4 <sub><sub>
5</p>
6
7<br />
8
9<p align="center">
10 <a href="https://npmcharts.com/compare/ts-lit-plugin?minimal=true"><img alt="Downloads per month" src="https://img.shields.io/npm/dm/ts-lit-plugin.svg" height="20"/></a>
11<a href="https://www.npmjs.com/package/ts-lit-plugin"><img alt="NPM Version" src="https://img.shields.io/npm/v/ts-lit-plugin.svg" height="20"/></a>
12<a href="https://david-dm.org/runem/lit-analyzer"><img alt="Dependencies" src="https://img.shields.io/david/runem/lit-analyzer.svg" height="20"/></a>
13<a href="https://github.com/runem/lit-analyzer/graphs/contributors"><img alt="Contributors" src="https://img.shields.io/github/contributors/runem/lit-analyzer.svg" height="20"/></a>
14 </p>
15
16
17<p align="center">
18 <img src="https://user-images.githubusercontent.com/5372940/62078476-02c1ec00-b24d-11e9-8de5-1322012cbde2.gif" alt="Lit plugin GIF"/>
19</p>
20
21
22[![-----------------------------------------------------](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png)](#installation)
23
24## ➤ Installation
25
26First, install the plugin:
27
28```bash
29npm install ts-lit-plugin -D
30```
31
32
33Then add a `plugins` section to your [`tsconfig.json`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html):
34
35```json
36{
37 "compilerOptions": {
38 "plugins": [
39 {
40 "name": "ts-lit-plugin"
41 }
42 ]
43 }
44}
45```
46
47Finally, restart you Typescript Language Service, and you should start getting diagnostics from `ts-lit-plugin`.
48
49**Note:**
50* If you use Visual Studio Code you can also install the [lit-plugin](https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin) extension.
51* If you would rather use a CLI, you can install the [lit-analyzer](https://github.com/runem/lit-analyzer/blob/master/packages/lit-analyzer).
52
53[![-----------------------------------------------------](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png)](#configuration)
54
55## ➤ Configuration
56
57You can configure this plugin through your `tsconfig.json`.
58
59### Example
60
61```json
62{
63 "compilerOptions": {
64 "plugins": [
65 {
66 "name": "ts-lit-plugin",
67 "strict": true,
68 "rules": {
69 "no-unknown-tag-name": "off",
70 "no-unknown-event": "warn"
71 }
72 }
73 ]
74 }
75}
76```
77
78### Available options
79
80<!-- prettier-ignore -->
81| Option | Description | Type | Default |
82| :----- | ----------- | ---- | ------- |
83| `strict` | Enabling strict mode will change which rules are applied as default (see list of [rules](https://github.com/runem/lit-analyzer/blob/master/docs/readme/rules.md)) | `boolean` | false |
84| `rules` | Enable/disable individual rules or set their severity. Example: `{"no-unknown-tag-name": "off"}` | `{"rule-name": "off" \| "warn" \| "error"}` | The default rules enabled depend on the `strict` option |
85| `disable` | Completely disable this plugin. | `boolean` | false |
86| `dontShowSuggestions` | This option sets strict as | `boolean` | false |
87| `htmlTemplateTags` | List of template tags to enable html support in. | `string[]` | ["html", "raw"] | |
88| `cssTemplateTags` | This option sets strict as | `string[]` | ["css"] |
89| `globalTags` | List of html tag names that you expect to be present at all times. | `string[]` | |
90| `globalAttributes` | List of html attributes names that you expect to be present at all times. | `string[]` | |
91| `globalEvents` | List of event names that you expect to be present at all times | `string[]` | |
92| `customHtmlData` | This plugin supports the [custom vscode html data format](https://code.visualstudio.com/updates/v1_31#_html-and-css-custom-data-support) through this setting. | [Vscode Custom HTML Data Format](https://github.com/Microsoft/vscode-html-languageservice/blob/master/docs/customData.md). Supports arrays, objects and relative file paths | |
93
94
95[![-----------------------------------------------------](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png)](#rules)
96
97## ➤ Rules
98
99The default severity of each rule depend on the `strict` [configuration option](#-configuration). Strict mode is disabled as default.
100
101Each rule can have severity of `off`, `warning` or `error`. You can toggle rules as you like.
102
103**Validating custom elements**
104
105<!-- prettier-ignore -->
106| Rule | Description | Severity normal | Severity strict |
107| :------ | ----------- | --------------- | --------------- |
108| [no-unknown-tag-name](#-no-unknown-tag-name) | The existence of tag names are checked. Be aware that not all custom elements from libraries will be found out of the box. | off | warning |
109| [no-missing-import](#-no-missing-import) | When using custom elements in HTML it is checked if the element has been imported and is available in the current context. | off | warning |
110| [no-unclosed-tag](#-no-unclosed-tag) | Unclosed tags, and invalid self closing tags like custom elements tags, are checked. | warning | error |
111
112
113**Validating binding names**
114
115<!-- prettier-ignore -->
116| Rule | Description | Severity normal | Severity strict |
117| :------ | ----------- | --------------- | --------------- |
118| [no-unknown-attribute](#-no-unknown-attribute-no-unknown-property)<br> [no-unknown-property](#-no-unknown-attribute-no-unknown-property) | You will get a warning whenever you use an unknown attribute or property within your `lit-html` template. | off | warning |
119| [no-unknown-event](#-no-unknown-event) | When using event bindings it's checked that the event names are fired. | off | off |
120| [no-unknown-slot](#-no-unknown-slot) | Using the "@slot" jsdoc tag on your custom element class, you can tell which slots are accepted for a particular element. | off | warning |
121
122
123**Validating binding types**
124
125<!-- prettier-ignore -->
126| Rule | Description | Severity normal | Severity strict |
127| :------ | ----------- | --------------- | --------------- |
128| [no-invalid-boolean-binding](#-no-invalid-boolean-binding) | Disallow boolean attribute bindings on non-boolean types. | error | error |
129| [no-expressionless-property-binding](#-no-expressionless-property-binding) | Disallow property bindings without an expression. | error | error |
130| [no-noncallable-event-binding](#-no-noncallable-event-binding) | Disallow event listener bindings with a noncallable type. | error | error |
131| [no-boolean-in-attribute-binding](#-no-boolean-in-attribute-binding) | Disallow attribute bindings with a boolean type. | error | error |
132| [no-complex-attribute-binding](#-no-complex-attribute-binding) | Disallow attribute bindings with a complex type. | error | error |
133| [no-nullable-attribute-binding](#-no-nullable-attribute-binding) | Disallow attribute bindings with nullable types such as "null" or "undefined". | error | error |
134| [no-incompatible-type-binding](#-no-incompatible-type-binding) | Disallow incompatible type in bindings. | error | error |
135| [no-invalid-directive-binding](#-no-invalid-directive-binding) | Disallow using built-in directives in unsupported bindings. | error | error |
136
137**Validating LitElement**
138
139<!-- prettier-ignore -->
140| Rule | Description | Severity normal | Severity strict |
141| :------ | ----------- | --------------- | --------------- |
142| [no-incompatible-property-type](#-no-incompatible-property-type) | When using the @property decorator in Typescript, the property option `type` is checked against the declared property Typescript type | error | error |
143| [no-unknown-property-converter](#-no-unknown-property-converter) | LitElement provides default converters. For example 'Function' is not a valid default converter type for a LitElement-managed property. | error | error |
144| [no-invalid-attribute-name](#-no-invalid-attribute-name) | When using the property option `attribute`, the value is checked to make sure it's a valid attribute name. | error | error |
145| [no-invalid-tag-name](#-no-invalid-tag-name) | When defining a custom element the tag name is checked to make sure it's valid. | error | error |
146
147**Validating CSS**
148
149<!-- prettier-ignore -->
150| Rule | Description | Severity normal | Severity strict |
151| :------ | ----------- | --------------- | --------------- |
152| [💅 no-invalid-css](#-no-invalid-css) | CSS within the tagged template literal `css` will be validated. | warning | error |
153
154
155### Validating custom elements
156
157All web components in your code are analyzed using [web-component-analyzer](https://github.com/runem/web-component-analyzer) which supports native custom elements and web components built with LitElement.
158
159#### 🤷‍ no-unknown-tag-name
160
161Web components defined in libraries need to either extend the global `HTMLElementTagNameMap` (typescript definition file) or include the "@customElement tag-name" jsdoc on the custom element class.
162
163Below you will see an example of what to add to your library typescript definition files if you want type checking support for a given html tag name.
164
165```typescript
166declare global {
167 interface HTMLElementTagNameMap {
168 "my-element": MyElement;
169 }
170}
171```
172
173#### 📣 no-missing-import
174
175When using custom elements in HTML it is checked if the element has been imported and is available in the current context. It's considered imported if any imported module (or their imports) defines the custom element.
176
177The following example is considered a warning:
178```js
179// No import of "my-element"
180html`<my-element></my-element>`
181```
182
183The following example is not considered a warning:
184```js
185import "my-element.js";
186html`<my-element></my-element>`
187```
188
189
190#### ☯ no-unclosed-tag
191
192Unclosed tags, and invalid self closing tags like custom elements tags, are checked.
193
194The following examples are considered warnings:
195```js
196html`<div>`
197html`<video />`
198html`<custom-element />`
199```
200
201The following examples are not considered warnings:
202```js
203html`<div></div>`
204html`<custom-element></custom-element>`
205html`<video></video>`
206html`<input />`
207```
208
209### Validating binding names
210
211Attributes, properties and events are picked up on custom elements using [web-component-analyzer](https://github.com/runem/web-component-analyzer) which supports native custom elements and web components built with LitElement.
212
213#### ✅ no-unknown-attribute, no-unknown-property
214
215You will get a warning whenever you use an unknown attribute or property. This check is made on both custom elements and built in elements.
216
217**The following example is considered a warning:**
218```js
219html`<input .valuuue="${value}" unknownattribute="button" />`
220```
221
222**The following example is not considered a warning:**
223```js
224html`<input .value="${value}" type="button" />`
225```
226
227#### ⚡️ no-unknown-event
228
229You can opt in to check for unknown event names. Using the `@fires` jsdoc or the statement `this.dispatch(new CustomElement("my-event))` will make the event name available. All event names are accepted globally because events bubble.
230
231The following example is considered a warning:
232```js
233html`<input @iinput="${console.log}" />`
234```
235
236The following example is not considered a warning:
237```js
238html`<input @input="${console.log}" />`
239```
240
241#### 📬 no-unknown-slot
242
243Using the "@slot" jsdoc tag on your custom element class, you can tell which slots are accepted for a particular element. Then you will get warnings for invalid slot names and if you forget to add the slot attribute on elements without an unnamed slot.
244
245```js
246/**
247 * @slot - This is a comment for the unnamed slot
248 * @slot right - Right content
249 * @slot left
250 */
251class MyElement extends HTMLElement {
252}
253customElements.define("my-element", MyElement);
254```
255
256The following example is considered a warning:
257```js
258html`
259<my-element>
260 <div slot="not a slot name"></div>
261</my-element>
262`
263```
264
265The following example is not considered a warning:
266```js
267html`
268<my-element>
269 <div></div>
270 <div slot="right"></div>
271 <div slot="left"></div>
272</my-element>
273`
274```
275
276
277### Validating binding types
278
279Be aware that many checks involving analyzing bindings will work better in Typescript files because we have more information about the values being bound.
280
281#### ❓ no-invalid-boolean-binding
282
283It never makes sense to use the boolean attribute binding on a non-boolean type.
284
285The following example is considered a warning:
286```js
287html`<input ?type="${"button"}" />`
288```
289
290The following example is not considered a warning:
291```js
292html`<input ?disabled="${isDisabled}" />`
293```
294
295#### ⚫️ no-expressionless-property-binding
296
297Because of how `lit-html` [parses bindings internally](https://github.com/Polymer/lit-html/issues/843) you cannot use the property binding without an expression.
298
299The following example is considered a warning:
300```js
301html`<input .value="text" />`
302```
303
304The following example is not considered a warning:
305```js
306html`<input .value="${text}" />`
307```
308
309#### 🌀 no-noncallable-event-binding
310
311It's a common mistake to incorrectly call the function when setting up an event handler binding instead of passing a reference to the function. This makes the function call whenever the code evaluates.
312
313The following examples are considered warnings:
314```js
315html`<button @click="${myEventHandler()}">Click</button>`
316html`<button @click="${{hannndleEvent: console.log()}}">Click</button>`
317```
318
319The following examples are not considered warnings:
320```js
321html`<button @click="${myEventHandler}">Click</button>`
322html`<button @click="${{handleEvent: console.log}}">Click</button>`
323```
324
325#### 😈 no-boolean-in-attribute-binding
326
327You should not be binding to a boolean type using an attribute binding because it could result in binding the string "true" or "false". Instead you should be using a **boolean** attribute binding.
328
329This error is particular tricky, because the string "false" is truthy when evaluated in a conditional.
330
331The following example is considered a warning:
332```js
333html`<input disabled="${isDisabled}" />`
334```
335
336The following example is not considered a warning:
337```js
338html`<input ?disabled="${isDisabled}" />`
339```
340
341#### ☢️ no-complex-attribute-binding
342
343Binding an object using an attribute binding would result in binding the string "[object Object]" to the attribute. In this cases it's probably better to use a property binding instead.
344
345The following example is considered a warning:
346```js
347html`<my-list listitems="${listItems}"></my-list>`
348```
349
350The following example is not considered a warning:
351```js
352html`<my-list .listItems="${listItems}"></my-list>`
353```
354
355
356#### ⭕️ no-nullable-attribute-binding
357
358Binding `undefined` or `null` in an attribute binding will result in binding the string "undefined" or "null". Here you should probably wrap your expression in the "ifDefined" directive.
359
360The following examples are considered warnings:
361```js
362html`<input value="${maybeUndefined}" />`
363html`<input value="${maybeNull}" />`
364```
365
366The following examples are not considered warnings:
367```js
368html`<input value="${ifDefined(maybeUndefined)}" />`
369html`<input value="${ifDefined(maybeNull === null ? undefined : maybeNull)}" />`
370```
371
372#### 💔 no-incompatible-type-binding
373
374Assignments in your HTML are typed checked just like it would be in Typescript.
375
376The following examples are considered warnings:
377```js
378html`<input type="wrongvalue" />`
379html`<input placeholder />`
380html`<input max="${"hello"}" />`
381html`<my-list .listItems="${123}"></my-list>`
382```
383
384The following examples are not considered warnings:
385```js
386html`<input type="button" />`
387html`<input placeholder="a placeholder" />`
388html`<input max="${123}" />`
389html`<my-list .listItems="${listItems}"></my-list>`
390```
391
392#### 💥 no-invalid-directive-binding
393
394Directives are checked to make sure that the following rules are met:
395* `ifDefined` is only used in an attribute binding.
396* `class` is only used in an attribute binding on the 'class' attribute.
397* `style` is only used in an attribute binding on the 'style' attribute.
398* `unsafeHTML`, `cache`, `repeat`, `asyncReplace` and `asyncAppend` are only used within a text binding.
399
400The directives already make these checks on runtime, so this will help you catch errors before runtime.
401
402The following examples are considered warnings:
403```js
404html`<button value="${unsafeHTML(html)}"></button>`
405html`<input .value="${ifDefined(myValue)}" />`
406html`<div role="${class(classMap)}"></div>`
407```
408
409The following examples are not considered warnings:
410```js
411html`<button>${unsafeHTML(html)}</button>`
412html`<input .value="${myValue}" />`
413html`<input value="${myValue}" />`
414html`<div class="${class(classMap)}"></div>`
415```
416
417
418
419### Validating LitElement
420
421#### 💞 no-incompatible-property-type
422
423When using the @property decorator in Typescript, the property option `type` is checked against the declared property Typescript type.
424
425The following examples are considered warnings:
426```js
427class MyElement extends LitElement {
428 @property({type: Number}) text: string;
429 @property({type: Boolean}) count: number;
430 @property({type: String}) disabled: boolean;
431 @property({type: Object}) list: ListItem[];
432}
433```
434
435The following examples are not considered warnings:
436```js
437class MyElement extends LitElement {
438 @property({type: String}) text: string;
439 @property({type: Number}) count: number;
440 @property({type: Boolean}) disabled: boolean;
441 @property({type: Array}) list: ListItem[];
442}
443```
444
445#### 👎 no-unknown-property-converter
446
447The default converter in LitElement only accepts `String`, `Boolean`, `Number`, `Array` and `Object`, so all other values for `type` are considered warnings. This check doesn't run if a custom converter is used.
448
449The following example is considered a warning:
450```js
451class MyElement extends LitElement {
452 static get properties () {
453 return {
454 callback: {
455 type: Function
456 },
457 text: {
458 type: MyElement
459 }
460 }
461 }
462}
463```
464
465The following example is not considered a warning:
466```js
467class MyElement extends LitElement {
468 static get properties () {
469 return {
470 callback: {
471 type: Function,
472 converter: myCustomConverter
473 },
474 text: {
475 type: String
476 }
477 }
478 }
479}
480```
481
482
483#### ⁉️ no-invalid-attribute-name
484
485When using the property option `attribute`, the value is checked to make sure it's a valid attribute name.
486
487The following example is considered a warning:
488```js
489class MyElement extends LitElement {
490 static get properties () {
491 return {
492 text: {
493 attribute: "invald=name"
494 }
495 }
496 }
497}
498```
499
500#### ⁉️ no-invalid-tag-name
501
502When defining a custom element, the tag name is checked to make sure it's a valid custom element name.
503
504The following example is considered a warning:
505```js
506@customElement("wrongElementName")
507class MyElement extends LitElement {
508}
509
510customElements.define("alsoWrongName", MyElement);
511```
512
513The following example is not considered a warning:
514```js
515@customElement("my-element")
516class MyElement extends LitElement {
517}
518
519customElements.define("correct-element-name", MyElement);
520```
521
522### Validating CSS
523
524`lit-analyzer` uses [vscode-css-languageservice](https://github.com/Microsoft/vscode-css-languageservice) to validate CSS.
525
526#### 💅 no-invalid-css
527
528CSS within the tagged template literal `css` will be validated.
529
530The following example is considered a warning:
531```js
532css`
533 button
534 background: red;
535 }
536`
537```
538
539The following example is not considered a warning:
540```js
541css`
542 button {
543 background: red;
544 }
545`
546```
547
548[![-----------------------------------------------------](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png)](#documenting-slots-events-attributes-and-properties)
549
550## ➤ Documenting slots, events, attributes and properties
551
552Code is analyzed using [web-component-analyzer](https://github.com/runem/web-component-analyzer) in order to find properties, attributes and events. Unfortunately, sometimes it's not possible to analyze these things by looking at the code, and you will have to document how your component looks using `jsdoc`like this:
553
554```js
555/**
556 * This is my element
557 * @attr size
558 * @attr {red|blue} color - The color of my element
559 * @prop {String} value
560 * @prop {Boolean} myProp - This is my property
561 * @fires change
562 * @fires my-event - This is my own event
563 * @slot - This is a comment for the unnamed slot
564 * @slot right - Right content
565 * @slot left
566 */
567class MyElement extends HTMLElement {
568}
569
570customElements.define("my-element", MyElement);
571```
572
573
574
575[![-----------------------------------------------------](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png)](#contributors)
576
577## ➤ Contributors
578
579
580| [<img alt="Rune Mehlsen" src="https://avatars2.githubusercontent.com/u/5372940?s=460&v=4" width="100">](https://twitter.com/runemehlsen) | [<img alt="Andreas Mehlsen" src="https://avatars1.githubusercontent.com/u/6267397?s=460&v=4" width="100">](https://twitter.com/andreasmehlsen) | [<img alt="You?" src="https://joeschmoe.io/api/v1/random" width="100">](https://github.com/runem/lit-analyzer/blob/master/CONTRIBUTING.md) |
581|:--------------------------------------------------:|:--------------------------------------------------:|:--------------------------------------------------:|
582| [Rune Mehlsen](https://twitter.com/runemehlsen) | [Andreas Mehlsen](https://twitter.com/andreasmehlsen) | [You?](https://github.com/runem/lit-analyzer/blob/master/CONTRIBUTING.md) |
583
584
585[![-----------------------------------------------------](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png)](#license)
586
587## ➤ License
588
589Licensed under [MIT](https://opensource.org/licenses/MIT).