@fictjs/eslint-plugin 0.0.14 → 0.1.0

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.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  default: () => index_default,
24
+ noComputedPropsKey: () => no_computed_props_key_default,
24
25
  noDirectMutation: () => no_direct_mutation_default,
25
26
  noEmptyEffect: () => no_empty_effect_default,
26
27
  noInlineFunctions: () => no_inline_functions_default,
@@ -29,13 +30,49 @@ __export(index_exports, {
29
30
  noStateDestructureWrite: () => no_state_destructure_write_default,
30
31
  noStateInLoop: () => no_state_in_loop_default,
31
32
  noStateOutsideComponent: () => no_state_outside_component_default,
33
+ noThirdPartyPropsSpread: () => no_third_party_props_spread_default,
34
+ noUnsafePropsSpread: () => no_unsafe_props_spread_default,
35
+ noUnsupportedPropsDestructure: () => no_unsupported_props_destructure_default,
32
36
  requireComponentReturn: () => require_component_return_default,
33
37
  requireListKey: () => require_list_key_default
34
38
  });
35
39
  module.exports = __toCommonJS(index_exports);
36
40
 
37
- // src/rules/no-direct-mutation.ts
41
+ // src/rules/no-computed-props-key.ts
38
42
  var rule = {
43
+ meta: {
44
+ type: "suggestion",
45
+ docs: {
46
+ description: "Disallow computed keys in JSX props object spreads",
47
+ recommended: true
48
+ },
49
+ messages: {
50
+ computedKey: "Computed props key may break fine-grained reactivity; use explicit props."
51
+ },
52
+ schema: []
53
+ },
54
+ create(context) {
55
+ return {
56
+ JSXSpreadAttribute(node) {
57
+ const expr = node.argument;
58
+ if (!expr || expr.type !== "ObjectExpression") return;
59
+ for (const prop of expr.properties ?? []) {
60
+ if (prop.type === "Property" && prop.computed) {
61
+ context.report({
62
+ node: prop,
63
+ messageId: "computedKey"
64
+ });
65
+ return;
66
+ }
67
+ }
68
+ }
69
+ };
70
+ }
71
+ };
72
+ var no_computed_props_key_default = rule;
73
+
74
+ // src/rules/no-direct-mutation.ts
75
+ var rule2 = {
39
76
  meta: {
40
77
  type: "suggestion",
41
78
  docs: {
@@ -87,10 +124,10 @@ function isDeepAccess(node) {
87
124
  }
88
125
  return depth > 1;
89
126
  }
90
- var no_direct_mutation_default = rule;
127
+ var no_direct_mutation_default = rule2;
91
128
 
92
129
  // src/rules/no-empty-effect.ts
93
- var rule2 = {
130
+ var rule3 = {
94
131
  meta: {
95
132
  type: "suggestion",
96
133
  docs: {
@@ -215,10 +252,10 @@ var rule2 = {
215
252
  };
216
253
  }
217
254
  };
218
- var no_empty_effect_default = rule2;
255
+ var no_empty_effect_default = rule3;
219
256
 
220
257
  // src/rules/no-inline-functions.ts
221
- var rule3 = {
258
+ var rule4 = {
222
259
  meta: {
223
260
  type: "suggestion",
224
261
  docs: {
@@ -268,10 +305,10 @@ var rule3 = {
268
305
  };
269
306
  }
270
307
  };
271
- var no_inline_functions_default = rule3;
308
+ var no_inline_functions_default = rule4;
272
309
 
273
310
  // src/rules/no-memo-side-effects.ts
274
- var rule4 = {
311
+ var rule5 = {
275
312
  meta: {
276
313
  type: "problem",
277
314
  docs: {
@@ -331,10 +368,10 @@ var rule4 = {
331
368
  };
332
369
  }
333
370
  };
334
- var no_memo_side_effects_default = rule4;
371
+ var no_memo_side_effects_default = rule5;
335
372
 
336
373
  // src/rules/no-nested-components.ts
337
- var rule5 = {
374
+ var rule6 = {
338
375
  meta: {
339
376
  type: "problem",
340
377
  docs: {
@@ -425,66 +462,7 @@ var rule5 = {
425
462
  };
426
463
  }
427
464
  };
428
- var no_nested_components_default = rule5;
429
-
430
- // src/rules/no-state-in-loop.ts
431
- var rule6 = {
432
- meta: {
433
- type: "problem",
434
- docs: {
435
- description: "Disallow $state declarations inside loops",
436
- recommended: true
437
- },
438
- messages: {
439
- noStateInLoop: "$state should not be declared inside a loop. Move it outside the loop."
440
- },
441
- schema: []
442
- },
443
- create(context) {
444
- let loopDepth = 0;
445
- return {
446
- ForStatement() {
447
- loopDepth++;
448
- },
449
- "ForStatement:exit"() {
450
- loopDepth--;
451
- },
452
- ForInStatement() {
453
- loopDepth++;
454
- },
455
- "ForInStatement:exit"() {
456
- loopDepth--;
457
- },
458
- ForOfStatement() {
459
- loopDepth++;
460
- },
461
- "ForOfStatement:exit"() {
462
- loopDepth--;
463
- },
464
- WhileStatement() {
465
- loopDepth++;
466
- },
467
- "WhileStatement:exit"() {
468
- loopDepth--;
469
- },
470
- DoWhileStatement() {
471
- loopDepth++;
472
- },
473
- "DoWhileStatement:exit"() {
474
- loopDepth--;
475
- },
476
- CallExpression(node) {
477
- if (loopDepth > 0 && node.callee.type === "Identifier" && node.callee.name === "$state") {
478
- context.report({
479
- node,
480
- messageId: "noStateInLoop"
481
- });
482
- }
483
- }
484
- };
485
- }
486
- };
487
- var no_state_in_loop_default = rule6;
465
+ var no_nested_components_default = rule6;
488
466
 
489
467
  // src/rules/no-state-destructure-write.ts
490
468
  var rule7 = {
@@ -576,6 +554,65 @@ var rule7 = {
576
554
  };
577
555
  var no_state_destructure_write_default = rule7;
578
556
 
557
+ // src/rules/no-state-in-loop.ts
558
+ var rule8 = {
559
+ meta: {
560
+ type: "problem",
561
+ docs: {
562
+ description: "Disallow $state declarations inside loops",
563
+ recommended: true
564
+ },
565
+ messages: {
566
+ noStateInLoop: "$state should not be declared inside a loop. Move it outside the loop."
567
+ },
568
+ schema: []
569
+ },
570
+ create(context) {
571
+ let loopDepth = 0;
572
+ return {
573
+ ForStatement() {
574
+ loopDepth++;
575
+ },
576
+ "ForStatement:exit"() {
577
+ loopDepth--;
578
+ },
579
+ ForInStatement() {
580
+ loopDepth++;
581
+ },
582
+ "ForInStatement:exit"() {
583
+ loopDepth--;
584
+ },
585
+ ForOfStatement() {
586
+ loopDepth++;
587
+ },
588
+ "ForOfStatement:exit"() {
589
+ loopDepth--;
590
+ },
591
+ WhileStatement() {
592
+ loopDepth++;
593
+ },
594
+ "WhileStatement:exit"() {
595
+ loopDepth--;
596
+ },
597
+ DoWhileStatement() {
598
+ loopDepth++;
599
+ },
600
+ "DoWhileStatement:exit"() {
601
+ loopDepth--;
602
+ },
603
+ CallExpression(node) {
604
+ if (loopDepth > 0 && node.callee.type === "Identifier" && node.callee.name === "$state") {
605
+ context.report({
606
+ node,
607
+ messageId: "noStateInLoop"
608
+ });
609
+ }
610
+ }
611
+ };
612
+ }
613
+ };
614
+ var no_state_in_loop_default = rule8;
615
+
579
616
  // src/rules/no-state-outside-component.ts
580
617
  var isUpperCaseName = (name) => !!name && /^[A-Z]/.test(name);
581
618
  var isHookName = (name) => !!name && /^use[A-Z]/.test(name);
@@ -643,7 +680,7 @@ var isDirectStateDeclaration = (node, ancestors) => {
643
680
  if (parent.init !== node) return false;
644
681
  return parent.id?.type === "Identifier";
645
682
  };
646
- var rule8 = {
683
+ var rule9 = {
647
684
  meta: {
648
685
  type: "problem",
649
686
  docs: {
@@ -692,10 +729,358 @@ var rule8 = {
692
729
  };
693
730
  }
694
731
  };
695
- var no_state_outside_component_default = rule8;
732
+ var no_state_outside_component_default = rule9;
733
+
734
+ // src/rules/no-third-party-props-spread.ts
735
+ var rule10 = {
736
+ meta: {
737
+ type: "suggestion",
738
+ docs: {
739
+ description: "Warn on third-party object spreads in JSX props",
740
+ recommended: true
741
+ },
742
+ messages: {
743
+ thirdPartySpread: "Spreading third-party objects into props may hide reactive changes; prefer explicit props or map fields."
744
+ },
745
+ schema: [
746
+ {
747
+ type: "object",
748
+ properties: {
749
+ includeCallExpressions: {
750
+ type: "boolean",
751
+ description: "Also warn when JSX spread comes from a third-party call expression."
752
+ },
753
+ allow: {
754
+ type: "array",
755
+ items: { type: "string" },
756
+ description: "Module specifiers to treat as internal."
757
+ },
758
+ internalPrefixes: {
759
+ type: "array",
760
+ items: { type: "string" },
761
+ description: 'Import path prefixes to treat as internal (e.g. "@/", "~/" ).'
762
+ }
763
+ },
764
+ additionalProperties: false
765
+ }
766
+ ]
767
+ },
768
+ create(context) {
769
+ const options = context.options[0] || {};
770
+ const allow = new Set(options.allow ?? []);
771
+ const internalPrefixes = options.internalPrefixes ?? [];
772
+ const includeCallExpressions = options.includeCallExpressions === true;
773
+ const thirdPartyImports = /* @__PURE__ */ new Set();
774
+ const isThirdPartySource = (source) => {
775
+ if (allow.has(source)) return false;
776
+ if (source.startsWith(".") || source.startsWith("/")) return false;
777
+ if (internalPrefixes.some((prefix) => source.startsWith(prefix))) return false;
778
+ return true;
779
+ };
780
+ const isComponentName = (name) => {
781
+ if (name.type === "JSXIdentifier") {
782
+ return /^[A-Z]/.test(name.name);
783
+ }
784
+ if (name.type === "JSXMemberExpression") {
785
+ return true;
786
+ }
787
+ return false;
788
+ };
789
+ const unwrapExpression = (expr) => {
790
+ let current = expr;
791
+ while (current) {
792
+ if (current.type === "ChainExpression") {
793
+ current = current.expression;
794
+ continue;
795
+ }
796
+ if (current.type === "TSAsExpression" || current.type === "TSTypeAssertion" || current.type === "TSNonNullExpression") {
797
+ current = current.expression;
798
+ continue;
799
+ }
800
+ break;
801
+ }
802
+ return current;
803
+ };
804
+ const getRootIdentifierName = (expr) => {
805
+ let current = unwrapExpression(expr);
806
+ while (current) {
807
+ if (current.type === "Identifier") return current.name;
808
+ if (current.type === "MemberExpression" || current.type === "OptionalMemberExpression") {
809
+ current = unwrapExpression(current.object);
810
+ continue;
811
+ }
812
+ if (includeCallExpressions && (current.type === "CallExpression" || current.type === "OptionalCallExpression")) {
813
+ current = unwrapExpression(current.callee);
814
+ continue;
815
+ }
816
+ return null;
817
+ }
818
+ return null;
819
+ };
820
+ return {
821
+ ImportDeclaration(node) {
822
+ if (!node.source?.value || typeof node.source.value !== "string") return;
823
+ if (!isThirdPartySource(node.source.value)) return;
824
+ for (const spec of node.specifiers ?? []) {
825
+ if (spec.local?.name) {
826
+ thirdPartyImports.add(spec.local.name);
827
+ }
828
+ }
829
+ },
830
+ JSXOpeningElement(node) {
831
+ if (!isComponentName(node.name)) return;
832
+ for (const attr of node.attributes ?? []) {
833
+ if (attr.type !== "JSXSpreadAttribute") continue;
834
+ const expr = attr.argument;
835
+ if (!expr) continue;
836
+ if (expr.type === "CallExpression" && expr.callee?.type === "Identifier" && expr.callee.name === "mergeProps") {
837
+ continue;
838
+ }
839
+ const root = getRootIdentifierName(expr);
840
+ if (root && thirdPartyImports.has(root)) {
841
+ context.report({
842
+ node: attr,
843
+ messageId: "thirdPartySpread"
844
+ });
845
+ }
846
+ }
847
+ }
848
+ };
849
+ }
850
+ };
851
+ var no_third_party_props_spread_default = rule10;
852
+
853
+ // src/rules/no-unsafe-props-spread.ts
854
+ var rule11 = {
855
+ meta: {
856
+ type: "suggestion",
857
+ docs: {
858
+ description: "Warn on JSX spread sources that are too dynamic to keep props reactive",
859
+ recommended: true
860
+ },
861
+ messages: {
862
+ unsafeSpread: "JSX spread source is too dynamic to keep props reactive. Consider passing explicit props or using mergeProps(() => source)."
863
+ },
864
+ schema: [
865
+ {
866
+ type: "object",
867
+ properties: {
868
+ accessorNames: {
869
+ type: "array",
870
+ items: { type: "string" },
871
+ description: "Identifier names to treat as accessor functions."
872
+ },
873
+ accessorModules: {
874
+ type: "array",
875
+ items: { type: "string" },
876
+ description: "Module specifiers whose imports are accessor functions."
877
+ }
878
+ },
879
+ additionalProperties: false
880
+ }
881
+ ]
882
+ },
883
+ create(context) {
884
+ const options = context.options[0] || {};
885
+ const accessorVars = new Set(options.accessorNames ?? []);
886
+ const accessorModules = new Set(options.accessorModules ?? []);
887
+ const isComponentName = (name) => {
888
+ if (name.type === "JSXIdentifier") {
889
+ return /^[A-Z]/.test(name.name);
890
+ }
891
+ if (name.type === "JSXMemberExpression") {
892
+ return true;
893
+ }
894
+ return false;
895
+ };
896
+ const recordAccessorVar = (node) => {
897
+ if (!node.init || node.id?.type !== "Identifier") return;
898
+ if (node.init.type !== "CallExpression") return;
899
+ if (node.init.callee?.type !== "Identifier") return;
900
+ const callee = node.init.callee.name;
901
+ if (callee === "$state" || callee === "$memo" || callee === "prop") {
902
+ accessorVars.add(node.id.name);
903
+ }
904
+ };
905
+ const isSafeAccessorExpr = (expr) => {
906
+ if (expr.type === "Identifier") return true;
907
+ if (expr.type === "CallExpression" && expr.callee?.type === "Identifier" && expr.arguments.length === 0 && accessorVars.has(expr.callee.name)) {
908
+ return true;
909
+ }
910
+ return false;
911
+ };
912
+ const isObviouslyDynamic = (expr) => expr.type === "ConditionalExpression" || expr.type === "LogicalExpression" || expr.type === "SequenceExpression" || expr.type === "AssignmentExpression" || expr.type === "UpdateExpression" || expr.type === "AwaitExpression" || expr.type === "NewExpression" || expr.type === "YieldExpression";
913
+ const hasUnsafeObjectLiteral = (obj) => {
914
+ for (const prop of obj.properties ?? []) {
915
+ if (prop.type === "SpreadElement") return true;
916
+ if (prop.type === "Property") {
917
+ if (prop.computed) return true;
918
+ if (prop.kind === "get" || prop.kind === "set") return true;
919
+ }
920
+ }
921
+ return false;
922
+ };
923
+ const shouldWarnForSpreadExpr = (expr) => {
924
+ if (isSafeAccessorExpr(expr)) return false;
925
+ if (expr.type === "CallExpression" && expr.callee?.type === "Identifier" && expr.callee.name === "mergeProps") {
926
+ return false;
927
+ }
928
+ if (expr.type === "ObjectExpression") {
929
+ return hasUnsafeObjectLiteral(expr);
930
+ }
931
+ if (isObviouslyDynamic(expr)) return true;
932
+ if (expr.type === "CallExpression") return true;
933
+ if (expr.type === "MemberExpression") return true;
934
+ return false;
935
+ };
936
+ return {
937
+ ImportDeclaration(node) {
938
+ if (!node.source?.value || typeof node.source.value !== "string") return;
939
+ if (!accessorModules.has(node.source.value)) return;
940
+ for (const spec of node.specifiers ?? []) {
941
+ if (spec.local?.name) {
942
+ accessorVars.add(spec.local.name);
943
+ }
944
+ }
945
+ },
946
+ VariableDeclarator: recordAccessorVar,
947
+ JSXOpeningElement(node) {
948
+ if (!isComponentName(node.name)) return;
949
+ for (const attr of node.attributes ?? []) {
950
+ if (attr.type !== "JSXSpreadAttribute") continue;
951
+ const expr = attr.argument;
952
+ if (!expr) continue;
953
+ if (shouldWarnForSpreadExpr(expr)) {
954
+ context.report({
955
+ node: attr,
956
+ messageId: "unsafeSpread"
957
+ });
958
+ }
959
+ }
960
+ }
961
+ };
962
+ }
963
+ };
964
+ var no_unsafe_props_spread_default = rule11;
965
+
966
+ // src/rules/no-unsupported-props-destructure.ts
967
+ var rule12 = {
968
+ meta: {
969
+ type: "suggestion",
970
+ docs: {
971
+ description: "Warn on unsupported props destructuring patterns in components",
972
+ recommended: true
973
+ },
974
+ messages: {
975
+ computedKey: "Computed property in props pattern cannot be made reactive.",
976
+ arrayRest: "Array rest in props destructuring falls back to non-reactive binding.",
977
+ nestedRest: "Nested props rest destructuring falls back to non-reactive binding; access props directly or use prop.",
978
+ nonFirstParam: "Props destructuring is only supported in the first parameter.",
979
+ fallback: "Props destructuring falls back to non-reactive binding."
980
+ },
981
+ schema: []
982
+ },
983
+ create(context) {
984
+ const isComponentName = (name) => /^[A-Z]/.test(name);
985
+ const getPropsPattern = (fnNode) => {
986
+ const params = fnNode?.params ?? [];
987
+ const first = params[0];
988
+ if (params.length > 1) {
989
+ params.slice(1).forEach((param) => {
990
+ if (!param) return;
991
+ const target = param.type === "AssignmentPattern" ? param.left : param;
992
+ if (target?.type === "ObjectPattern" || target?.type === "ArrayPattern") {
993
+ context.report({
994
+ node: target,
995
+ messageId: "nonFirstParam"
996
+ });
997
+ }
998
+ });
999
+ }
1000
+ if (!first) return null;
1001
+ if (first.type === "ObjectPattern") return first;
1002
+ if (first.type === "AssignmentPattern" && first.left?.type === "ObjectPattern") {
1003
+ return first.left;
1004
+ }
1005
+ if (first.type === "ArrayPattern") {
1006
+ context.report({
1007
+ node: first,
1008
+ messageId: "fallback"
1009
+ });
1010
+ return null;
1011
+ }
1012
+ return null;
1013
+ };
1014
+ const reportOnce = (node, messageId) => {
1015
+ context.report({
1016
+ node,
1017
+ messageId
1018
+ });
1019
+ };
1020
+ const walkPattern = (pattern, depth) => {
1021
+ if (!pattern) return;
1022
+ if (pattern.type === "ObjectPattern") {
1023
+ for (const prop of pattern.properties ?? []) {
1024
+ if (prop.type === "RestElement") {
1025
+ if (depth > 0) {
1026
+ reportOnce(prop, "nestedRest");
1027
+ }
1028
+ continue;
1029
+ }
1030
+ if (prop.type !== "Property") {
1031
+ reportOnce(prop, "fallback");
1032
+ continue;
1033
+ }
1034
+ if (prop.computed) {
1035
+ reportOnce(prop, "computedKey");
1036
+ continue;
1037
+ }
1038
+ const value = prop.value;
1039
+ if (value.type === "Identifier") {
1040
+ continue;
1041
+ }
1042
+ if (value.type === "AssignmentPattern" && value.left?.type === "Identifier") {
1043
+ continue;
1044
+ }
1045
+ if (value.type === "ObjectPattern") {
1046
+ walkPattern(value, depth + 1);
1047
+ continue;
1048
+ }
1049
+ if (value.type === "ArrayPattern") {
1050
+ const hasRest = (value.elements ?? []).some((el) => el?.type === "RestElement");
1051
+ reportOnce(value, hasRest ? "arrayRest" : "fallback");
1052
+ continue;
1053
+ }
1054
+ reportOnce(value, "fallback");
1055
+ }
1056
+ return;
1057
+ }
1058
+ if (pattern.type === "ArrayPattern") {
1059
+ reportOnce(pattern, "fallback");
1060
+ }
1061
+ };
1062
+ return {
1063
+ FunctionDeclaration(node) {
1064
+ if (!node.id?.name || !isComponentName(node.id.name)) return;
1065
+ const pattern = getPropsPattern(node);
1066
+ if (pattern) walkPattern(pattern, 0);
1067
+ },
1068
+ VariableDeclarator(node) {
1069
+ if (!node.id || node.id.type !== "Identifier" || !isComponentName(node.id.name)) return;
1070
+ if (!node.init) return;
1071
+ if (node.init.type !== "ArrowFunctionExpression" && node.init.type !== "FunctionExpression") {
1072
+ return;
1073
+ }
1074
+ const pattern = getPropsPattern(node.init);
1075
+ if (pattern) walkPattern(pattern, 0);
1076
+ }
1077
+ };
1078
+ }
1079
+ };
1080
+ var no_unsupported_props_destructure_default = rule12;
696
1081
 
697
1082
  // src/rules/require-component-return.ts
698
- var rule9 = {
1083
+ var rule13 = {
699
1084
  meta: {
700
1085
  type: "problem",
701
1086
  docs: {
@@ -783,10 +1168,10 @@ var rule9 = {
783
1168
  };
784
1169
  }
785
1170
  };
786
- var require_component_return_default = rule9;
1171
+ var require_component_return_default = rule13;
787
1172
 
788
1173
  // src/rules/require-list-key.ts
789
- var rule10 = {
1174
+ var rule14 = {
790
1175
  meta: {
791
1176
  type: "problem",
792
1177
  docs: {
@@ -877,7 +1262,7 @@ var rule10 = {
877
1262
  };
878
1263
  }
879
1264
  };
880
- var require_list_key_default = rule10;
1265
+ var require_list_key_default = rule14;
881
1266
 
882
1267
  // src/index.ts
883
1268
  var plugin = {
@@ -889,10 +1274,14 @@ var plugin = {
889
1274
  "no-state-in-loop": no_state_in_loop_default,
890
1275
  "no-direct-mutation": no_direct_mutation_default,
891
1276
  "no-empty-effect": no_empty_effect_default,
1277
+ "no-computed-props-key": no_computed_props_key_default,
892
1278
  "no-inline-functions": no_inline_functions_default,
893
1279
  "no-state-destructure-write": no_state_destructure_write_default,
894
1280
  "no-state-outside-component": no_state_outside_component_default,
895
1281
  "no-nested-components": no_nested_components_default,
1282
+ "no-third-party-props-spread": no_third_party_props_spread_default,
1283
+ "no-unsafe-props-spread": no_unsafe_props_spread_default,
1284
+ "no-unsupported-props-destructure": no_unsupported_props_destructure_default,
896
1285
  "require-list-key": require_list_key_default,
897
1286
  "no-memo-side-effects": no_memo_side_effects_default,
898
1287
  "require-component-return": require_component_return_default
@@ -905,12 +1294,16 @@ var plugin = {
905
1294
  "fict/no-direct-mutation": "warn",
906
1295
  "fict/no-empty-effect": "warn",
907
1296
  // FICT-E001
1297
+ "fict/no-computed-props-key": "warn",
908
1298
  "fict/no-inline-functions": "warn",
909
1299
  // FICT-X003
910
1300
  "fict/no-state-destructure-write": "error",
911
1301
  "fict/no-state-outside-component": "error",
912
1302
  "fict/no-nested-components": "error",
913
1303
  // FICT-C003
1304
+ "fict/no-third-party-props-spread": "warn",
1305
+ "fict/no-unsafe-props-spread": "warn",
1306
+ "fict/no-unsupported-props-destructure": "warn",
914
1307
  "fict/require-list-key": "error",
915
1308
  // FICT-J002
916
1309
  "fict/no-memo-side-effects": "warn",
@@ -924,6 +1317,7 @@ var plugin = {
924
1317
  var index_default = plugin;
925
1318
  // Annotate the CommonJS export names for ESM import in node:
926
1319
  0 && (module.exports = {
1320
+ noComputedPropsKey,
927
1321
  noDirectMutation,
928
1322
  noEmptyEffect,
929
1323
  noInlineFunctions,
@@ -932,6 +1326,9 @@ var index_default = plugin;
932
1326
  noStateDestructureWrite,
933
1327
  noStateInLoop,
934
1328
  noStateOutsideComponent,
1329
+ noThirdPartyPropsSpread,
1330
+ noUnsafePropsSpread,
1331
+ noUnsupportedPropsDestructure,
935
1332
  requireComponentReturn,
936
1333
  requireListKey
937
1334
  });