tsl-react 0.0.3-next.3 → 0.0.3-next.5

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/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- import { Rule } from 'tsl';
1
+ import { Rule } from "tsl";
2
+
3
+ //#region src/rules/no-leaked-conditional-rendering.d.ts
2
4
 
3
5
  /**
4
6
  * Prevents problematic leaked values from being rendered.
@@ -52,5 +54,5 @@ import { Rule } from 'tsl';
52
54
  * @since 0.0.0
53
55
  */
54
56
  declare const noLeakedConditionalRendering: (options?: "off" | undefined) => Rule<unknown>;
55
-
56
- export { noLeakedConditionalRendering };
57
+ //#endregion
58
+ export { noLeakedConditionalRendering };
package/dist/index.js CHANGED
@@ -1,66 +1,118 @@
1
- import { compare } from 'compare-versions';
2
- import { defineRule } from 'tsl';
3
- import { SyntaxKind } from 'typescript';
4
- import { isLogicalNegationExpression } from '@react-analyzer/ast';
5
- import { unit } from '@react-analyzer/eff';
6
- import { Report } from '@react-analyzer/kit';
7
- import { getAnalyzerOptions } from '@react-analyzer/shared';
8
- import * as RA from '@react-analyzer/core';
1
+ import { compare } from "compare-versions";
2
+ import { defineRule } from "tsl";
3
+ import { SyntaxKind } from "typescript";
4
+ import { isLogicalNegationExpression } from "@react-analyzer/ast";
5
+ import * as RA from "@react-analyzer/core";
6
+ import { unit } from "@react-analyzer/eff";
7
+ import { Report } from "@react-analyzer/kit";
8
+ import { getAnalyzerOptions } from "@react-analyzer/shared";
9
9
 
