Skip to content

Commit 866c4a3

Browse files
authored
Add no-document-cookie rule (#1244)
1 parent 6b340a3 commit 866c4a3

File tree

7 files changed

+197
-0
lines changed

7 files changed

+197
-0
lines changed

docs/rules/no-document-cookie.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Do not use `document.cookie` directly
2+
3+
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).
4+
5+
## Fail
6+
7+
```js
8+
document.cookie =
9+
'foo=bar' +
10+
'; Path=/' +
11+
'; Domain=example.com' +
12+
'; expires=Fri, 31 Dec 9999 23:59:59 GMT' +
13+
'; Secure';
14+
```
15+
16+
```js
17+
document.cookie += '; foo=bar';
18+
```
19+
20+
## Pass
21+
22+
```js
23+
await cookieStore.set({
24+
name: 'foo',
25+
value: 'bar',
26+
expires: Date.now() + 24 * 60 * 60 * 1000,
27+
domain: 'example.com'
28+
});
29+
```
30+
31+
```js
32+
const array = document.cookie.split('; ');
33+
```
34+
35+
```js
36+
import Cookies from 'js-cookie';
37+
38+
Cookies.set('foo', 'bar');
39+
```

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ module.exports = {
5959
'unicorn/no-array-push-push': 'error',
6060
'unicorn/no-array-reduce': 'error',
6161
'unicorn/no-console-spaces': 'error',
62+
'unicorn/no-document-cookie': 'error',
6263
'unicorn/no-for-loop': 'error',
6364
'unicorn/no-hex-escape': 'error',
6465
'unicorn/no-instanceof-array': 'error',

readme.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ Configure it in `package.json`.
5555
"unicorn/no-array-push-push": "error",
5656
"unicorn/no-array-reduce": "error",
5757
"unicorn/no-console-spaces": "error",
58+
"unicorn/no-document-cookie": "error",
5859
"unicorn/no-for-loop": "error",
5960
"unicorn/no-hex-escape": "error",
6061
"unicorn/no-instanceof-array": "error",
@@ -150,6 +151,7 @@ Each rule has emojis denoting:
150151
| [no-array-push-push](docs/rules/no-array-push-push.md) | Enforce combining multiple `Array#push()` into one call. || 🔧 |
151152
| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. || |
152153
| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. || 🔧 |
154+
| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. || |
153155
| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. || 🔧 |
154156
| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. || 🔧 |
155157
| [no-instanceof-array](docs/rules/no-instanceof-array.md) | Require `Array.isArray()` instead of `instanceof Array`. || 🔧 |

rules/no-document-cookie.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict';
2+
const getDocumentationUrl = require('./utils/get-documentation-url');
3+
const getPropertyName = require('./utils/get-property-name');
4+
5+
const MESSAGE_ID = 'no-document-cookie';
6+
const messages = {
7+
[MESSAGE_ID]: 'Do not use `document.cookie` directly.'
8+
};
9+
10+
const selector = [
11+
'AssignmentExpression',
12+
'>',
13+
'MemberExpression.left',
14+
'[object.type="Identifier"]',
15+
'[object.name="document"]'
16+
].join('');
17+
18+
/** @param {import('eslint').Rule.RuleContext} context */
19+
const create = context => {
20+
return {
21+
[selector](node) {
22+
if (getPropertyName(node, context.getScope()) !== 'cookie') {
23+
return;
24+
}
25+
26+
context.report({
27+
node,
28+
messageId: MESSAGE_ID
29+
});
30+
}
31+
};
32+
};
33+
34+
module.exports = {
35+
create,
36+
meta: {
37+
type: 'problem',
38+
docs: {
39+
description: 'Do not use `document.cookie` directly.',
40+
url: getDocumentationUrl(__filename)
41+
},
42+
schema: [],
43+
messages
44+
}
45+
};

test/no-document-cookie.mjs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import outdent from 'outdent';
2+
import {getTester} from './utils/test.mjs';
3+
4+
const {test} = getTester(import.meta);
5+
6+
test.snapshot({
7+
valid: [
8+
'document.cookie',
9+
'const foo = document.cookie',
10+
'foo = document.cookie',
11+
'foo = document?.cookie',
12+
'foo = document.cookie + ";foo=bar"',
13+
'delete document.cookie',
14+
'if (document.cookie.includes("foo")){}',
15+
'Object.assign(document, {cookie: "foo=bar"})',
16+
'document[CONSTANTS_COOKIE] = "foo=bar"',
17+
'document[cookie] = "foo=bar"',
18+
'var doc = document; doc.cookie = "foo=bar"',
19+
'window.document.cookie = "foo=bar"'
20+
],
21+
invalid: [
22+
'document.cookie = "foo=bar"',
23+
'document.cookie += ";foo=bar"',
24+
'document.cookie = document.cookie + ";foo=bar"',
25+
'document.cookie &&= true',
26+
outdent`
27+
const CONSTANTS_COOKIE = "cookie";
28+
document[CONSTANTS_COOKIE] = "foo=bar";
29+
`,
30+
'document["coo" + "kie"] = "foo=bar"',
31+
'foo = document.cookie = "foo=bar"'
32+
]
33+
});
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Snapshot report for `test/no-document-cookie.mjs`
2+
3+
The actual snapshot is saved in `no-document-cookie.mjs.snap`.
4+
5+
Generated by [AVA](https://avajs.dev).
6+
7+
## Invalid #1
8+
1 | document.cookie = "foo=bar"
9+
10+
> Error 1/1
11+
12+
`␊
13+
> 1 | document.cookie = "foo=bar"␊
14+
| ^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
15+
`
16+
17+
## Invalid #2
18+
1 | document.cookie += ";foo=bar"
19+
20+
> Error 1/1
21+
22+
`␊
23+
> 1 | document.cookie += ";foo=bar"␊
24+
| ^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
25+
`
26+
27+
## Invalid #3
28+
1 | document.cookie = document.cookie + ";foo=bar"
29+
30+
> Error 1/1
31+
32+
`␊
33+
> 1 | document.cookie = document.cookie + ";foo=bar"␊
34+
| ^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
35+
`
36+
37+
## Invalid #4
38+
1 | document.cookie &&= true
39+
40+
> Error 1/1
41+
42+
`␊
43+
> 1 | document.cookie &&= true␊
44+
| ^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
45+
`
46+
47+
## Invalid #5
48+
1 | const CONSTANTS_COOKIE = "cookie";
49+
2 | document[CONSTANTS_COOKIE] = "foo=bar";
50+
51+
> Error 1/1
52+
53+
`␊
54+
1 | const CONSTANTS_COOKIE = "cookie";␊
55+
> 2 | document[CONSTANTS_COOKIE] = "foo=bar";␊
56+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
57+
`
58+
59+
## Invalid #6
60+
1 | document["coo" + "kie"] = "foo=bar"
61+
62+
> Error 1/1
63+
64+
`␊
65+
> 1 | document["coo" + "kie"] = "foo=bar"␊
66+
| ^^^^^^^^^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
67+
`
68+
69+
## Invalid #7
70+
1 | foo = document.cookie = "foo=bar"
71+
72+
> Error 1/1
73+
74+
`␊
75+
> 1 | foo = document.cookie = "foo=bar"␊
76+
| ^^^^^^^^^^^^^^^ Do not use \`document.cookie\` directly.␊
77+
`
422 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)