@ngrx/eslint-plugin 21.0.1 → 21.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ngrx/eslint-plugin",
3
- "version": "21.0.1",
3
+ "version": "21.1.0",
4
4
  "description": "NgRx ESLint Plugin",
5
5
  "repository": {
6
6
  "type": "git",
@@ -45,7 +45,7 @@
45
45
  "strip-json-comments": "3.1.1"
46
46
  },
47
47
  "peerDependencies": {
48
- "eslint": "^8.57.0 || ^9.0.0",
48
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
49
49
  "typescript": "*",
50
50
  "typescript-eslint": "^8.0.0",
51
51
  "@typescript-eslint/utils": "^8.0.0"
@@ -82,7 +82,11 @@ exports.default = (0, rule_creator_1.createRule)({
82
82
  else if (argument) {
83
83
  const services = utils_1.ESLintUtils.getParserServices(context);
84
84
  const typeChecker = services.program.getTypeChecker();
85
- const type = services.getTypeAtLocation(argument);
85
+ let type = services.getTypeAtLocation(argument);
86
+ const callSignatures = type.getCallSignatures();
87
+ if (callSignatures.length > 0) {
88
+ type = typeChecker.getReturnTypeOfSignature(callSignatures[0]);
89
+ }
86
90
  if (typeChecker.isArrayType(type) || typeChecker.isTupleType(type)) {
87
91
  context.report({
88
92
  node: argument,
@@ -100,8 +104,7 @@ exports.default = (0, rule_creator_1.createRule)({
100
104
  });
101
105
  return;
102
106
  }
103
- const callSignatures = type.getCallSignatures();
104
- if (callSignatures.length > 0) {
107
+ if (type.getCallSignatures().length > 0) {
105
108
  context.report({
106
109
  node: argument,
107
110
  messageId: exports.messageId,
@@ -110,6 +113,14 @@ exports.default = (0, rule_creator_1.createRule)({
110
113
  return;
111
114
  }
112
115
  const typeString = typeChecker.typeToString(type);
116
+ if (typeString === 'void') {
117
+ context.report({
118
+ node: argument,
119
+ messageId: exports.messageId,
120
+ data: { property: 'Function' },
121
+ });
122
+ return;
123
+ }
113
124
  const matchedType = NON_RECORD_TYPES.find((t) => typeString.startsWith(`${t}<`));
114
125
  if (matchedType) {
115
126
  context.report({
@@ -1 +1 @@
1
- {"version":3,"file":"with-state-no-arrays-at-root-level.js","sourceRoot":"","sources":["../../../../../../modules/eslint-plugin/src/rules/signals/with-state-no-arrays-at-root-level.ts"],"names":[],"mappings":"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","sourcesContent":["import { ESLintUtils, type TSESTree } from '@typescript-eslint/utils';\nimport * as path from 'path';\nimport { createRule } from '../../rule-creator';\nimport { isArrayExpression } from '../../utils';\n\nexport const messageId = 'withStateNoArraysAtRootLevel';\n\ntype MessageIds = typeof messageId;\ntype Options = readonly [];\n\nconst NON_RECORD_TYPES = [\n 'Array',\n 'Set',\n 'Map',\n 'WeakSet',\n 'WeakMap',\n 'Date',\n 'Error',\n 'RegExp',\n 'ArrayBuffer',\n 'DataView',\n 'Promise',\n 'Function',\n];\n\nexport default createRule<Options, MessageIds>({\n name: path.parse(__filename).name,\n meta: {\n type: 'problem',\n docs: {\n description: `withState should accept a record or dictionary as an input argument.`,\n ngrxModule: 'signals',\n requiresTypeChecking: true,\n },\n schema: [],\n messages: {\n [messageId]:\n 'The property type `{{ property }}` is forbidden as the initial state argument, wrap the property in a record or dictionary.',\n },\n },\n defaultOptions: [],\n create: (context) => {\n return {\n [`CallExpression[callee.name=withState]`](node: TSESTree.CallExpression) {\n const [argument] = node.arguments;\n if (isArrayExpression(argument)) {\n context.report({\n node: argument,\n messageId,\n data: { property: 'Array' },\n });\n } else if (argument) {\n const services = ESLintUtils.getParserServices(context);\n const typeChecker = services.program.getTypeChecker();\n const type = services.getTypeAtLocation(argument);\n\n if (typeChecker.isArrayType(type) || typeChecker.isTupleType(type)) {\n context.report({\n node: argument,\n messageId,\n data: { property: 'Array' },\n });\n return;\n }\n\n const symbol = type.getSymbol();\n if (symbol && NON_RECORD_TYPES.includes(symbol.getName())) {\n context.report({\n node: argument,\n messageId,\n data: { property: symbol.getName() },\n });\n return;\n }\n\n const callSignatures = type.getCallSignatures();\n if (callSignatures.length > 0) {\n context.report({\n node: argument,\n messageId,\n data: { property: 'Function' },\n });\n return;\n }\n\n const typeString = typeChecker.typeToString(type);\n const matchedType = NON_RECORD_TYPES.find((t) =>\n typeString.startsWith(`${t}<`)\n );\n if (matchedType) {\n context.report({\n node: argument,\n messageId,\n data: { property: matchedType },\n });\n }\n }\n },\n };\n },\n});\n"]}
1
+ {"version":3,"file":"with-state-no-arrays-at-root-level.js","sourceRoot":"","sources":["../../../../../../modules/eslint-plugin/src/rules/signals/with-state-no-arrays-at-root-level.ts"],"names":[],"mappings":"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","sourcesContent":["import { ESLintUtils, type TSESTree } from '@typescript-eslint/utils';\nimport * as path from 'path';\nimport { createRule } from '../../rule-creator';\nimport { isArrayExpression } from '../../utils';\n\nexport const messageId = 'withStateNoArraysAtRootLevel';\n\ntype MessageIds = typeof messageId;\ntype Options = readonly [];\n\nconst NON_RECORD_TYPES = [\n 'Array',\n 'Set',\n 'Map',\n 'WeakSet',\n 'WeakMap',\n 'Date',\n 'Error',\n 'RegExp',\n 'ArrayBuffer',\n 'DataView',\n 'Promise',\n 'Function',\n];\n\nexport default createRule<Options, MessageIds>({\n name: path.parse(__filename).name,\n meta: {\n type: 'problem',\n docs: {\n description: `withState should accept a record or dictionary as an input argument.`,\n ngrxModule: 'signals',\n requiresTypeChecking: true,\n },\n schema: [],\n messages: {\n [messageId]:\n 'The property type `{{ property }}` is forbidden as the initial state argument, wrap the property in a record or dictionary.',\n },\n },\n defaultOptions: [],\n create: (context) => {\n return {\n [`CallExpression[callee.name=withState]`](node: TSESTree.CallExpression) {\n const [argument] = node.arguments;\n if (isArrayExpression(argument)) {\n context.report({\n node: argument,\n messageId,\n data: { property: 'Array' },\n });\n } else if (argument) {\n const services = ESLintUtils.getParserServices(context);\n const typeChecker = services.program.getTypeChecker();\n\n let type = services.getTypeAtLocation(argument);\n const callSignatures = type.getCallSignatures();\n if (callSignatures.length > 0) {\n type = typeChecker.getReturnTypeOfSignature(callSignatures[0]);\n }\n\n if (typeChecker.isArrayType(type) || typeChecker.isTupleType(type)) {\n context.report({\n node: argument,\n messageId,\n data: { property: 'Array' },\n });\n return;\n }\n\n const symbol = type.getSymbol();\n if (symbol && NON_RECORD_TYPES.includes(symbol.getName())) {\n context.report({\n node: argument,\n messageId,\n data: { property: symbol.getName() },\n });\n return;\n }\n\n if (type.getCallSignatures().length > 0) {\n context.report({\n node: argument,\n messageId,\n data: { property: 'Function' },\n });\n return;\n }\n\n const typeString = typeChecker.typeToString(type);\n\n if (typeString === 'void') {\n context.report({\n node: argument,\n messageId,\n data: { property: 'Function' },\n });\n return;\n }\n\n const matchedType = NON_RECORD_TYPES.find((t) =>\n typeString.startsWith(`${t}<`)\n );\n if (matchedType) {\n context.report({\n node: argument,\n messageId,\n data: { property: matchedType },\n });\n }\n }\n },\n };\n },\n});\n"]}
@@ -80,7 +80,7 @@ exports.default = (0, rule_creator_1.createRule)({
80
80
  data: { name: suggestedName },
81
81
  fix: (fixer) => {
82
82
  const parent = node.parent;
83
- const sourceCode = context.getSourceCode();
83
+ const sourceCode = context.sourceCode ?? context.getSourceCode();
84
84
  // Handle destructuring: { selectAll: allItems }
85
85
  if (parent &&
86
86
  parent.type === 'Property' &&
@@ -1 +1 @@
1
- {"version":3,"file":"prefix-selectors-with-select.js","sourceRoot":"","sources":["../../../../../../modules/eslint-plugin/src/rules/store/prefix-selectors-with-select.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport * as path from 'path';\nimport { createRule } from '../../rule-creator';\nimport { capitalize } from '../../utils';\n\nexport const prefixSelectorsWithSelect = 'prefixSelectorsWithSelect';\nexport const prefixSelectorsWithSelectSuggest =\n 'prefixSelectorsWithSelectSuggest';\n\ntype MessageIds =\n | typeof prefixSelectorsWithSelect\n | typeof prefixSelectorsWithSelectSuggest;\ntype Options = readonly [];\n\nexport default createRule<Options, MessageIds>({\n name: path.parse(__filename).name,\n meta: {\n type: 'suggestion',\n hasSuggestions: true,\n docs: {\n description:\n 'The selector should start with \"select\", for example \"selectEntity\".',\n ngrxModule: 'store',\n },\n schema: [],\n messages: {\n [prefixSelectorsWithSelect]: 'The selector should start with \"select\".',\n [prefixSelectorsWithSelectSuggest]:\n 'Prefix the selector with \"select\": `{{ name }}`.',\n },\n },\n defaultOptions: [],\n create: (context) => {\n function reportIfInvalid(name: string, node: TSESTree.Identifier) {\n // Name starts with select and\n // the first character after select is an uppercase ASCII letter, _, or $\n const isValid =\n name.startsWith('select') &&\n name.length > 'select'.length &&\n /^[A-Z_$]/.test(name.slice('select'.length));\n\n if (!isValid) {\n const suggestedName = getSuggestedName(name);\n context.report({\n node,\n loc: {\n start: node.loc.start,\n end: {\n line: node.loc.start.line,\n column: node.loc.start.column + name.length,\n },\n },\n messageId: prefixSelectorsWithSelect,\n suggest: [\n {\n messageId: prefixSelectorsWithSelectSuggest,\n data: { name: suggestedName },\n fix: (fixer) => {\n const parent = node.parent;\n const sourceCode = context.getSourceCode();\n\n // Handle destructuring: { selectAll: allItems }\n if (\n parent &&\n parent.type === 'Property' &&\n parent.value === node &&\n parent.parent &&\n parent.parent.type === 'ObjectPattern'\n ) {\n return fixer.replaceText(node, suggestedName);\n }\n\n // Handle simple variable declarator: const allItems = ...\n if (\n parent &&\n parent.type === 'VariableDeclarator' &&\n parent.id.type === 'Identifier'\n ) {\n const typeAnnotation = parent.id.typeAnnotation\n ? sourceCode.getText(parent.id.typeAnnotation)\n : '';\n return fixer.replaceText(\n parent.id,\n `${suggestedName}${typeAnnotation}`\n );\n }\n\n // Fallback: just replace the identifier\n return fixer.replaceText(node, suggestedName);\n },\n },\n ],\n });\n }\n }\n\n function isSelectorFactoryCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee;\n return (\n callee.type === 'Identifier' &&\n [\n 'createSelector',\n 'createFeatureSelector',\n 'createSelectorFactory',\n ].includes(callee.name)\n );\n }\n\n function checkFunctionBody(\n name: string,\n node: TSESTree.Identifier,\n body: TSESTree.BlockStatement | TSESTree.Expression\n ) {\n if (body.type === 'CallExpression' && isSelectorFactoryCall(body)) {\n reportIfInvalid(name, node);\n }\n\n if (body.type === 'BlockStatement') {\n for (const stmt of body.body) {\n if (\n stmt.type === 'ReturnStatement' &&\n stmt.argument &&\n stmt.argument.type === 'CallExpression' &&\n isSelectorFactoryCall(stmt.argument)\n ) {\n reportIfInvalid(name, node);\n }\n }\n }\n }\n\n return {\n VariableDeclarator(node: TSESTree.VariableDeclarator) {\n const { id, init } = node;\n\n const isSelectorSource =\n init?.type === 'CallExpression' &&\n ((init.callee.type === 'Identifier' &&\n init.callee.name === 'getSelectors') ||\n (init.callee.type === 'MemberExpression' &&\n init.callee.property.type === 'Identifier' &&\n init.callee.property.name === 'getSelectors'));\n\n if (id.type === 'ObjectPattern' && isSelectorSource) {\n for (const prop of id.properties) {\n if (prop.type === 'Property' && prop.value.type === 'Identifier') {\n reportIfInvalid(prop.value.name, prop.value);\n }\n }\n return;\n }\n\n if (id.type === 'Identifier') {\n const typeName =\n node.id.typeAnnotation?.typeAnnotation.type === 'TSTypeReference' &&\n node.id.typeAnnotation.typeAnnotation.typeName.type === 'Identifier'\n ? node.id.typeAnnotation.typeAnnotation.typeName.name\n : null;\n\n const hasSelectorType =\n typeName !== null &&\n [\n 'MemoizedSelector',\n 'MemoizedSelectorWithProps',\n 'Selector',\n 'SelectorWithProps',\n ].includes(typeName);\n\n const isSelectorCall =\n init?.type === 'CallExpression' && isSelectorFactoryCall(init);\n\n const isArrowFunction =\n init?.type === 'ArrowFunctionExpression' &&\n init.body &&\n (init.body.type === 'CallExpression' ||\n init.body.type === 'BlockStatement');\n\n const isFunctionExpression =\n init?.type === 'FunctionExpression' &&\n init.body &&\n init.body.type === 'BlockStatement';\n\n if (hasSelectorType || isSelectorCall) {\n reportIfInvalid(id.name, id);\n } else if (isArrowFunction || isFunctionExpression) {\n checkFunctionBody(id.name, id, init.body);\n }\n }\n },\n };\n },\n});\n\nfunction getSuggestedName(name: string): string {\n const selectWord = 'select';\n\n if (name.startsWith(selectWord)) {\n const rest = name.slice(selectWord.length);\n if (rest.length === 0) {\n return 'selectSelect';\n }\n if (/^[A-Z_]+$/.test(rest)) {\n return `${selectWord}${rest}`;\n }\n return `${selectWord}${capitalize(rest)}`;\n }\n\n if (/^get([^a-z].+)/.test(name)) {\n const rest = name.slice(3);\n return `${selectWord}${capitalize(rest)}`;\n }\n\n if (/^[A-Z_]+$/.test(name)) {\n return `${selectWord}${name}`;\n }\n\n return `${selectWord}${capitalize(name)}`;\n}\n"]}
1
+ {"version":3,"file":"prefix-selectors-with-select.js","sourceRoot":"","sources":["../../../../../../modules/eslint-plugin/src/rules/store/prefix-selectors-with-select.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport * as path from 'path';\nimport { createRule } from '../../rule-creator';\nimport { capitalize } from '../../utils';\n\nexport const prefixSelectorsWithSelect = 'prefixSelectorsWithSelect';\nexport const prefixSelectorsWithSelectSuggest =\n 'prefixSelectorsWithSelectSuggest';\n\ntype MessageIds =\n | typeof prefixSelectorsWithSelect\n | typeof prefixSelectorsWithSelectSuggest;\ntype Options = readonly [];\n\nexport default createRule<Options, MessageIds>({\n name: path.parse(__filename).name,\n meta: {\n type: 'suggestion',\n hasSuggestions: true,\n docs: {\n description:\n 'The selector should start with \"select\", for example \"selectEntity\".',\n ngrxModule: 'store',\n },\n schema: [],\n messages: {\n [prefixSelectorsWithSelect]: 'The selector should start with \"select\".',\n [prefixSelectorsWithSelectSuggest]:\n 'Prefix the selector with \"select\": `{{ name }}`.',\n },\n },\n defaultOptions: [],\n create: (context) => {\n function reportIfInvalid(name: string, node: TSESTree.Identifier) {\n // Name starts with select and\n // the first character after select is an uppercase ASCII letter, _, or $\n const isValid =\n name.startsWith('select') &&\n name.length > 'select'.length &&\n /^[A-Z_$]/.test(name.slice('select'.length));\n\n if (!isValid) {\n const suggestedName = getSuggestedName(name);\n context.report({\n node,\n loc: {\n start: node.loc.start,\n end: {\n line: node.loc.start.line,\n column: node.loc.start.column + name.length,\n },\n },\n messageId: prefixSelectorsWithSelect,\n suggest: [\n {\n messageId: prefixSelectorsWithSelectSuggest,\n data: { name: suggestedName },\n fix: (fixer) => {\n const parent = node.parent;\n const sourceCode =\n context.sourceCode ?? context.getSourceCode();\n\n // Handle destructuring: { selectAll: allItems }\n if (\n parent &&\n parent.type === 'Property' &&\n parent.value === node &&\n parent.parent &&\n parent.parent.type === 'ObjectPattern'\n ) {\n return fixer.replaceText(node, suggestedName);\n }\n\n // Handle simple variable declarator: const allItems = ...\n if (\n parent &&\n parent.type === 'VariableDeclarator' &&\n parent.id.type === 'Identifier'\n ) {\n const typeAnnotation = parent.id.typeAnnotation\n ? sourceCode.getText(parent.id.typeAnnotation)\n : '';\n return fixer.replaceText(\n parent.id,\n `${suggestedName}${typeAnnotation}`\n );\n }\n\n // Fallback: just replace the identifier\n return fixer.replaceText(node, suggestedName);\n },\n },\n ],\n });\n }\n }\n\n function isSelectorFactoryCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee;\n return (\n callee.type === 'Identifier' &&\n [\n 'createSelector',\n 'createFeatureSelector',\n 'createSelectorFactory',\n ].includes(callee.name)\n );\n }\n\n function checkFunctionBody(\n name: string,\n node: TSESTree.Identifier,\n body: TSESTree.BlockStatement | TSESTree.Expression\n ) {\n if (body.type === 'CallExpression' && isSelectorFactoryCall(body)) {\n reportIfInvalid(name, node);\n }\n\n if (body.type === 'BlockStatement') {\n for (const stmt of body.body) {\n if (\n stmt.type === 'ReturnStatement' &&\n stmt.argument &&\n stmt.argument.type === 'CallExpression' &&\n isSelectorFactoryCall(stmt.argument)\n ) {\n reportIfInvalid(name, node);\n }\n }\n }\n }\n\n return {\n VariableDeclarator(node: TSESTree.VariableDeclarator) {\n const { id, init } = node;\n\n const isSelectorSource =\n init?.type === 'CallExpression' &&\n ((init.callee.type === 'Identifier' &&\n init.callee.name === 'getSelectors') ||\n (init.callee.type === 'MemberExpression' &&\n init.callee.property.type === 'Identifier' &&\n init.callee.property.name === 'getSelectors'));\n\n if (id.type === 'ObjectPattern' && isSelectorSource) {\n for (const prop of id.properties) {\n if (prop.type === 'Property' && prop.value.type === 'Identifier') {\n reportIfInvalid(prop.value.name, prop.value);\n }\n }\n return;\n }\n\n if (id.type === 'Identifier') {\n const typeName =\n node.id.typeAnnotation?.typeAnnotation.type === 'TSTypeReference' &&\n node.id.typeAnnotation.typeAnnotation.typeName.type === 'Identifier'\n ? node.id.typeAnnotation.typeAnnotation.typeName.name\n : null;\n\n const hasSelectorType =\n typeName !== null &&\n [\n 'MemoizedSelector',\n 'MemoizedSelectorWithProps',\n 'Selector',\n 'SelectorWithProps',\n ].includes(typeName);\n\n const isSelectorCall =\n init?.type === 'CallExpression' && isSelectorFactoryCall(init);\n\n const isArrowFunction =\n init?.type === 'ArrowFunctionExpression' &&\n init.body &&\n (init.body.type === 'CallExpression' ||\n init.body.type === 'BlockStatement');\n\n const isFunctionExpression =\n init?.type === 'FunctionExpression' &&\n init.body &&\n init.body.type === 'BlockStatement';\n\n if (hasSelectorType || isSelectorCall) {\n reportIfInvalid(id.name, id);\n } else if (isArrowFunction || isFunctionExpression) {\n checkFunctionBody(id.name, id, init.body);\n }\n }\n },\n };\n },\n});\n\nfunction getSuggestedName(name: string): string {\n const selectWord = 'select';\n\n if (name.startsWith(selectWord)) {\n const rest = name.slice(selectWord.length);\n if (rest.length === 0) {\n return 'selectSelect';\n }\n if (/^[A-Z_]+$/.test(rest)) {\n return `${selectWord}${rest}`;\n }\n return `${selectWord}${capitalize(rest)}`;\n }\n\n if (/^get([^a-z].+)/.test(name)) {\n const rest = name.slice(3);\n return `${selectWord}${capitalize(rest)}`;\n }\n\n if (/^[A-Z_]+$/.test(name)) {\n return `${selectWord}${name}`;\n }\n\n return `${selectWord}${capitalize(name)}`;\n}\n"]}