Skip to content

Commit

Permalink
Add no-document-cookie rule (#1244)
Browse files Browse the repository at this point in the history
  • Loading branch information
fisker committed May 8, 2021
1 parent 6b340a3 commit 866c4a3
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 0 deletions.
39 changes: 39 additions & 0 deletions docs/rules/no-document-cookie.md
@@ -0,0 +1,39 @@
# Do not use `document.cookie` directly

It's not recommended to use [`document.cookie`](https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie) directly as it's easy to get the string wrong. Instead, you should use the [Cookie Store API](https://developer.mozilla.org/en-US/docs/Web/API/Cookie_Store_API) or a [cookie library](https://www.npmjs.com/search?q=cookie).

## Fail

```js
document.cookie =
'foo=bar' +
'; Path=/' +
'; Domain=example.com' +
'; expires=Fri, 31 Dec 9999 23:59:59 GMT' +
'; Secure';
```

```js
document.cookie += '; foo=bar';
```

## Pass

```js
await cookieStore.set({
name: 'foo',
value: 'bar',
expires: Date.now() + 24 * 60 * 60 * 1000,
domain: 'example.com'
});
```

```js
const array = document.cookie.split('; ');
```

```js
import Cookies from 'js-cookie';

Cookies.set('foo', 'bar');
```
1 change: 1 addition & 0 deletions index.js
Expand Up @@ -59,6 +59,7 @@ module.exports = {
'unicorn/no-array-push-push': 'error',
'unicorn/no-array-reduce': 'error',
'unicorn/no-console-spaces': 'error',
'unicorn/no-document-cookie': 'error',
'unicorn/no-for-loop': 'error',
'unicorn/no-hex-escape': 'error',
'unicorn/no-instanceof-array': 'error',
Expand Down
2 changes: 2 additions & 0 deletions readme.md
Expand Up @@ -55,6 +55,7 @@ Configure it in `package.json`.
"unicorn/no-array-push-push": "error",
"unicorn/no-array-reduce": "error",
"unicorn/no-console-spaces": "error",
"unicorn/no-document-cookie": "error",
"unicorn/no-for-loop": "error",
"unicorn/no-hex-escape": "error",
"unicorn/no-instanceof-array": "error",
Expand Down Expand Up @@ -150,6 +151,7 @@ Each rule has emojis denoting:
| [no-array-push-push](docs/rules/no-array-push-push.md) | Enforce combining multiple `Array#push()` into one call. || 🔧 |
| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. || |
| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. || 🔧 |
| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. || |
| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. || 🔧 |
| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. || 🔧 |
| [no-instanceof-array](docs/rules/no-instanceof-array.md) | Require `Array.isArray()` instead of `instanceof Array`. || 🔧 |
Expand Down
45 changes: 45 additions & 0 deletions rules/no-document-cookie.js
@@ -0,0 +1,45 @@
'use strict';
const getDocumentationUrl = require('./utils/get-documentation-url');
const getPropertyName = require('./utils/get-property-name');

const MESSAGE_ID = 'no-document-cookie';
const messages = {
[MESSAGE_ID]: 'Do not use `document.cookie` directly.'
};

const selector = [
'AssignmentExpression',
'>',
'MemberExpression.left',
'[object.type="Identifier"]',
'[object.name="document"]'
].join('');

/** @param {import('eslint').Rule.RuleContext} context */
const create = context => {
return {
[selector](node) {
if (getPropertyName(node, context.getScope()) !== 'cookie') {
return;
}

context.report({
node,
messageId: MESSAGE_ID
});
}
};
};

module.exports = {
create,
meta: {
type: 'problem',
docs: {
description: 'Do not use `document.cookie` directly.',
url: getDocumentationUrl(__filename)
},
schema: [],
messages
}
};
33 changes: 33 additions & 0 deletions test/no-document-cookie.mjs
@@ -0,0 +1,33 @@
import outdent from 'outdent';
import {getTester} from './utils/test.mjs';

const {test} = getTester(import.meta);

test.snapshot({
valid: [
'document.cookie',
'const foo = document.cookie',
'foo = document.cookie',
'foo = document?.cookie',
'foo = document.cookie + ";foo=bar"',
'delete document.cookie',
'if (document.cookie.includes("foo")){}',
'Object.assign(document, {cookie: "foo=bar"})',
'document[CONSTANTS_COOKIE] = "foo=bar"',
'document[cookie] = "foo=bar"',
'var doc = document; doc.cookie = "foo=bar"',
'window.document.cookie = "foo=bar"'
],
invalid: [
'document.cookie = "foo=bar"',
'document.cookie += ";foo=bar"',
'document.cookie = document.cookie + ";foo=bar"',
'document.cookie &&= true',
outdent`
const CONSTANTS_COOKIE = "cookie";
document[CONSTANTS_COOKIE] = "foo=bar";
`,
'document["coo" + "kie"] = "foo=bar"',
'foo = document.cookie = "foo=bar"'
]
});
77 changes: 77 additions & 0 deletions test/snapshots/no-document-cookie.mjs.md
@@ -0,0 +1,77 @@
# Snapshot report for `test/no-document-cookie.mjs`

The actual snapshot is saved in `no-document-cookie.mjs.snap`.

Generated by [AVA](https://avajs.dev).

## Invalid #1
1 | document.cookie = "foo=bar"

> Error 1/1
`␊
> 1 | document.cookie = "foo=bar"␊
| ^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
`

## Invalid #2
1 | document.cookie += ";foo=bar"

> Error 1/1
`␊
> 1 | document.cookie += ";foo=bar"␊
| ^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
`

## Invalid #3
1 | document.cookie = document.cookie + ";foo=bar"

> Error 1/1
`␊
> 1 | document.cookie = document.cookie + ";foo=bar"␊
| ^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
`

## Invalid #4
1 | document.cookie &&= true

> Error 1/1
`␊
> 1 | document.cookie &&= true␊
| ^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
`

## Invalid #5
1 | const CONSTANTS_COOKIE = "cookie";
2 | document[CONSTANTS_COOKIE] = "foo=bar";

> Error 1/1
`␊
1 | const CONSTANTS_COOKIE = "cookie";␊
> 2 | document[CONSTANTS_COOKIE] = "foo=bar";␊
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
`

## Invalid #6
1 | document["coo" + "kie"] = "foo=bar"

> Error 1/1
`␊
> 1 | document["coo" + "kie"] = "foo=bar"␊
| ^^^^^^^^^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
`

## Invalid #7
1 | foo = document.cookie = "foo=bar"

> Error 1/1
`␊
> 1 | foo = document.cookie = "foo=bar"␊
| ^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
`
Binary file added test/snapshots/no-document-cookie.mjs.snap
Binary file not shown.

0 comments on commit 866c4a3

Please sign in to comment.