@violetflux/eslint-plugin-kerros 0.3.2 → 0.3.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/dist/index.cjs CHANGED
@@ -736,7 +736,10 @@ const noBroadStoreAccess = createRule({
736
736
  docs: { description: "Prevent broad enumeration and serialization of complete Store snapshots." },
737
737
  schema: [{
738
738
  type: "object",
739
- properties: { includeObjectFields: { type: "boolean" } },
739
+ properties: {
740
+ includeObjectFields: { type: "boolean" },
741
+ includeStoreModels: { type: "boolean" }
742
+ },
740
743
  additionalProperties: false
741
744
  }],
742
745
  messages: {
@@ -744,10 +747,31 @@ const noBroadStoreAccess = createRule({
744
747
  broadObjectField: "Do not enumerate, serialize, or spread an object field from a selector-free Store snapshot."
745
748
  }
746
749
  },
747
- defaultOptions: [{ includeObjectFields: false }],
750
+ defaultOptions: [{
751
+ includeObjectFields: false,
752
+ includeStoreModels: false
753
+ }],
748
754
  create(context, [options]) {
749
- const { getIdentifierSymbol, getType, isStoreHookCall } = createKerrosTypeTools(context);
755
+ const { getFactoryKind, getIdentifierSymbol, getType, isStoreHookCall } = createKerrosTypeTools(context);
750
756
  const origins = createReferenceOriginTracker(context.sourceCode.ast);
757
+ const storeModels = /* @__PURE__ */ new Set();
758
+ const pendingReports = [];
759
+ /** Test whether an expression belongs to a function registered as a createStore model. */
760
+ const isInsideStoreModel = (expression) => {
761
+ let node = expression.parent;
762
+ while (node) {
763
+ if (node.type === "FunctionDeclaration" && node.id) {
764
+ const symbol = getIdentifierSymbol(node.id);
765
+ return symbol ? storeModels.has(symbol) : false;
766
+ }
767
+ if ((node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression") && node.parent.type === "VariableDeclarator" && node.parent.id.type === "Identifier") {
768
+ const symbol = getIdentifierSymbol(node.parent.id);
769
+ return symbol ? storeModels.has(symbol) : false;
770
+ }
771
+ node = node.parent;
772
+ }
773
+ return false;
774
+ };
751
775
  /** Classify whether an expression is a complete Store snapshot or one object field from it. */
752
776
  const readStoreOrigin = (input, seen = /* @__PURE__ */ new Set()) => {
753
777
  const node = unwrapExpression(input);
@@ -777,12 +801,12 @@ const noBroadStoreAccess = createRule({
777
801
  /** Report one operation that subscribes to every enumerable field. */
778
802
  const reportBroadAccess = (expression) => {
779
803
  const origin = readStoreOrigin(expression);
780
- if (origin === "snapshot") context.report({
781
- node: expression,
804
+ if (origin === "snapshot") pendingReports.push({
805
+ expression,
782
806
  messageId: "broadAccess"
783
807
  });
784
- else if (origin === "objectField" && options.includeObjectFields) context.report({
785
- node: expression,
808
+ else if (origin === "objectField" && options.includeObjectFields) pendingReports.push({
809
+ expression,
786
810
  messageId: "broadObjectField"
787
811
  });
788
812
  };
@@ -812,6 +836,13 @@ const noBroadStoreAccess = createRule({
812
836
  };
813
837
  return {
814
838
  CallExpression(node) {
839
+ if (getFactoryKind(node) === "createStore") {
840
+ const model = node.arguments[0];
841
+ if (model?.type === "Identifier") {
842
+ const symbol = getIdentifierSymbol(model);
843
+ if (symbol) storeModels.add(symbol);
844
+ }
845
+ }
815
846
  const argument = getBroadArgument(node);
816
847
  if (argument) reportBroadAccess(argument);
817
848
  },
@@ -838,6 +869,15 @@ const noBroadStoreAccess = createRule({
838
869
  expression: node.right,
839
870
  objectField: false
840
871
  }, node);
872
+ },
873
+ "Program:exit"() {
874
+ for (const { expression, messageId } of pendingReports) {
875
+ if (!options.includeStoreModels && isInsideStoreModel(expression)) continue;
876
+ context.report({
877
+ node: expression,
878
+ messageId
879
+ });
880
+ }
841
881
  }
842
882
  };
843
883
  }
@@ -2501,7 +2541,7 @@ const rules = {
2501
2541
  const plugin = {
2502
2542
  meta: {
2503
2543
  name: "@violetflux/eslint-plugin-kerros",
2504
- version: "0.3.2"
2544
+ version: "0.3.3"
2505
2545
  },
2506
2546
  rules
2507
2547
  };
package/dist/index.mjs CHANGED
@@ -708,7 +708,10 @@ const noBroadStoreAccess = createRule({
708
708
  docs: { description: "Prevent broad enumeration and serialization of complete Store snapshots." },
709
709
  schema: [{
710
710
  type: "object",
711
- properties: { includeObjectFields: { type: "boolean" } },
711
+ properties: {
712
+ includeObjectFields: { type: "boolean" },
713
+ includeStoreModels: { type: "boolean" }
714
+ },
712
715
  additionalProperties: false
713
716
  }],
714
717
  messages: {
@@ -716,10 +719,31 @@ const noBroadStoreAccess = createRule({
716
719
  broadObjectField: "Do not enumerate, serialize, or spread an object field from a selector-free Store snapshot."
717
720
  }
718
721
  },
719
- defaultOptions: [{ includeObjectFields: false }],
722
+ defaultOptions: [{
723
+ includeObjectFields: false,
724
+ includeStoreModels: false
725
+ }],
720
726
  create(context, [options]) {
721
- const { getIdentifierSymbol, getType, isStoreHookCall } = createKerrosTypeTools(context);
727
+ const { getFactoryKind, getIdentifierSymbol, getType, isStoreHookCall } = createKerrosTypeTools(context);
722
728
  const origins = createReferenceOriginTracker(context.sourceCode.ast);
729
+ const storeModels = /* @__PURE__ */ new Set();
730
+ const pendingReports = [];
731
+ /** Test whether an expression belongs to a function registered as a createStore model. */
732
+ const isInsideStoreModel = (expression) => {
733
+ let node = expression.parent;
734
+ while (node) {
735
+ if (node.type === "FunctionDeclaration" && node.id) {
736
+ const symbol = getIdentifierSymbol(node.id);
737
+ return symbol ? storeModels.has(symbol) : false;
738
+ }
739
+ if ((node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression") && node.parent.type === "VariableDeclarator" && node.parent.id.type === "Identifier") {
740
+ const symbol = getIdentifierSymbol(node.parent.id);
741
+ return symbol ? storeModels.has(symbol) : false;
742
+ }
743
+ node = node.parent;
744
+ }
745
+ return false;
746
+ };
723
747
  /** Classify whether an expression is a complete Store snapshot or one object field from it. */
724
748
  const readStoreOrigin = (input, seen = /* @__PURE__ */ new Set()) => {
725
749
  const node = unwrapExpression(input);
@@ -749,12 +773,12 @@ const noBroadStoreAccess = createRule({
749
773
  /** Report one operation that subscribes to every enumerable field. */
750
774
  const reportBroadAccess = (expression) => {
751
775
  const origin = readStoreOrigin(expression);
752
- if (origin === "snapshot") context.report({
753
- node: expression,
776
+ if (origin === "snapshot") pendingReports.push({
777
+ expression,
754
778
  messageId: "broadAccess"
755
779
  });
756
- else if (origin === "objectField" && options.includeObjectFields) context.report({
757
- node: expression,
780
+ else if (origin === "objectField" && options.includeObjectFields) pendingReports.push({
781
+ expression,
758
782
  messageId: "broadObjectField"
759
783
  });
760
784
  };
@@ -784,6 +808,13 @@ const noBroadStoreAccess = createRule({
784
808
  };
785
809
  return {
786
810
  CallExpression(node) {
811
+ if (getFactoryKind(node) === "createStore") {
812
+ const model = node.arguments[0];
813
+ if (model?.type === "Identifier") {
814
+ const symbol = getIdentifierSymbol(model);
815
+ if (symbol) storeModels.add(symbol);
816
+ }
817
+ }
787
818
  const argument = getBroadArgument(node);
788
819
  if (argument) reportBroadAccess(argument);
789
820
  },
@@ -810,6 +841,15 @@ const noBroadStoreAccess = createRule({
810
841
  expression: node.right,
811
842
  objectField: false
812
843
  }, node);
844
+ },
845
+ "Program:exit"() {
846
+ for (const { expression, messageId } of pendingReports) {
847
+ if (!options.includeStoreModels && isInsideStoreModel(expression)) continue;
848
+ context.report({
849
+ node: expression,
850
+ messageId
851
+ });
852
+ }
813
853
  }
814
854
  };
815
855
  }
@@ -2473,7 +2513,7 @@ const rules = {
2473
2513
  const plugin = {
2474
2514
  meta: {
2475
2515
  name: "@violetflux/eslint-plugin-kerros",
2476
- version: "0.3.2"
2516
+ version: "0.3.3"
2477
2517
  },
2478
2518
  rules
2479
2519
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@violetflux/eslint-plugin-kerros",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Type-aware ESLint rules for Kerros stores.",
5
5
  "repository": {
6
6
  "type": "git",