@lipemat/eslint-config 5.0.0-beta.2 → 5.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/plugins/security/rules/dangerously-set-inner-html.js +1 -1
- package/plugins/security/rules/html-executing-assignment.js +7 -7
- package/plugins/security/rules/html-executing-function.js +10 -9
- package/plugins/security/rules/html-sinks.js +5 -11
- package/plugins/security/rules/html-string-concat.js +6 -1
- package/plugins/security/rules/jquery-executing.js +2 -2
- package/plugins/security/rules/window-escaping.js +13 -46
- package/plugins/security/utils/shared.js +36 -5
- package/types/plugins/security/rules/html-string-concat.d.ts +7 -1
- package/types/plugins/security/utils/shared.d.ts +20 -2
package/package.json
CHANGED
|
@@ -52,7 +52,7 @@ const plugin = {
|
|
|
52
52
|
node,
|
|
53
53
|
messageId: 'dangerousInnerHtml',
|
|
54
54
|
fix: (fixer) => {
|
|
55
|
-
return fixer.replaceText(node, `dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(${context.sourceCode.getText(htmlValue)})}}`);
|
|
55
|
+
return fixer.replaceText(node, `dangerouslySetInnerHTML={{__html: DOMPurify.sanitize( ${context.sourceCode.getText(htmlValue)} )}}`);
|
|
56
56
|
},
|
|
57
57
|
});
|
|
58
58
|
},
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
-
import { isSanitized } from '../utils/shared.js';
|
|
2
|
+
import { isDomElementType, isSafeLiteralString, isSanitized } from '../utils/shared.js';
|
|
3
3
|
const UNSAFE_PROPERTIES = [
|
|
4
|
-
'innerHTML',
|
|
4
|
+
'innerHTML',
|
|
5
|
+
'outerHTML',
|
|
5
6
|
];
|
|
6
7
|
function isUnsafeProperty(propertyName) {
|
|
7
8
|
return UNSAFE_PROPERTIES.includes(propertyName);
|
|
@@ -26,8 +27,7 @@ const plugin = {
|
|
|
26
27
|
create(context) {
|
|
27
28
|
return {
|
|
28
29
|
AssignmentExpression(node) {
|
|
29
|
-
|
|
30
|
-
if (AST_NODE_TYPES.MemberExpression !== node.left.type || !('name' in node.left.property)) {
|
|
30
|
+
if (AST_NODE_TYPES.MemberExpression !== node.left.type || AST_NODE_TYPES.Identifier !== node.left.property.type) {
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
33
|
const propertyName = node.left.property.name;
|
|
@@ -35,7 +35,7 @@ const plugin = {
|
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
37
|
const value = node.right;
|
|
38
|
-
if (!isSanitized(value)) {
|
|
38
|
+
if (!isSafeLiteralString(value) && !isSanitized(value) && isDomElementType(node.left.object, context)) {
|
|
39
39
|
context.report({
|
|
40
40
|
node,
|
|
41
41
|
messageId: 'executed',
|
|
@@ -47,14 +47,14 @@ const plugin = {
|
|
|
47
47
|
messageId: 'domPurify',
|
|
48
48
|
fix: (fixer) => {
|
|
49
49
|
const valueText = context.sourceCode.getText(value);
|
|
50
|
-
return fixer.replaceText(value, `DOMPurify.sanitize(${valueText})`);
|
|
50
|
+
return fixer.replaceText(value, `DOMPurify.sanitize( ${valueText} )`);
|
|
51
51
|
},
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
messageId: 'sanitize',
|
|
55
55
|
fix: (fixer) => {
|
|
56
56
|
const valueText = context.sourceCode.getText(value);
|
|
57
|
-
return fixer.replaceText(value, `sanitize(${valueText})`);
|
|
57
|
+
return fixer.replaceText(value, `sanitize( ${valueText} )`);
|
|
58
58
|
},
|
|
59
59
|
},
|
|
60
60
|
],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
-
import { isDomElementType, isSanitized } from '../utils/shared.js';
|
|
2
|
+
import { isDomElementType, isSafeLiteralString, isSanitized } from '../utils/shared.js';
|
|
3
3
|
import { isJQueryCall } from './jquery-executing.js';
|
|
4
4
|
const DOCUMENT_METHODS = [
|
|
5
5
|
'document.write',
|
|
@@ -42,19 +42,20 @@ function getDocumentCall(node) {
|
|
|
42
42
|
}
|
|
43
43
|
return null;
|
|
44
44
|
}
|
|
45
|
-
function getElementMethodCall(node) {
|
|
46
|
-
|
|
47
|
-
if (AST_NODE_TYPES.MemberExpression !== node.callee.type || !('name' in node.callee.property)) {
|
|
45
|
+
function getElementMethodCall(node, context) {
|
|
46
|
+
if (AST_NODE_TYPES.MemberExpression !== node.callee.type || AST_NODE_TYPES.Identifier !== node.callee.property.type) {
|
|
48
47
|
return null;
|
|
49
48
|
}
|
|
50
49
|
const methodName = node.callee.property.name;
|
|
50
|
+
if (!isDomElementType(node.callee.object, context)) {
|
|
51
|
+
return null; // We only care about DOM element method calls.
|
|
52
|
+
}
|
|
51
53
|
if (!isUnsafeMethod(methodName)) {
|
|
52
54
|
return null;
|
|
53
55
|
}
|
|
54
56
|
if (isJQueryCall(node)) {
|
|
55
57
|
return null; // Handled in jquery-executing rule
|
|
56
58
|
}
|
|
57
|
-
// This is a generic element method call, not jQuery specific
|
|
58
59
|
return methodName;
|
|
59
60
|
}
|
|
60
61
|
const plugin = {
|
|
@@ -91,7 +92,7 @@ const plugin = {
|
|
|
91
92
|
method = documentMethod;
|
|
92
93
|
}
|
|
93
94
|
else {
|
|
94
|
-
method = getElementMethodCall(node);
|
|
95
|
+
method = getElementMethodCall(node, context);
|
|
95
96
|
if (null === method) {
|
|
96
97
|
return;
|
|
97
98
|
}
|
|
@@ -100,7 +101,7 @@ const plugin = {
|
|
|
100
101
|
if (isSecondArgMethod(method)) {
|
|
101
102
|
arg = node.arguments[1];
|
|
102
103
|
}
|
|
103
|
-
if (!isSanitized(arg) && !isDomElementType(arg, context)) {
|
|
104
|
+
if (!isSafeLiteralString(arg) && !isSanitized(arg) && !isDomElementType(arg, context)) {
|
|
104
105
|
context.report({
|
|
105
106
|
node,
|
|
106
107
|
messageId: method,
|
|
@@ -109,14 +110,14 @@ const plugin = {
|
|
|
109
110
|
messageId: 'domPurify',
|
|
110
111
|
fix: (fixer) => {
|
|
111
112
|
const argText = context.sourceCode.getText(arg);
|
|
112
|
-
return fixer.replaceText(arg, `DOMPurify.sanitize(${argText})`);
|
|
113
|
+
return fixer.replaceText(arg, `DOMPurify.sanitize( ${argText} )`);
|
|
113
114
|
},
|
|
114
115
|
},
|
|
115
116
|
{
|
|
116
117
|
messageId: 'sanitize',
|
|
117
118
|
fix: (fixer) => {
|
|
118
119
|
const argText = context.sourceCode.getText(arg);
|
|
119
|
-
return fixer.replaceText(arg, `sanitize(${argText})`);
|
|
120
|
+
return fixer.replaceText(arg, `sanitize( ${argText} )`);
|
|
120
121
|
},
|
|
121
122
|
},
|
|
122
123
|
],
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
-
import { isSanitized, isStringLike } from '../utils/shared.js';
|
|
3
|
-
/**
|
|
4
|
-
* Check if a node is a literal string
|
|
5
|
-
*/
|
|
6
|
-
function isLiteralString(node) {
|
|
7
|
-
return AST_NODE_TYPES.Literal === node.type && 'string' === typeof node.value;
|
|
8
|
-
}
|
|
2
|
+
import { isLiteralString, isSanitized, isStringLike } from '../utils/shared.js';
|
|
9
3
|
/**
|
|
10
4
|
* Get the callee name from a call expression
|
|
11
5
|
*/
|
|
@@ -87,11 +81,11 @@ const plugin = {
|
|
|
87
81
|
suggest: [
|
|
88
82
|
{
|
|
89
83
|
messageId: 'domPurify',
|
|
90
|
-
fix: fixer => fixer.replaceText(firstArg, `DOMPurify.sanitize(${argText})`),
|
|
84
|
+
fix: fixer => fixer.replaceText(firstArg, `DOMPurify.sanitize( ${argText} )`),
|
|
91
85
|
},
|
|
92
86
|
{
|
|
93
87
|
messageId: 'sanitize',
|
|
94
|
-
fix: fixer => fixer.replaceText(firstArg, `sanitize(${argText})`),
|
|
88
|
+
fix: fixer => fixer.replaceText(firstArg, `sanitize( ${argText} )`),
|
|
95
89
|
},
|
|
96
90
|
],
|
|
97
91
|
});
|
|
@@ -111,11 +105,11 @@ const plugin = {
|
|
|
111
105
|
suggest: [
|
|
112
106
|
{
|
|
113
107
|
messageId: 'domPurify',
|
|
114
|
-
fix: fixer => fixer.replaceText(node.right, `DOMPurify.sanitize(${rightText})`),
|
|
108
|
+
fix: fixer => fixer.replaceText(node.right, `DOMPurify.sanitize( ${rightText} )`),
|
|
115
109
|
},
|
|
116
110
|
{
|
|
117
111
|
messageId: 'sanitize',
|
|
118
|
-
fix: fixer => fixer.replaceText(node.right, `sanitize(${rightText})`),
|
|
112
|
+
fix: fixer => fixer.replaceText(node.right, `sanitize( ${rightText} )`),
|
|
119
113
|
},
|
|
120
114
|
],
|
|
121
115
|
});
|
|
@@ -3,7 +3,12 @@ function isStringConcat(node) {
|
|
|
3
3
|
// 'foo' + userInput + 'bar' (HTML-like only)
|
|
4
4
|
return AST_NODE_TYPES.BinaryExpression === node.type && '+' === node.operator && hasHtmlLikeStrings(node);
|
|
5
5
|
}
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Check if an expression contains any HTML-like strings.
|
|
8
|
+
* - Looks for `<` or `>` characters in string literals and template literals.
|
|
9
|
+
* - Recursively checks binary expressions with the ` + ` operator.
|
|
10
|
+
*/
|
|
11
|
+
export function hasHtmlLikeStrings(node) {
|
|
7
12
|
if (AST_NODE_TYPES.Literal === node.type && 'string' === typeof node.value) {
|
|
8
13
|
return /[<>]/.test(node.value);
|
|
9
14
|
}
|
|
@@ -84,14 +84,14 @@ const plugin = {
|
|
|
84
84
|
messageId: 'domPurify',
|
|
85
85
|
fix: (fixer) => {
|
|
86
86
|
const argText = context.sourceCode.getText(arg);
|
|
87
|
-
return fixer.replaceText(arg, `DOMPurify.sanitize(${argText})`);
|
|
87
|
+
return fixer.replaceText(arg, `DOMPurify.sanitize( ${argText} )`);
|
|
88
88
|
},
|
|
89
89
|
},
|
|
90
90
|
{
|
|
91
91
|
messageId: 'sanitize',
|
|
92
92
|
fix: (fixer) => {
|
|
93
93
|
const argText = context.sourceCode.getText(arg);
|
|
94
|
-
return fixer.replaceText(arg, `sanitize(${argText})`);
|
|
94
|
+
return fixer.replaceText(arg, `sanitize( ${argText} )`);
|
|
95
95
|
},
|
|
96
96
|
},
|
|
97
97
|
],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
-
import { isSanitized } from '../utils/shared.js';
|
|
2
|
+
import { isLiteralString, isSanitized } from '../utils/shared.js';
|
|
3
3
|
// Window and location properties that need special handling
|
|
4
4
|
const LOCATION_PROPS = new Set(['href', 'src', 'action',
|
|
5
5
|
'protocol', 'host', 'hostname', 'pathname', 'search', 'hash', 'username', 'port', 'name', 'status',
|
|
@@ -9,37 +9,7 @@ export function isSafeUrlString(value) {
|
|
|
9
9
|
return !/^\s*(?:javascript|data|vbscript|about|livescript)\s*:/i.test(decodeURIComponent(value.replace(/[\u0000-\u001F\u007F]+/g, '')));
|
|
10
10
|
}
|
|
11
11
|
function isSafeUrlLiteral(node) {
|
|
12
|
-
|
|
13
|
-
return false;
|
|
14
|
-
}
|
|
15
|
-
if (typeof node.value !== 'string') {
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
return isSafeUrlString(node.value);
|
|
19
|
-
}
|
|
20
|
-
function isSafeUrlTemplate(node) {
|
|
21
|
-
if (AST_NODE_TYPES.TemplateLiteral !== node.type || 0 === node.quasis.length) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
// Basic scheme safety on the first static chunk
|
|
25
|
-
const firstChunk = node.quasis[0];
|
|
26
|
-
if (isSafeUrlLiteral(firstChunk)) {
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
return isUrlEncoded(node);
|
|
30
|
-
}
|
|
31
|
-
function isUrlEncoded(node) {
|
|
32
|
-
if (AST_NODE_TYPES.TemplateLiteral !== node.type) {
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
return Array.isArray(node.expressions) && node.expressions.length > 0 && node.expressions.every(isEncoded);
|
|
36
|
-
}
|
|
37
|
-
function isEncoded(node) {
|
|
38
|
-
if (AST_NODE_TYPES.CallExpression !== node.type) {
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
return AST_NODE_TYPES.Identifier === node.callee.type &&
|
|
42
|
-
('encodeURIComponent' === node.callee.name || 'encodeURI' === node.callee.name);
|
|
12
|
+
return isLiteralString(node) && isSafeUrlString(node.value);
|
|
43
13
|
}
|
|
44
14
|
function isWindowLocationAssignment(node) {
|
|
45
15
|
// window.location.<prop> = ...
|
|
@@ -60,16 +30,16 @@ function isWindowAssignment(node) {
|
|
|
60
30
|
'window' === node.left.object.name &&
|
|
61
31
|
WINDOW_PROPS.has(node.left.property.name));
|
|
62
32
|
}
|
|
63
|
-
function
|
|
33
|
+
function isWindowOrLocation(expression) {
|
|
64
34
|
// Helper to detect a window.* or window.location.*
|
|
65
|
-
if (AST_NODE_TYPES.MemberExpression !==
|
|
35
|
+
if (AST_NODE_TYPES.MemberExpression !== expression.type) {
|
|
66
36
|
return false;
|
|
67
37
|
}
|
|
68
|
-
if (AST_NODE_TYPES.Identifier ===
|
|
38
|
+
if (AST_NODE_TYPES.Identifier === expression.object.type && 'window' === expression.object.name) {
|
|
69
39
|
return true;
|
|
70
40
|
}
|
|
71
|
-
if (AST_NODE_TYPES.MemberExpression ===
|
|
72
|
-
const memberObject =
|
|
41
|
+
if (AST_NODE_TYPES.MemberExpression === expression.object.type) {
|
|
42
|
+
const memberObject = expression.object;
|
|
73
43
|
const isObjectWindow = AST_NODE_TYPES.Identifier === memberObject.object.type && 'window' === memberObject.object.name;
|
|
74
44
|
const isPropertyLocation = AST_NODE_TYPES.Identifier === memberObject.property.type && 'location' === memberObject.property.name;
|
|
75
45
|
return isObjectWindow && isPropertyLocation;
|
|
@@ -108,10 +78,7 @@ const plugin = {
|
|
|
108
78
|
if (!LOCATION_PROPS.has(propName)) {
|
|
109
79
|
return;
|
|
110
80
|
}
|
|
111
|
-
if (isSafeUrlLiteral(rhsResolved) ||
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (isSanitized(rhsResolved)) {
|
|
81
|
+
if (isSafeUrlLiteral(rhsResolved) || isSanitized(rhsResolved)) {
|
|
115
82
|
return;
|
|
116
83
|
}
|
|
117
84
|
context.report({
|
|
@@ -125,13 +92,13 @@ const plugin = {
|
|
|
125
92
|
messageId: 'sanitize',
|
|
126
93
|
fix: (fixer) => {
|
|
127
94
|
const argText = context.sourceCode.getText(right);
|
|
128
|
-
return fixer.replaceText(right, `sanitize(${argText})`);
|
|
95
|
+
return fixer.replaceText(right, `sanitize( ${argText} )`);
|
|
129
96
|
},
|
|
130
97
|
}, {
|
|
131
98
|
messageId: 'domPurify',
|
|
132
99
|
fix: (fixer) => {
|
|
133
100
|
const argText = context.sourceCode.getText(right);
|
|
134
|
-
return fixer.replaceText(right, `DOMPurify.sanitize(${argText})`);
|
|
101
|
+
return fixer.replaceText(right, `DOMPurify.sanitize( ${argText} )`);
|
|
135
102
|
},
|
|
136
103
|
},
|
|
137
104
|
],
|
|
@@ -154,13 +121,13 @@ const plugin = {
|
|
|
154
121
|
messageId: 'sanitize',
|
|
155
122
|
fix: (fixer) => {
|
|
156
123
|
const argText = context.sourceCode.getText(right);
|
|
157
|
-
return fixer.replaceText(right, `sanitize(${argText})`);
|
|
124
|
+
return fixer.replaceText(right, `sanitize( ${argText} )`);
|
|
158
125
|
},
|
|
159
126
|
}, {
|
|
160
127
|
messageId: 'domPurify',
|
|
161
128
|
fix: (fixer) => {
|
|
162
129
|
const argText = context.sourceCode.getText(right);
|
|
163
|
-
return fixer.replaceText(right, `DOMPurify.sanitize(${argText})`);
|
|
130
|
+
return fixer.replaceText(right, `DOMPurify.sanitize( ${argText} )`);
|
|
164
131
|
},
|
|
165
132
|
},
|
|
166
133
|
],
|
|
@@ -173,7 +140,7 @@ const plugin = {
|
|
|
173
140
|
if (AST_NODE_TYPES.AssignmentExpression === parent.type && parent.left === node) {
|
|
174
141
|
return;
|
|
175
142
|
}
|
|
176
|
-
if (!
|
|
143
|
+
if (!isWindowOrLocation(node) || !('name' in node.property)) {
|
|
177
144
|
return;
|
|
178
145
|
}
|
|
179
146
|
const propName = node.property.name;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';
|
|
2
2
|
import {} from 'typescript';
|
|
3
|
+
/**
|
|
4
|
+
* Is the node of type string.
|
|
5
|
+
* - String literals.
|
|
6
|
+
* - constants of type string.
|
|
7
|
+
* - template literals.
|
|
8
|
+
* - intrinsic type string.
|
|
9
|
+
*/
|
|
3
10
|
export function isStringLike(node, context) {
|
|
4
11
|
const type = getType(node, context);
|
|
5
12
|
const literal = type.isStringLiteral();
|
|
@@ -9,9 +16,9 @@ export function isStringLike(node, context) {
|
|
|
9
16
|
/**
|
|
10
17
|
* Get the TypeScript type of node.
|
|
11
18
|
*/
|
|
12
|
-
export function getType(
|
|
19
|
+
export function getType(expression, context) {
|
|
13
20
|
const { getTypeAtLocation } = ESLintUtils.getParserServices(context);
|
|
14
|
-
const type = getTypeAtLocation(
|
|
21
|
+
const type = getTypeAtLocation(expression);
|
|
15
22
|
return type.getNonNullableType();
|
|
16
23
|
}
|
|
17
24
|
/**
|
|
@@ -22,10 +29,13 @@ export function getType(arg, context) {
|
|
|
22
29
|
*
|
|
23
30
|
* @link https://typescript-eslint.io/developers/custom-rules/#typed-rules
|
|
24
31
|
*/
|
|
25
|
-
export function isDomElementType(
|
|
26
|
-
const
|
|
27
|
-
const name =
|
|
32
|
+
export function isDomElementType(expression, context) {
|
|
33
|
+
const type = getType(expression, context);
|
|
34
|
+
const name = type.getSymbol()?.escapedName ?? '';
|
|
28
35
|
// Match any type that ends with "Element", e.g., HTMLElement, HTMLDivElement, Element, etc.
|
|
36
|
+
if ('Element' === name) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
29
39
|
return name.startsWith('HTML') && name.endsWith('Element');
|
|
30
40
|
}
|
|
31
41
|
/**
|
|
@@ -45,3 +55,24 @@ export function isSanitized(node) {
|
|
|
45
55
|
}
|
|
46
56
|
return false;
|
|
47
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Check if a node is a literal string
|
|
60
|
+
*/
|
|
61
|
+
export function isLiteralString(node) {
|
|
62
|
+
return AST_NODE_TYPES.Literal === node.type && 'string' === typeof node.value;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if a node is a literal string that is safe to use in an HTML context.
|
|
66
|
+
* - Must be a literal string.
|
|
67
|
+
* - Must not contain `<script`.
|
|
68
|
+
* - Must not start with a dangerous protocol (javascript:, data:, vbscript:, about:, livescript:).
|
|
69
|
+
*/
|
|
70
|
+
export function isSafeLiteralString(node) {
|
|
71
|
+
if (!isLiteralString(node)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
if (node.value.includes('<script')) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
return !/^\s*(?:javascript|data|vbscript|about|livescript)\s*:/i.test(decodeURIComponent(node.value.replace(/[\u0000-\u001F\u007F]+/g, '')));
|
|
78
|
+
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
import { type TSESLint } from '@typescript-eslint/utils';
|
|
1
|
+
import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Check if an expression contains any HTML-like strings.
|
|
4
|
+
* - Looks for `<` or `>` characters in string literals and template literals.
|
|
5
|
+
* - Recursively checks binary expressions with the ` + ` operator.
|
|
6
|
+
*/
|
|
7
|
+
export declare function hasHtmlLikeStrings(node: TSESTree.Expression | TSESTree.PrivateIdentifier): boolean;
|
|
2
8
|
declare const plugin: TSESLint.RuleModule<'htmlStringConcat'>;
|
|
3
9
|
export default plugin;
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
|
|
2
2
|
import { type Type } from 'typescript';
|
|
3
|
+
/**
|
|
4
|
+
* Is the node of type string.
|
|
5
|
+
* - String literals.
|
|
6
|
+
* - constants of type string.
|
|
7
|
+
* - template literals.
|
|
8
|
+
* - intrinsic type string.
|
|
9
|
+
*/
|
|
3
10
|
export declare function isStringLike(node: TSESTree.CallExpressionArgument, context: Readonly<TSESLint.RuleContext<string, readonly []>>): boolean;
|
|
4
11
|
/**
|
|
5
12
|
* Get the TypeScript type of node.
|
|
6
13
|
*/
|
|
7
|
-
export declare function getType<Context extends Readonly<TSESLint.RuleContext<string, readonly []>>>(
|
|
14
|
+
export declare function getType<Context extends Readonly<TSESLint.RuleContext<string, readonly []>>>(expression: TSESTree.CallExpressionArgument, context: Context): Type;
|
|
8
15
|
/**
|
|
9
16
|
* Is the type of variable being passed a DOM element?
|
|
10
17
|
*
|
|
@@ -13,9 +20,20 @@ export declare function getType<Context extends Readonly<TSESLint.RuleContext<st
|
|
|
13
20
|
*
|
|
14
21
|
* @link https://typescript-eslint.io/developers/custom-rules/#typed-rules
|
|
15
22
|
*/
|
|
16
|
-
export declare function isDomElementType<Context extends Readonly<TSESLint.RuleContext<string, readonly []>>>(
|
|
23
|
+
export declare function isDomElementType<Context extends Readonly<TSESLint.RuleContext<string, readonly []>>>(expression: TSESTree.CallExpressionArgument, context: Context): boolean;
|
|
17
24
|
/**
|
|
18
25
|
* Check if a node is a call to a known sanitization function.
|
|
19
26
|
* - Currently recognizes `sanitize(...)` and `DOMPurify.sanitize(...)`.
|
|
20
27
|
*/
|
|
21
28
|
export declare function isSanitized(node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Check if a node is a literal string
|
|
31
|
+
*/
|
|
32
|
+
export declare function isLiteralString(node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument): node is TSESTree.StringLiteral;
|
|
33
|
+
/**
|
|
34
|
+
* Check if a node is a literal string that is safe to use in an HTML context.
|
|
35
|
+
* - Must be a literal string.
|
|
36
|
+
* - Must not contain `<script`.
|
|
37
|
+
* - Must not start with a dangerous protocol (javascript:, data:, vbscript:, about:, livescript:).
|
|
38
|
+
*/
|
|
39
|
+
export declare function isSafeLiteralString(node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument): boolean;
|