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

Provide a list of lint rules in the "deno lint" reference #1249

Merged
merged 11 commits into from
Dec 16, 2024
13 changes: 13 additions & 0 deletions _includes/lint_rule.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const layout = "doc.tsx";

export default function LintRule(props: Lume.Data, helpers: Lume.Helpers) {
// Strip /lint/rules/ and trailing slash
const lintRuleName = props.url.substring(12).slice(0, -1);

return (
<>
<h1>{lintRuleName}</h1>
{props.children}
</>
);
}
1 change: 1 addition & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions lint/_data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Sidebar, SidebarLink } from "../types.ts";
import { walk } from "jsr:@std/fs";
import { basename } from "jsr:@std/path";
import { extractYaml } from "jsr:@std/[email protected]";

async function generateSidebarItems() {
const sidebarItems = [];

for await (
const dirEntry of walk(
new URL(import.meta.resolve("./rules/")),
{ exts: ["md"] },
)
) {
const lintRuleName = basename(dirEntry.path).split(".")[0];
const mdContent = await Deno.readTextFile(dirEntry.path);
let frontMatterData = { body: "", attrs: {} };
try {
frontMatterData = extractYaml(mdContent);
} catch {
frontMatterData.body = mdContent;
}
const tags = frontMatterData.attrs.tags ?? [];
// TODO(bartlomieju): handle descriptions properly
// const description = frontMatterData.body.split(".")[0];

sidebarItems.push(
{
href: `/lint/rules/${lintRuleName}`,
label: lintRuleName,
tags,
// description,
} satisfies SidebarLink,
);
}

sidebarItems.sort((a, b) => a.label.localeCompare(b.label));

return sidebarItems;
}

export const lintRulePages = await generateSidebarItems();

export const sidebar = [
{
title: "Lint rules",
items: lintRulePages,
},
] satisfies Sidebar;

export const sectionTitle = "Lint rules";
19 changes: 19 additions & 0 deletions lint/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
title: Lint rules
templateEngine: [vto, md]
---

<div>

{{ for lintRule of lintRulePages }}

<div>
<a href="{{ lintRule.href }}">{{ lintRule.label }}</a>
{{ for tag of lintRule.tags }}
<span class="lint-tag-{{ tag }}">{{ tag }}</span>
{{/for }}
</div>

{{ /for }}

</div>
1 change: 1 addition & 0 deletions lint/rules/_data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const layout = "lint_rule.tsx";
84 changes: 84 additions & 0 deletions lint/rules/adjacent-overload-signatures.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
tags: [recommended]
---

Requires overload signatures to be adjacent to each other.

Overloaded signatures which are not next to each other can lead to code which is
hard to read and maintain.

**Invalid:**

(`bar` is declared in-between `foo` overloads)

```typescript
type FooType = {
foo(s: string): void;
foo(n: number): void;
bar(): void;
foo(sn: string | number): void;
};
```

```typescript
interface FooInterface {
foo(s: string): void;
foo(n: number): void;
bar(): void;
foo(sn: string | number): void;
}
```

```typescript
class FooClass {
foo(s: string): void;
foo(n: number): void;
bar(): void {}
foo(sn: string | number): void {}
}
```

```typescript
export function foo(s: string): void;
export function foo(n: number): void;
export function bar(): void {}
export function foo(sn: string | number): void {}
```

**Valid:**

(`bar` is declared after `foo`)

```typescript
type FooType = {
foo(s: string): void;
foo(n: number): void;
foo(sn: string | number): void;
bar(): void;
};
```

```typescript
interface FooInterface {
foo(s: string): void;
foo(n: number): void;
foo(sn: string | number): void;
bar(): void;
}
```

```typescript
class FooClass {
foo(s: string): void;
foo(n: number): void;
foo(sn: string | number): void {}
bar(): void {}
}
```

```typescript
export function foo(s: string): void;
export function foo(n: number): void;
export function foo(sn: string | number): void {}
export function bar(): void {}
```
43 changes: 43 additions & 0 deletions lint/rules/ban-ts-comment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
tags: [recommended]
---

Disallows the use of Typescript directives without a comment.

Typescript directives reduce the effectiveness of the compiler, something which
should only be done in exceptional circumstances. The reason why should be
documented in a comment alongside the directive.