10
- // src/rules/no-leaked-conditional-rendering.ts
11
- var messages = {
12
- noLeakedConditionalRendering: (p) => `Potential leaked value ${p.value} that might cause unintentionally rendered values or rendering crashes.`
13
- };
14
- var noLeakedConditionalRendering = defineRule(() => {
15
- return {
16
- name: "@react-analyzer/noLeakedConditionalRendering",
17
- createData(ctx) {
18
- const { version } = getAnalyzerOptions();
19
- const state = {
20
- isWithinJsxExpression: false
21
- };
22
- const allowedVariants = [
23
- "any",
24
- "boolean",
25
- "nullish",
26
- "object",
27
- "falsy boolean",
28
- "truthy bigint",
29
- "truthy boolean",
30
- "truthy number",
31
- "truthy string",
32
- ...compare(version, "18.0.0", "<") ? [] : ["string", "falsy string"]
33
- ];
34
- function getReportDescriptor(node) {
35
- if (isLogicalNegationExpression(node.left)) return unit;
36
- const leftType = ctx.utils.getConstrainedTypeAtLocation(node.left);
37
- const leftTypeVariants = RA.getVariantsOfTypes(ctx.utils.unionConstituents(leftType));
38
- const areAllLeftTypeVariantsAllowed = Array.from(leftTypeVariants.values()).every((type) => allowedVariants.some((allowed) => allowed === type));
39
- if (!areAllLeftTypeVariantsAllowed) {
40
- return {
41
- node: node.left,
42
- message: messages.noLeakedConditionalRendering({ value: node.left.getText() })
43
- };
44
- }
45
- return unit;
46
- }
47
- return { state, version, allowedVariants, getReportDescriptor };
48
- },
49
- visitor: {
50
- JsxExpression(ctx) {
51
- ctx.data.state.isWithinJsxExpression = true;
52
- },
53
- JsxExpression_exit(ctx) {
54
- ctx.data.state.isWithinJsxExpression = false;
55
- },
56
- BinaryExpression(ctx, node) {
57
- const { state, getReportDescriptor } = ctx.data;
58
- if (!state.isWithinJsxExpression) return;
59
- if (node.operatorToken.kind !== SyntaxKind.AmpersandAmpersandToken) return;
60
- Report.report(ctx, getReportDescriptor(node));
61
- }
62
- }
63
- };
10
+ //#region src/rules/no-leaked-conditional-rendering.ts
11
+ /** @internal */
12
+ const messages = { noLeakedConditionalRendering: (p) => `Potential leaked value ${p.value} that might cause unintentionally rendered values or rendering crashes.` };
13
+ /**
14
+ * Prevents problematic leaked values from being rendered.
15
+ *
16
+ * Using the && operator to render some element conditionally in JSX can cause unexpected values being rendered, or even crashing the rendering.
17
+ *
18
+ * **Examples**
19
+ *
20
+ * ```tsx
21
+ * import React from "react";
22
+ *
23
+ * interface MyComponentProps {
24
+ * count: number;
25
+ * }
26
+ *
27
+ * function MyComponent({ count }: MyComponentProps) {
28
+ * return <div>{count && <span>There are {count} results</span>}</div>;
29
+ * // ^^^^^
30
+ * // - Potential leaked value 'count' that might cause unintentionally rendered values or rendering crashes.
31
+ * }
32
+ * ```
33
+ *
34
+ * ```tsx
35
+ * import React from "react";
36
+ *
37
+ * interface MyComponentProps {
38
+ * items: string[];
39
+ * }
40
+ *
41
+ * function MyComponent({ items }: MyComponentProps) {
42
+ * return <div>{items.length && <List items={items} />}</div>;
43
+ * // ^^^^^^^^^^^^
44
+ * // - Potential leaked value 'items.length' that might cause unintentionally rendered values or rendering crashes.
45
+ * }
46
+ * ```
47
+ *
48
+ * ```tsx
49
+ * import React from "react";
50
+ *
51
+ * interface MyComponentProps {
52
+ * items: string[];
53
+ * }
54
+ *
55
+ * function MyComponent({ items }: MyComponentProps) {
56
+ * return <div>{items[0] && <List items={items} />}</div>;
57
+ * // ^^^^^^^^
58
+ * // - Potential leaked value 'items[0]' that might cause unintentionally rendered values or rendering crashes.
59
+ * }
60
+ * ```
61
+ *
62
+ * @since 0.0.0
63
+ */
64
+ const noLeakedConditionalRendering = defineRule(() => {
65
+ return {
66
+ name: "@react-analyzer/noLeakedConditionalRendering",
67
+ createData(ctx) {
68
+ const { version } = getAnalyzerOptions();
69
+ const state = { isWithinJsxExpression: false };
70
+ const allowedVariants = [
71
+ "any",
72
+ "boolean",
73
+ "nullish",
74
+ "object",
75
+ "falsy boolean",
76
+ "truthy bigint",
77
+ "truthy boolean",
78
+ "truthy number",
79
+ "truthy string",
80
+ ...compare(version, "18.0.0", "<") ? [] : ["string", "falsy string"]
81
+ ];
82
+ function getReportDescriptor(node) {
83
+ if (isLogicalNegationExpression(node.left)) return unit;
84
+ const leftType = ctx.utils.getConstrainedTypeAtLocation(node.left);
85
+ const leftTypeVariants = RA.getVariantsOfTypes(ctx.utils.unionConstituents(leftType));
86
+ const areAllLeftTypeVariantsAllowed = Array.from(leftTypeVariants.values()).every((type) => allowedVariants.some((allowed) => allowed === type));
87
+ if (!areAllLeftTypeVariantsAllowed) return {
88
+ node: node.left,
89
+ message: messages.noLeakedConditionalRendering({ value: node.left.getText() })
90
+ };
91
+ return unit;
92
+ }
93
+ return {
94
+ state,
95
+ version,
96
+ allowedVariants,
97
+ getReportDescriptor
98
+ };
99
+ },
100
+ visitor: {
101
+ JsxExpression(ctx) {
102
+ ctx.data.state.isWithinJsxExpression = true;
103
+ },
104
+ JsxExpression_exit(ctx) {
105
+ ctx.data.state.isWithinJsxExpression = false;
106
+ },
107
+ BinaryExpression(ctx, node) {
108
+ const { state, getReportDescriptor } = ctx.data;
109
+ if (!state.isWithinJsxExpression) return;
110
+ if (node.operatorToken.kind !== SyntaxKind.AmpersandAmpersandToken) return;
111
+ Report.report(ctx, getReportDescriptor(node));
112
+ }
113
+ }
114
+ };
64
115
  });
65
116
 
66
- export { noLeakedConditionalRendering };
117
+ //#endregion
118
+ export { noLeakedConditionalRendering };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsl-react",
3
- "version": "0.0.3-next.3",
3
+ "version": "0.0.3-next.5",
4
4
  "description": "A unified plugin that combines all individual plugins from the react-analyzer monorepo into one.",
5
5
  "keywords": [
6
6
  "react",
@@ -28,14 +28,14 @@
28
28
  ],
29
29
  "dependencies": {
30
30
  "compare-versions": "^6.1.1",
31
- "@react-analyzer/ast": "0.0.3-next.3",
32
- "@react-analyzer/core": "0.0.3-next.3",
33
- "@react-analyzer/eff": "0.0.3-next.3",
34
- "@react-analyzer/kit": "0.0.3-next.3",
35
- "@react-analyzer/shared": "0.0.3-next.3"
31
+ "@react-analyzer/ast": "0.0.3-next.5",
32
+ "@react-analyzer/kit": "0.0.3-next.5",
33
+ "@react-analyzer/shared": "0.0.3-next.5",
34
+ "@react-analyzer/eff": "0.0.3-next.5",
35
+ "@react-analyzer/core": "0.0.3-next.5"
36
36
  },
37
37
  "devDependencies": {
38
- "tsup": "^8.5.0",
38
+ "tsdown": "^0.14.1",
39
39
  "@local/configs": "0.0.0"
40
40
  },
41
41
  "peerDependencies": {
@@ -50,7 +50,7 @@
50
50
  "access": "public"
51
51
  },
52
52
  "scripts": {
53
- "build": "tsup --dts-resolve",
53
+ "build": "tsdown --dts-resolve",
54
54
  "build:docs": "typedoc",
55
55
  "lint:publish": "pnpm publint",
56
56
  "lint:ts": "tsl"