-
Notifications
You must be signed in to change notification settings - Fork 754
Expand file tree
/
Copy pathserver-event-handlers.ts
More file actions
60 lines (52 loc) · 1.96 KB
/
Copy pathserver-event-handlers.ts
File metadata and controls
60 lines (52 loc) · 1.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { NO_VISITOR, pathSegments } from "../utils.ts";
/**
* Reports server components that install client side event handlers.
*
* Disallows `on*` attributes for JSX components inside the
* `routes/` directory, as these components are rendered on the server.
*
* It will also warn when passing a function as prop to a custom element,
* as functions cannot be serialized to HTML on the server.
*
* @example
* ```tsx
* // routes/index.ts
* <button onClick={() => {}} />
* // ^^^^^^^^^^^^^^^^^^ invalid handler
*
* <MyComponent handler={() => {}} />
* // ^^^^^^^^^^^^^^^^^^ invalid handler
* ```
*
* The `(_islands)` directory is excluded from this lint rule.
*
* @module
*/
export const RULE_NAME = "server-event-handlers";
const MESSAGE = "Server components cannot install client side event handlers.";
const HINT =
"Remove this property or turn the enclosing component into an island";
// Note: This selector will match any function passed as a prop to a custom element, not just event handlers.
const CUSTOM_ELEMENT_FN_EXPR_ATTR_SELECTOR =
'JSXOpeningElement[name.type="JSXIdentifier"][name.name=/-/] > JSXAttribute[name.type="JSXIdentifier"]:has(> JSXExpressionContainer[expression.type=/^(FunctionExpression|ArrowFunctionExpression)$/])';
const HTML_ELEMENT_ON_ATTR_SELECTOR =
'JSXOpeningElement[name.type="JSXIdentifier"][name.name=/^[a-z]+$/] > JSXAttribute[name.type="JSXIdentifier"][name.name=/^on/]';
export const rule: Deno.lint.Rule = {
create(ctx) {
const path = pathSegments(ctx.filename);
// Ignore island components or components outside `routes/` dir
if (path.isIsland() || !path.isRoute()) return NO_VISITOR;
const reportNode = (node: Deno.lint.JSXAttribute) => {
ctx.report({
message: MESSAGE,
hint: HINT,
node,
range: node.range,
});
};
return {
[CUSTOM_ELEMENT_FN_EXPR_ATTR_SELECTOR]: reportNode,
[HTML_ELEMENT_ON_ATTR_SELECTOR]: reportNode,
};
},
};