**Invalid:**

```typescript
// @ts-expect-error
let a: number = "I am a string";
```

```typescript
// @ts-ignore
let a: number = "I am a string";
```

```typescript
// @ts-nocheck
let a: number = "I am a string";
```

**Valid:**

```typescript
// @ts-expect-error: Temporary workaround (see ticket #422)
let a: number = "I am a string";
```

```typescript
// @ts-ignore: Temporary workaround (see ticket #422)
let a: number = "I am a string";
```

```typescript
// @ts-nocheck: Temporary workaround (see ticket #422)
let a: number = "I am a string";
```
46 changes: 46 additions & 0 deletions lint/rules/ban-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
tags: [recommended]
---

Bans the use of primitive wrapper objects (e.g. `String` the object is a wrapper
of `string` the primitive) in addition to the non-explicit `Function` type and
the misunderstood `Object` type.

There are very few situations where primitive wrapper objects are desired and
far more often a mistake was made with the case of the primitive type. You also
cannot assign a primitive wrapper object to a primitive leading to type issues
down the line. For reference, [the TypeScript handbook] also says we shouldn't
ever use these wrapper objects.

[the TypeScript handbook]: https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#number-string-boolean-symbol-and-object

With `Function`, it is better to explicitly define the entire function signature
rather than use the non-specific `Function` type which won't give you type
safety with the function.

Finally, `Object` and `{}` means "any non-nullish value" rather than "any object
type". `object` is a good choice for a meaning of "any object type".

**Invalid:**

```typescript
let a: Boolean;
let b: String;
let c: Number;
let d: Symbol;
let e: Function;
let f: Object;
let g: {};
```

**Valid:**

```typescript
let a: boolean;
let b: string;
let c: number;
let d: symbol;
let e: () => number;
let f: object;
let g: Record<string, never>;
```
39 changes: 39 additions & 0 deletions lint/rules/ban-unknown-rule-code.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
tags: [recommended]
---

Warns the usage of unknown rule codes in ignore directives

We sometimes have to suppress and ignore lint errors for some reasons. We can do
so using [ignore directives](https://lint.deno.land/ignoring-rules) with rule
names that should be ignored like so:

```typescript
// deno-lint-ignore no-explicit-any no-unused-vars
const foo: any = 42;
```

This rule checks for the validity of the specified rule names (i.e. whether
`deno_lint` provides the rule or not).

**Invalid:**

```typescript
// typo
// deno-lint-ignore eq-eq-e
console.assert(x == 42);

// unknown rule name
// deno-lint-ignore UNKNOWN_RULE_NAME
const b = "b";
```

**Valid:**

```typescript
// deno-lint-ignore eq-eq-eq
console.assert(x == 42);

// deno-lint-ignore no-unused-vars
const b = "b";
```
22 changes: 22 additions & 0 deletions lint/rules/ban-untagged-ignore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
tags: [recommended]
---

Requires `deno-lint-ignore` to be annotated with one or more rule names.

Ignoring all rules can mask unexpected or future problems. Therefore you need to
explicitly specify which rule(s) are to be ignored.

**Invalid:**

```typescript
// deno-lint-ignore
export function duplicateArgumentsFn(a, b, a) {}
```

**Valid:**

```typescript
// deno-lint-ignore no-dupe-args
export function duplicateArgumentsFn(a, b, a) {}
```
48 changes: 48 additions & 0 deletions lint/rules/ban-untagged-todo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
tags: []
---

Requires TODOs to be annotated with either a user tag (`@user`) or an issue
reference (`#issue`).

TODOs without reference to a user or an issue become stale with no easy way to
get more information.

**Invalid:**

```typescript
// TODO Improve calc engine
export function calcValue(): number {}
```

```typescript
// TODO Improve calc engine (@djones)
export function calcValue(): number {}
```

```typescript
// TODO Improve calc engine (#332)
export function calcValue(): number {}
```

**Valid:**

```typescript
// TODO(djones) Improve calc engine
export function calcValue(): number {}
```

```typescript
// TODO(@djones) Improve calc engine
export function calcValue(): number {}
```

```typescript
// TODO(#332)
export function calcValue(): number {}
```

```typescript
// TODO(#332) Improve calc engine
export function calcValue(): number {}
```
Loading
Loading