@ngrx/eslint-plugin 14.0.0-beta.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/jest.config.js +22 -0
- package/jest.config.js.map +1 -0
- package/migrations/migration.json +3 -0
- package/package.json +51 -0
- package/schematics/collection.json +10 -0
- package/schematics/ng-add/index.js +51 -0
- package/schematics/ng-add/index.js.map +1 -0
- package/schematics/ng-add/schema.js +3 -0
- package/schematics/ng-add/schema.js.map +1 -0
- package/schematics/ng-add/schema.json +87 -0
- package/scripts/generate-config.js +85 -0
- package/scripts/generate-config.js.map +1 -0
- package/scripts/generate-docs.js +90 -0
- package/scripts/generate-docs.js.map +1 -0
- package/scripts/generate-overview.js +98 -0
- package/scripts/generate-overview.js.map +1 -0
- package/spec/utils/index.js +22 -0
- package/spec/utils/index.js.map +1 -0
- package/src/configs/all-requiring-type-checking.js +46 -0
- package/src/configs/all-requiring-type-checking.js.map +1 -0
- package/src/configs/all.js +39 -0
- package/src/configs/all.js.map +1 -0
- package/src/configs/component-store-strict.js +11 -0
- package/src/configs/component-store-strict.js.map +1 -0
- package/src/configs/component-store.js +11 -0
- package/src/configs/component-store.js.map +1 -0
- package/src/configs/effects-requiring-type-checking.js +27 -0
- package/src/configs/effects-requiring-type-checking.js.map +1 -0
- package/src/configs/effects-strict-requiring-type-checking.js +27 -0
- package/src/configs/effects-strict-requiring-type-checking.js.map +1 -0
- package/src/configs/effects-strict.js +20 -0
- package/src/configs/effects-strict.js.map +1 -0
- package/src/configs/effects.js +20 -0
- package/src/configs/effects.js.map +1 -0
- package/src/configs/index.js +33 -0
- package/src/configs/index.js.map +1 -0
- package/src/configs/recommended-requiring-type-checking.js +46 -0
- package/src/configs/recommended-requiring-type-checking.js.map +1 -0
- package/src/configs/recommended.js +39 -0
- package/src/configs/recommended.js.map +1 -0
- package/src/configs/store-strict.js +30 -0
- package/src/configs/store-strict.js.map +1 -0
- package/src/configs/store.js +30 -0
- package/src/configs/store.js.map +1 -0
- package/src/configs/strict-requiring-type-checking.js +46 -0
- package/src/configs/strict-requiring-type-checking.js.map +1 -0
- package/src/configs/strict.js +39 -0
- package/src/configs/strict.js.map +1 -0
- package/src/index.js +8 -0
- package/src/index.js.map +1 -0
- package/src/rule-creator.js +29 -0
- package/src/rule-creator.js.map +1 -0
- package/src/rules/component-store/updater-explicit-return-type.js +69 -0
- package/src/rules/component-store/updater-explicit-return-type.js.map +1 -0
- package/src/rules/effects/avoid-cyclic-effects.js +202 -0
- package/src/rules/effects/avoid-cyclic-effects.js.map +1 -0
- package/src/rules/effects/no-dispatch-in-effects.js +83 -0
- package/src/rules/effects/no-dispatch-in-effects.js.map +1 -0
- package/src/rules/effects/no-effect-decorator-and-creator.js +107 -0
- package/src/rules/effects/no-effect-decorator-and-creator.js.map +1 -0
- package/src/rules/effects/no-effect-decorator.js +124 -0
- package/src/rules/effects/no-effect-decorator.js.map +1 -0
- package/src/rules/effects/no-effects-in-providers.js +105 -0
- package/src/rules/effects/no-effects-in-providers.js.map +1 -0
- package/src/rules/effects/no-multiple-actions-in-effects.js +77 -0
- package/src/rules/effects/no-multiple-actions-in-effects.js.map +1 -0
- package/src/rules/effects/prefer-action-creator-in-of-type.js +58 -0
- package/src/rules/effects/prefer-action-creator-in-of-type.js.map +1 -0
- package/src/rules/effects/prefer-concat-latest-from.js +153 -0
- package/src/rules/effects/prefer-concat-latest-from.js.map +1 -0
- package/src/rules/effects/prefer-effect-callback-in-block-statement.js +99 -0
- package/src/rules/effects/prefer-effect-callback-in-block-statement.js.map +1 -0
- package/src/rules/effects/use-effects-lifecycle-interface.js +88 -0
- package/src/rules/effects/use-effects-lifecycle-interface.js.map +1 -0
- package/src/rules/index.js +59 -0
- package/src/rules/index.js.map +1 -0
- package/src/rules/store/avoid-combining-selectors.js +65 -0
- package/src/rules/store/avoid-combining-selectors.js.map +1 -0
- package/src/rules/store/avoid-dispatching-multiple-actions-sequentially.js +95 -0
- package/src/rules/store/avoid-dispatching-multiple-actions-sequentially.js.map +1 -0
- package/src/rules/store/avoid-duplicate-actions-in-reducer.js +150 -0
- package/src/rules/store/avoid-duplicate-actions-in-reducer.js.map +1 -0
- package/src/rules/store/avoid-mapping-selectors.js +82 -0
- package/src/rules/store/avoid-mapping-selectors.js.map +1 -0
- package/src/rules/store/good-action-hygiene.js +84 -0
- package/src/rules/store/good-action-hygiene.js.map +1 -0
- package/src/rules/store/no-multiple-global-stores.js +157 -0
- package/src/rules/store/no-multiple-global-stores.js.map +1 -0
- package/src/rules/store/no-reducer-in-key-names.js +76 -0
- package/src/rules/store/no-reducer-in-key-names.js.map +1 -0
- package/src/rules/store/no-store-subscription.js +64 -0
- package/src/rules/store/no-store-subscription.js.map +1 -0
- package/src/rules/store/no-typed-global-store.js +101 -0
- package/src/rules/store/no-typed-global-store.js.map +1 -0
- package/src/rules/store/on-function-explicit-return-type.js +106 -0
- package/src/rules/store/on-function-explicit-return-type.js.map +1 -0
- package/src/rules/store/prefer-action-creator-in-dispatch.js +70 -0
- package/src/rules/store/prefer-action-creator-in-dispatch.js.map +1 -0
- package/src/rules/store/prefer-action-creator.js +58 -0
- package/src/rules/store/prefer-action-creator.js.map +1 -0
- package/src/rules/store/prefer-inline-action-props.js +72 -0
- package/src/rules/store/prefer-inline-action-props.js.map +1 -0
- package/src/rules/store/prefer-one-generic-in-create-for-feature-selector.js +93 -0
- package/src/rules/store/prefer-one-generic-in-create-for-feature-selector.js.map +1 -0
- package/src/rules/store/prefer-selector-in-select.js +93 -0
- package/src/rules/store/prefer-selector-in-select.js.map +1 -0
- package/src/rules/store/prefix-selectors-with-select.js +107 -0
- package/src/rules/store/prefix-selectors-with-select.js.map +1 -0
- package/src/rules/store/select-style.js +196 -0
- package/src/rules/store/select-style.js.map +1 -0
- package/src/rules/store/use-consistent-global-store-name.js +139 -0
- package/src/rules/store/use-consistent-global-store-name.js.map +1 -0
- package/src/utils/helper-functions/docs.js +8 -0
- package/src/utils/helper-functions/docs.js.map +1 -0
- package/src/utils/helper-functions/folder.js +118 -0
- package/src/utils/helper-functions/folder.js.map +1 -0
- package/src/utils/helper-functions/guards.js +56 -0
- package/src/utils/helper-functions/guards.js.map +1 -0
- package/src/utils/helper-functions/index.js +23 -0
- package/src/utils/helper-functions/index.js.map +1 -0
- package/src/utils/helper-functions/ngrx-modules.js +10 -0
- package/src/utils/helper-functions/ngrx-modules.js.map +1 -0
- package/src/utils/helper-functions/utils.js +302 -0
- package/src/utils/helper-functions/utils.js.map +1 -0
- package/src/utils/helper-functions/versions.js +70 -0
- package/src/utils/helper-functions/versions.js.map +1 -0
- package/src/utils/index.js +19 -0
- package/src/utils/index.js.map +1 -0
- package/src/utils/selectors/index.js +58 -0
- package/src/utils/selectors/index.js.map +1 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
exports.__esModule = true;
|
|
14
|
+
exports.createRule = void 0;
|
|
15
|
+
var experimental_utils_1 = require("@typescript-eslint/experimental-utils");
|
|
16
|
+
var utils_1 = require("./utils");
|
|
17
|
+
function createRule(config) {
|
|
18
|
+
var configOverwrite = __assign(__assign({}, config), { create: function (context, optionsWithDefault) {
|
|
19
|
+
var _a = config.meta, ngrxModule = _a.ngrxModule, version = _a.version;
|
|
20
|
+
if (version !== undefined &&
|
|
21
|
+
!(0, utils_1.ngrxVersionSatisfies)(utils_1.NGRX_MODULE_PATHS[ngrxModule], version)) {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
return config.create(context, optionsWithDefault);
|
|
25
|
+
} });
|
|
26
|
+
return experimental_utils_1.ESLintUtils.RuleCreator(utils_1.docsUrl)(configOverwrite);
|
|
27
|
+
}
|
|
28
|
+
exports.createRule = createRule;
|
|
29
|
+
//# sourceMappingURL=rule-creator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-creator.js","sourceRoot":"","sources":["../../../../modules/eslint-plugin/src/rule-creator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AACA,4EAAoE;AAEpE,iCAA2E;AAiB3E,SAAgB,UAAU,CAIxB,MAQE;IAEF,IAAM,eAAe,yBAChB,MAAM,KACT,MAAM,EAAE,UACN,OAA8D,EAC9D,kBAAsC;YAGpC,IAAA,KACE,MAAM,KADqB,EAArB,UAAU,gBAAA,EAAE,OAAO,aAAE,CACpB;YACX,IACE,OAAO,KAAK,SAAS;gBACrB,CAAC,IAAA,4BAAoB,EAAC,yBAAiB,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,EAC7D;gBACA,OAAO,EAAE,CAAC;aACX;YAED,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;QACpD,CAAC,GACF,CAAC;IAEF,OAAO,gCAAW,CAAC,WAAW,CAAC,eAAO,CAAC,CAAC,eAAe,CAAC,CAAC;AAC3D,CAAC;AAnCD,gCAmCC","sourcesContent":["import type { TSESLint } from '@typescript-eslint/experimental-utils';\nimport { ESLintUtils } from '@typescript-eslint/experimental-utils';\nimport type { NGRX_MODULE } from './utils';\nimport { docsUrl, ngrxVersionSatisfies, NGRX_MODULE_PATHS } from './utils';\n\ntype Meta<TMessageIds extends string> =\n | TSESLint.RuleMetaData<TMessageIds> & {\n ngrxModule: NGRX_MODULE;\n version?: string;\n };\ntype CreateRuleMeta<TMessageIds extends string> = {\n docs: Omit<TSESLint.RuleMetaDataDocs, 'url'>;\n} & Omit<Meta<TMessageIds>, 'docs'>;\nexport type NgRxRuleModule<\n TOptions extends readonly unknown[],\n TMessageIds extends string\n> = Omit<TSESLint.RuleModule<TMessageIds, TOptions>, 'meta'> & {\n meta: Meta<TMessageIds>;\n};\n\nexport function createRule<\n TOptions extends readonly unknown[],\n TMessageIds extends string\n>(\n config: Readonly<{\n name: string;\n meta: CreateRuleMeta<TMessageIds>;\n defaultOptions: Readonly<TOptions>;\n create: (\n context: Readonly<TSESLint.RuleContext<TMessageIds, TOptions>>,\n optionsWithDefault: Readonly<TOptions>\n ) => TSESLint.RuleListener;\n }>\n): TSESLint.RuleModule<TMessageIds, TOptions> {\n const configOverwrite = {\n ...config,\n create: (\n context: Readonly<TSESLint.RuleContext<TMessageIds, TOptions>>,\n optionsWithDefault: Readonly<TOptions>\n ) => {\n const {\n meta: { ngrxModule, version },\n } = config;\n if (\n version !== undefined &&\n !ngrxVersionSatisfies(NGRX_MODULE_PATHS[ngrxModule], version)\n ) {\n return {};\n }\n\n return config.create(context, optionsWithDefault);\n },\n };\n\n return ESLintUtils.RuleCreator(docsUrl)(configOverwrite);\n}\n"]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var _a;
|
|
26
|
+
exports.__esModule = true;
|
|
27
|
+
exports.messageId = void 0;
|
|
28
|
+
var path = __importStar(require("path"));
|
|
29
|
+
var rule_creator_1 = require("../../rule-creator");
|
|
30
|
+
var utils_1 = require("../../utils");
|
|
31
|
+
exports.messageId = 'updaterExplicitReturnType';
|
|
32
|
+
exports["default"] = (0, rule_creator_1.createRule)({
|
|
33
|
+
name: path.parse(__filename).name,
|
|
34
|
+
meta: {
|
|
35
|
+
type: 'problem',
|
|
36
|
+
ngrxModule: 'component-store',
|
|
37
|
+
docs: {
|
|
38
|
+
description: '`Updater` should have an explicit return type.',
|
|
39
|
+
recommended: 'warn'
|
|
40
|
+
},
|
|
41
|
+
schema: [],
|
|
42
|
+
messages: (_a = {},
|
|
43
|
+
_a[exports.messageId] = '`Updater` should have an explicit return type when using arrow functions: `this.store.updater((state, value): State => {}`.',
|
|
44
|
+
_a)
|
|
45
|
+
},
|
|
46
|
+
defaultOptions: [],
|
|
47
|
+
create: function (context) {
|
|
48
|
+
var _a;
|
|
49
|
+
var _b = (0, utils_1.getNgRxComponentStores)(context).identifiers, identifiers = _b === void 0 ? [] : _b;
|
|
50
|
+
var storeNames = identifiers.length > 0 ? (0, utils_1.asPattern)(identifiers) : null;
|
|
51
|
+
var withoutTypeAnnotation = "ArrowFunctionExpression:not([returnType.typeAnnotation])";
|
|
52
|
+
var selectors = [
|
|
53
|
+
"ClassDeclaration[superClass.name='ComponentStore'] CallExpression[callee.object.type='ThisExpression'][callee.property.name='updater'] > ".concat(withoutTypeAnnotation),
|
|
54
|
+
storeNames &&
|
|
55
|
+
"".concat((0, utils_1.namedExpression)(storeNames), "[callee.property.name='updater'] > ").concat(withoutTypeAnnotation),
|
|
56
|
+
]
|
|
57
|
+
.filter(Boolean)
|
|
58
|
+
.join(',');
|
|
59
|
+
return _a = {},
|
|
60
|
+
_a[selectors] = function (node) {
|
|
61
|
+
context.report({
|
|
62
|
+
node: node,
|
|
63
|
+
messageId: exports.messageId
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
_a;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=updater-explicit-return-type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updater-explicit-return-type.js","sourceRoot":"","sources":["../../../../../../modules/eslint-plugin/src/rules/component-store/updater-explicit-return-type.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,yCAA6B;AAC7B,mDAAgD;AAChD,qCAIqB;AAER,QAAA,SAAS,GAAG,2BAA2B,CAAC;AAKrD,qBAAe,IAAA,yBAAU,EAAsB;IAC7C,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI;IACjC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,iBAAiB;QAC7B,IAAI,EAAE;YACJ,WAAW,EAAE,gDAAgD;YAC7D,WAAW,EAAE,MAAM;SACpB;QACD,MAAM,EAAE,EAAE;QACV,QAAQ;YACN,GAAC,iBAAS,IACR,6HAA6H;eAChI;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,EAAE,UAAC,OAAO;;QACN,IAAA,KAAqB,IAAA,8BAAsB,EAAC,OAAO,CAAC,YAApC,EAAhB,WAAW,mBAAG,EAAE,KAAA,CAAqC;QAC7D,IAAM,UAAU,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAA,iBAAS,EAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1E,IAAM,qBAAqB,GAAG,0DAA0D,CAAC;QACzF,IAAM,SAAS,GAAG;YAChB,mJAA4I,qBAAqB,CAAE;YACnK,UAAU;gBACR,UAAG,IAAA,uBAAe,EAChB,UAAU,CACX,gDAAsC,qBAAqB,CAAE;SACjE;aACE,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,GAAG,CAAC,CAAC;QAEb;YACE,GAAC,SAAS,IAAV,UAAY,IAAsC;gBAChD,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,MAAA;oBACJ,SAAS,mBAAA;iBACV,CAAC,CAAC;YACL,CAAC;eACD;IACJ,CAAC;CACF,CAAC,CAAC","sourcesContent":["import type { TSESTree } from '@typescript-eslint/experimental-utils';\nimport * as path from 'path';\nimport { createRule } from '../../rule-creator';\nimport {\n asPattern,\n getNgRxComponentStores,\n namedExpression,\n} from '../../utils';\n\nexport const messageId = 'updaterExplicitReturnType';\n\ntype MessageIds = typeof messageId;\ntype Options = readonly [];\n\nexport default createRule<Options, MessageIds>({\n name: path.parse(__filename).name,\n meta: {\n type: 'problem',\n ngrxModule: 'component-store',\n docs: {\n description: '`Updater` should have an explicit return type.',\n recommended: 'warn',\n },\n schema: [],\n messages: {\n [messageId]:\n '`Updater` should have an explicit return type when using arrow functions: `this.store.updater((state, value): State => {}`.',\n },\n },\n defaultOptions: [],\n create: (context) => {\n const { identifiers = [] } = getNgRxComponentStores(context);\n const storeNames = identifiers.length > 0 ? asPattern(identifiers) : null;\n const withoutTypeAnnotation = `ArrowFunctionExpression:not([returnType.typeAnnotation])`;\n const selectors = [\n `ClassDeclaration[superClass.name='ComponentStore'] CallExpression[callee.object.type='ThisExpression'][callee.property.name='updater'] > ${withoutTypeAnnotation}`,\n storeNames &&\n `${namedExpression(\n storeNames\n )}[callee.property.name='updater'] > ${withoutTypeAnnotation}`,\n ]\n .filter(Boolean)\n .join(',');\n\n return {\n [selectors](node: TSESTree.ArrowFunctionExpression) {\n context.report({\n node,\n messageId,\n });\n },\n };\n },\n});\n"]}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
26
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
27
|
+
if (!m) return o;
|
|
28
|
+
var i = m.call(o), r, ar = [], e;
|
|
29
|
+
try {
|
|
30
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
31
|
+
}
|
|
32
|
+
catch (error) { e = { error: error }; }
|
|
33
|
+
finally {
|
|
34
|
+
try {
|
|
35
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
36
|
+
}
|
|
37
|
+
finally { if (e) throw e.error; }
|
|
38
|
+
}
|
|
39
|
+
return ar;
|
|
40
|
+
};
|
|
41
|
+
var __values = (this && this.__values) || function(o) {
|
|
42
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
43
|
+
if (m) return m.call(o);
|
|
44
|
+
if (o && typeof o.length === "number") return {
|
|
45
|
+
next: function () {
|
|
46
|
+
if (o && i >= o.length) o = void 0;
|
|
47
|
+
return { value: o && o[i++], done: !o };
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
51
|
+
};
|
|
52
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
53
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
54
|
+
if (ar || !(i in from)) {
|
|
55
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
56
|
+
ar[i] = from[i];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
60
|
+
};
|
|
61
|
+
var _a;
|
|
62
|
+
exports.__esModule = true;
|
|
63
|
+
exports.messageId = void 0;
|
|
64
|
+
var eslint_etc_1 = require("eslint-etc");
|
|
65
|
+
var path = __importStar(require("path"));
|
|
66
|
+
var ts = __importStar(require("typescript"));
|
|
67
|
+
var rule_creator_1 = require("../../rule-creator");
|
|
68
|
+
var utils_1 = require("../../utils");
|
|
69
|
+
exports.messageId = 'avoidCyclicEffects';
|
|
70
|
+
// This rule is a modified version (to support dispatch: false) from the eslint-plugin-rxjs plugin.
|
|
71
|
+
// The original implementation can be found at https://github.com/cartant/eslint-plugin-rxjs/blob/main/source/rules/no-cyclic-action.ts
|
|
72
|
+
// Thank you Nicholas Jamieson (@cartant).
|
|
73
|
+
exports["default"] = (0, rule_creator_1.createRule)({
|
|
74
|
+
name: path.parse(__filename).name,
|
|
75
|
+
meta: {
|
|
76
|
+
type: 'problem',
|
|
77
|
+
ngrxModule: 'effects',
|
|
78
|
+
docs: {
|
|
79
|
+
description: 'Avoid `Effect` that re-emit filtered actions.',
|
|
80
|
+
recommended: 'warn',
|
|
81
|
+
requiresTypeChecking: true
|
|
82
|
+
},
|
|
83
|
+
schema: [],
|
|
84
|
+
messages: (_a = {},
|
|
85
|
+
_a[exports.messageId] = '`Effect` that re-emit filtered actions are forbidden.',
|
|
86
|
+
_a)
|
|
87
|
+
},
|
|
88
|
+
defaultOptions: [],
|
|
89
|
+
create: function (context) {
|
|
90
|
+
var _a;
|
|
91
|
+
var _b = (0, utils_1.getNgRxEffectActions)(context).identifiers, identifiers = _b === void 0 ? [] : _b;
|
|
92
|
+
var actionsNames = identifiers.length > 0 ? (0, utils_1.asPattern)(identifiers) : null;
|
|
93
|
+
if (!actionsNames) {
|
|
94
|
+
return {};
|
|
95
|
+
}
|
|
96
|
+
var _c = (0, eslint_etc_1.getTypeServices)(context), getType = _c.getType, typeChecker = _c.typeChecker;
|
|
97
|
+
function checkNode(pipeCallExpression) {
|
|
98
|
+
var e_1, _a;
|
|
99
|
+
var operatorCallExpression = pipeCallExpression.arguments.find(function (arg) {
|
|
100
|
+
return (0, utils_1.isCallExpression)(arg) &&
|
|
101
|
+
(0, utils_1.isIdentifier)(arg.callee) &&
|
|
102
|
+
arg.callee.name === 'ofType';
|
|
103
|
+
});
|
|
104
|
+
if (!operatorCallExpression) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
var operatorType = getType(operatorCallExpression);
|
|
108
|
+
var _b = __read(typeChecker.getSignaturesOfType(operatorType, ts.SignatureKind.Call), 1), signature = _b[0];
|
|
109
|
+
if (!signature) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
var operatorReturnType = typeChecker.getReturnTypeOfSignature(signature);
|
|
113
|
+
if (!(0, utils_1.isTypeReference)(operatorReturnType)) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
var _c = __read(typeChecker.getTypeArguments(operatorReturnType), 1), operatorElementType = _c[0];
|
|
117
|
+
if (!operatorElementType) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
var pipeType = getType(pipeCallExpression);
|
|
121
|
+
if (!(0, utils_1.isTypeReference)(pipeType)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
var _d = __read(typeChecker.getTypeArguments(pipeType), 1), pipeElementType = _d[0];
|
|
125
|
+
if (!pipeElementType) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
var operatorActionTypes = getActionTypes(operatorElementType);
|
|
129
|
+
var pipeActionTypes = getActionTypes(pipeElementType);
|
|
130
|
+
try {
|
|
131
|
+
for (var operatorActionTypes_1 = __values(operatorActionTypes), operatorActionTypes_1_1 = operatorActionTypes_1.next(); !operatorActionTypes_1_1.done; operatorActionTypes_1_1 = operatorActionTypes_1.next()) {
|
|
132
|
+
var actionType = operatorActionTypes_1_1.value;
|
|
133
|
+
if (pipeActionTypes.includes(actionType)) {
|
|
134
|
+
context.report({
|
|
135
|
+
node: pipeCallExpression.callee,
|
|
136
|
+
messageId: exports.messageId
|
|
137
|
+
});
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
143
|
+
finally {
|
|
144
|
+
try {
|
|
145
|
+
if (operatorActionTypes_1_1 && !operatorActionTypes_1_1.done && (_a = operatorActionTypes_1["return"])) _a.call(operatorActionTypes_1);
|
|
146
|
+
}
|
|
147
|
+
finally { if (e_1) throw e_1.error; }
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function getActionType(symbol) {
|
|
151
|
+
var valueDeclaration = symbol.valueDeclaration;
|
|
152
|
+
if (!valueDeclaration) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
if (valueDeclaration.kind === ts.SyntaxKind.PropertyDeclaration) {
|
|
156
|
+
var parent_1 = symbol.parent;
|
|
157
|
+
return parent_1.valueDeclaration
|
|
158
|
+
? typeChecker.getTypeOfSymbolAtLocation(parent_1, parent_1.valueDeclaration)
|
|
159
|
+
: null;
|
|
160
|
+
}
|
|
161
|
+
return typeChecker.getTypeOfSymbolAtLocation(symbol, valueDeclaration);
|
|
162
|
+
}
|
|
163
|
+
function getActionTypes(type) {
|
|
164
|
+
var e_2, _a;
|
|
165
|
+
if (type.isUnion()) {
|
|
166
|
+
var memberActionTypes = [];
|
|
167
|
+
try {
|
|
168
|
+
for (var _b = __values(type.types), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
169
|
+
var memberType = _c.value;
|
|
170
|
+
memberActionTypes.push.apply(memberActionTypes, __spreadArray([], __read(getActionTypes(memberType)), false));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
174
|
+
finally {
|
|
175
|
+
try {
|
|
176
|
+
if (_c && !_c.done && (_a = _b["return"])) _a.call(_b);
|
|
177
|
+
}
|
|
178
|
+
finally { if (e_2) throw e_2.error; }
|
|
179
|
+
}
|
|
180
|
+
return memberActionTypes;
|
|
181
|
+
}
|
|
182
|
+
var symbol = typeChecker.getPropertyOfType(type, 'type');
|
|
183
|
+
if (!symbol) {
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
var actionType = getActionType(symbol);
|
|
187
|
+
if (!actionType) {
|
|
188
|
+
return [];
|
|
189
|
+
}
|
|
190
|
+
// TODO: support "dynamic" types
|
|
191
|
+
// e.g. const genericFoo = createAction(`${subject} FOO`); (resolves to 'string')
|
|
192
|
+
if (typeChecker.typeToString(actionType) === 'string') {
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
return [typeChecker.typeToString(actionType)];
|
|
196
|
+
}
|
|
197
|
+
return _a = {},
|
|
198
|
+
_a["".concat(utils_1.createEffectExpression, ":not([arguments.1]:has(Property[key.name='dispatch'][value.value=false])) CallExpression[callee.property.name='pipe'][callee.object.property.name=").concat(actionsNames, "]")] = checkNode,
|
|
199
|
+
_a;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
//# sourceMappingURL=avoid-cyclic-effects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avoid-cyclic-effects.js","sourceRoot":"","sources":["../../../../../../modules/eslint-plugin/src/rules/effects/avoid-cyclic-effects.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TSESTree } from '@typescript-eslint/experimental-utils';\nimport { getTypeServices } from 'eslint-etc';\nimport * as path from 'path';\nimport * as ts from 'typescript';\nimport { createRule } from '../../rule-creator';\nimport {\n asPattern,\n createEffectExpression,\n getNgRxEffectActions,\n isCallExpression,\n isIdentifier,\n isTypeReference,\n} from '../../utils';\n\nexport const messageId = 'avoidCyclicEffects';\n\ntype MessageIds = typeof messageId;\ntype Options = readonly [];\n\n// This rule is a modified version (to support dispatch: false) from the eslint-plugin-rxjs plugin.\n// The original implementation can be found at https://github.com/cartant/eslint-plugin-rxjs/blob/main/source/rules/no-cyclic-action.ts\n// Thank you Nicholas Jamieson (@cartant).\n\nexport default createRule<Options, MessageIds>({\n name: path.parse(__filename).name,\n meta: {\n type: 'problem',\n ngrxModule: 'effects',\n docs: {\n description: 'Avoid `Effect` that re-emit filtered actions.',\n recommended: 'warn',\n requiresTypeChecking: true,\n },\n schema: [],\n messages: {\n [messageId]: '`Effect` that re-emit filtered actions are forbidden.',\n },\n },\n defaultOptions: [],\n create: (context) => {\n const { identifiers = [] } = getNgRxEffectActions(context);\n const actionsNames = identifiers.length > 0 ? asPattern(identifiers) : null;\n\n if (!actionsNames) {\n return {};\n }\n\n const { getType, typeChecker } = getTypeServices(context);\n\n function checkNode(pipeCallExpression: TSESTree.CallExpression) {\n const operatorCallExpression = pipeCallExpression.arguments.find(\n (arg) =>\n isCallExpression(arg) &&\n isIdentifier(arg.callee) &&\n arg.callee.name === 'ofType'\n );\n if (!operatorCallExpression) {\n return;\n }\n const operatorType = getType(operatorCallExpression);\n const [signature] = typeChecker.getSignaturesOfType(\n operatorType,\n ts.SignatureKind.Call\n );\n\n if (!signature) {\n return;\n }\n const operatorReturnType =\n typeChecker.getReturnTypeOfSignature(signature);\n if (!isTypeReference(operatorReturnType)) {\n return;\n }\n const [operatorElementType] =\n typeChecker.getTypeArguments(operatorReturnType);\n if (!operatorElementType) {\n return;\n }\n\n const pipeType = getType(pipeCallExpression);\n if (!isTypeReference(pipeType)) {\n return;\n }\n const [pipeElementType] = typeChecker.getTypeArguments(pipeType);\n if (!pipeElementType) {\n return;\n }\n\n const operatorActionTypes = getActionTypes(operatorElementType);\n const pipeActionTypes = getActionTypes(pipeElementType);\n\n for (const actionType of operatorActionTypes) {\n if (pipeActionTypes.includes(actionType)) {\n context.report({\n node: pipeCallExpression.callee,\n messageId,\n });\n return;\n }\n }\n }\n\n function getActionType(symbol: ts.Symbol): ts.Type | null {\n const { valueDeclaration } = symbol;\n\n if (!valueDeclaration) {\n return null;\n }\n\n if (valueDeclaration.kind === ts.SyntaxKind.PropertyDeclaration) {\n const { parent } = symbol as typeof symbol & { parent: ts.Symbol };\n return parent.valueDeclaration\n ? typeChecker.getTypeOfSymbolAtLocation(\n parent,\n parent.valueDeclaration\n )\n : null;\n }\n\n return typeChecker.getTypeOfSymbolAtLocation(symbol, valueDeclaration);\n }\n\n function getActionTypes(type: ts.Type): string[] {\n if (type.isUnion()) {\n const memberActionTypes: string[] = [];\n for (const memberType of type.types) {\n memberActionTypes.push(...getActionTypes(memberType));\n }\n return memberActionTypes;\n }\n\n const symbol = typeChecker.getPropertyOfType(type, 'type');\n\n if (!symbol) {\n return [];\n }\n\n const actionType = getActionType(symbol);\n\n if (!actionType) {\n return [];\n }\n\n // TODO: support \"dynamic\" types\n // e.g. const genericFoo = createAction(`${subject} FOO`); (resolves to 'string')\n if (typeChecker.typeToString(actionType) === 'string') {\n return [];\n }\n return [typeChecker.typeToString(actionType)];\n }\n\n return {\n [`${createEffectExpression}:not([arguments.1]:has(Property[key.name='dispatch'][value.value=false])) CallExpression[callee.property.name='pipe'][callee.object.property.name=${actionsNames}]`]:\n checkNode,\n };\n },\n});\n"]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var _a;
|
|
26
|
+
exports.__esModule = true;
|
|
27
|
+
exports.noDispatchInEffectsSuggest = exports.noDispatchInEffects = void 0;
|
|
28
|
+
var path = __importStar(require("path"));
|
|
29
|
+
var rule_creator_1 = require("../../rule-creator");
|
|
30
|
+
var utils_1 = require("../../utils");
|
|
31
|
+
exports.noDispatchInEffects = 'noDispatchInEffects';
|
|
32
|
+
exports.noDispatchInEffectsSuggest = 'noDispatchInEffectsSuggest';
|
|
33
|
+
exports["default"] = (0, rule_creator_1.createRule)({
|
|
34
|
+
name: path.parse(__filename).name,
|
|
35
|
+
meta: {
|
|
36
|
+
type: 'suggestion',
|
|
37
|
+
ngrxModule: 'effects',
|
|
38
|
+
hasSuggestions: true,
|
|
39
|
+
docs: {
|
|
40
|
+
description: '`Effect` should not call `store.dispatch`.',
|
|
41
|
+
recommended: 'warn',
|
|
42
|
+
suggestion: true
|
|
43
|
+
},
|
|
44
|
+
schema: [],
|
|
45
|
+
messages: (_a = {},
|
|
46
|
+
_a[exports.noDispatchInEffects] = 'Calling `store.dispatch` in `Effect` is forbidden.',
|
|
47
|
+
_a[exports.noDispatchInEffectsSuggest] = 'Remove `store.dispatch`.',
|
|
48
|
+
_a)
|
|
49
|
+
},
|
|
50
|
+
defaultOptions: [],
|
|
51
|
+
create: function (context) {
|
|
52
|
+
var _a;
|
|
53
|
+
var _b = (0, utils_1.getNgRxStores)(context).identifiers, identifiers = _b === void 0 ? [] : _b;
|
|
54
|
+
var storeNames = identifiers.length > 0 ? (0, utils_1.asPattern)(identifiers) : null;
|
|
55
|
+
if (!storeNames) {
|
|
56
|
+
return {};
|
|
57
|
+
}
|
|
58
|
+
return _a = {},
|
|
59
|
+
_a[(0, utils_1.dispatchInEffects)(storeNames)] = function (node) {
|
|
60
|
+
var nodeToReport = getNodeToReport(node);
|
|
61
|
+
context.report({
|
|
62
|
+
node: nodeToReport,
|
|
63
|
+
messageId: exports.noDispatchInEffects,
|
|
64
|
+
suggest: [
|
|
65
|
+
{
|
|
66
|
+
messageId: exports.noDispatchInEffectsSuggest,
|
|
67
|
+
fix: function (fixer) { return fixer.remove(nodeToReport); }
|
|
68
|
+
},
|
|
69
|
+
]
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
_a;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
function getNodeToReport(node) {
|
|
76
|
+
var parent = node.parent;
|
|
77
|
+
var grandParent = parent.parent;
|
|
78
|
+
return grandParent &&
|
|
79
|
+
((0, utils_1.isArrowFunctionExpression)(grandParent) || (0, utils_1.isReturnStatement)(grandParent))
|
|
80
|
+
? node
|
|
81
|
+
: parent;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=no-dispatch-in-effects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-dispatch-in-effects.js","sourceRoot":"","sources":["../../../../../../modules/eslint-plugin/src/rules/effects/no-dispatch-in-effects.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,yCAA6B;AAC7B,mDAAgD;AAChD,qCAMqB;AAER,QAAA,mBAAmB,GAAG,qBAAqB,CAAC;AAC5C,QAAA,0BAA0B,GAAG,4BAA4B,CAAC;AAUvE,qBAAe,IAAA,yBAAU,EAAsB;IAC7C,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI;IACjC,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,UAAU,EAAE,SAAS;QACrB,cAAc,EAAE,IAAI;QACpB,IAAI,EAAE;YACJ,WAAW,EAAE,4CAA4C;YACzD,WAAW,EAAE,MAAM;YACnB,UAAU,EAAE,IAAI;SACjB;QACD,MAAM,EAAE,EAAE;QACV,QAAQ;YACN,GAAC,2BAAmB,IAClB,oDAAoD;YACtD,GAAC,kCAA0B,IAAG,0BAA0B;eACzD;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,EAAE,UAAC,OAAO;;QACN,IAAA,KAAqB,IAAA,qBAAa,EAAC,OAAO,CAAC,YAA3B,EAAhB,WAAW,mBAAG,EAAE,KAAA,CAA4B;QACpD,IAAM,UAAU,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAA,iBAAS,EAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAE1E,IAAI,CAAC,UAAU,EAAE;YACf,OAAO,EAAE,CAAC;SACX;QAED;YACE,GAAC,IAAA,yBAAiB,EAAC,UAAU,CAAC,IAA9B,UACE,IAA0C;gBAE1C,IAAM,YAAY,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;gBAC3C,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,YAAY;oBAClB,SAAS,EAAE,2BAAmB;oBAC9B,OAAO,EAAE;wBACP;4BACE,SAAS,EAAE,kCAA0B;4BACrC,GAAG,EAAE,UAAC,KAAK,IAAK,OAAA,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,EAA1B,CAA0B;yBAC3C;qBACF;iBACF,CAAC,CAAC;YACL,CAAC;eACD;IACJ,CAAC;CACF,CAAC,CAAC;AAEH,SAAS,eAAe,CAAC,IAA0C;IACzD,IAAA,MAAM,GAAK,IAAI,OAAT,CAAU;IAChB,IAAQ,WAAW,GAAK,MAAM,OAAX,CAAY;IACvC,OAAO,WAAW;QAChB,CAAC,IAAA,iCAAyB,EAAC,WAAW,CAAC,IAAI,IAAA,yBAAiB,EAAC,WAAW,CAAC,CAAC;QAC1E,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,MAAM,CAAC;AACb,CAAC","sourcesContent":["import type { TSESTree } from '@typescript-eslint/experimental-utils';\nimport * as path from 'path';\nimport { createRule } from '../../rule-creator';\nimport {\n asPattern,\n dispatchInEffects,\n getNgRxStores,\n isArrowFunctionExpression,\n isReturnStatement,\n} from '../../utils';\n\nexport const noDispatchInEffects = 'noDispatchInEffects';\nexport const noDispatchInEffectsSuggest = 'noDispatchInEffectsSuggest';\n\ntype MessageIds =\n | typeof noDispatchInEffects\n | typeof noDispatchInEffectsSuggest;\ntype Options = readonly [];\ntype MemberExpressionWithinCallExpression = TSESTree.MemberExpression & {\n parent: TSESTree.CallExpression;\n};\n\nexport default createRule<Options, MessageIds>({\n name: path.parse(__filename).name,\n meta: {\n type: 'suggestion',\n ngrxModule: 'effects',\n hasSuggestions: true,\n docs: {\n description: '`Effect` should not call `store.dispatch`.',\n recommended: 'warn',\n suggestion: true,\n },\n schema: [],\n messages: {\n [noDispatchInEffects]:\n 'Calling `store.dispatch` in `Effect` is forbidden.',\n [noDispatchInEffectsSuggest]: 'Remove `store.dispatch`.',\n },\n },\n defaultOptions: [],\n create: (context) => {\n const { identifiers = [] } = getNgRxStores(context);\n const storeNames = identifiers.length > 0 ? asPattern(identifiers) : null;\n\n if (!storeNames) {\n return {};\n }\n\n return {\n [dispatchInEffects(storeNames)](\n node: MemberExpressionWithinCallExpression\n ) {\n const nodeToReport = getNodeToReport(node);\n context.report({\n node: nodeToReport,\n messageId: noDispatchInEffects,\n suggest: [\n {\n messageId: noDispatchInEffectsSuggest,\n fix: (fixer) => fixer.remove(nodeToReport),\n },\n ],\n });\n },\n };\n },\n});\n\nfunction getNodeToReport(node: MemberExpressionWithinCallExpression) {\n const { parent } = node;\n const { parent: grandParent } = parent;\n return grandParent &&\n (isArrowFunctionExpression(grandParent) || isReturnStatement(grandParent))\n ? node\n : parent;\n}\n"]}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var _a;
|
|
26
|
+
exports.__esModule = true;
|
|
27
|
+
exports.noEffectDecoratorAndCreatorSuggest = exports.noEffectDecoratorAndCreator = void 0;
|
|
28
|
+
var path = __importStar(require("path"));
|
|
29
|
+
var rule_creator_1 = require("../../rule-creator");
|
|
30
|
+
var utils_1 = require("../../utils");
|
|
31
|
+
exports.noEffectDecoratorAndCreator = 'noEffectDecoratorAndCreator';
|
|
32
|
+
exports.noEffectDecoratorAndCreatorSuggest = 'noEffectDecoratorAndCreatorSuggest';
|
|
33
|
+
exports["default"] = (0, rule_creator_1.createRule)({
|
|
34
|
+
name: path.parse(__filename).name,
|
|
35
|
+
meta: {
|
|
36
|
+
type: 'suggestion',
|
|
37
|
+
hasSuggestions: true,
|
|
38
|
+
ngrxModule: 'effects',
|
|
39
|
+
docs: {
|
|
40
|
+
description: '`Effect` should use either the `createEffect` or the `@Effect` decorator, but not both.',
|
|
41
|
+
recommended: 'error',
|
|
42
|
+
suggestion: true
|
|
43
|
+
},
|
|
44
|
+
fixable: 'code',
|
|
45
|
+
schema: [],
|
|
46
|
+
messages: (_a = {},
|
|
47
|
+
_a[exports.noEffectDecoratorAndCreator] = 'Using the `createEffect` and the `@Effect` decorator simultaneously is forbidden.',
|
|
48
|
+
_a[exports.noEffectDecoratorAndCreatorSuggest] = 'Remove the `@Effect` decorator.',
|
|
49
|
+
_a)
|
|
50
|
+
},
|
|
51
|
+
defaultOptions: [],
|
|
52
|
+
create: function (context) {
|
|
53
|
+
var _a;
|
|
54
|
+
var sourceCode = context.getSourceCode();
|
|
55
|
+
return _a = {},
|
|
56
|
+
_a["".concat(utils_1.effectCreator, ":has(").concat(utils_1.effectDecorator, ")")] = function (node) {
|
|
57
|
+
var decorator = (0, utils_1.getDecorator)(node, 'Effect');
|
|
58
|
+
if (!decorator) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
var hasDecoratorArgument = Boolean((0, utils_1.getDecoratorArguments)(decorator)[0]);
|
|
62
|
+
var fix = function (fixer) {
|
|
63
|
+
return getFixes(node, sourceCode, fixer, decorator);
|
|
64
|
+
};
|
|
65
|
+
if (hasDecoratorArgument) {
|
|
66
|
+
context.report({
|
|
67
|
+
node: node.key,
|
|
68
|
+
messageId: exports.noEffectDecoratorAndCreator,
|
|
69
|
+
// In this case where the argument to the `@Effect({...})`
|
|
70
|
+
// decorator exists, it is more appropriate to **suggest**
|
|
71
|
+
// instead of **fix**, since either simply removing or merging
|
|
72
|
+
// the arguments would likely generate unexpected behaviors and
|
|
73
|
+
// would be quite costly.
|
|
74
|
+
suggest: [
|
|
75
|
+
{
|
|
76
|
+
messageId: exports.noEffectDecoratorAndCreatorSuggest,
|
|
77
|
+
fix: fix
|
|
78
|
+
},
|
|
79
|
+
]
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
context.report({
|
|
84
|
+
node: node.key,
|
|
85
|
+
messageId: exports.noEffectDecoratorAndCreator,
|
|
86
|
+
fix: fix
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
_a;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
function getFixes(node, sourceCode, fixer, decorator) {
|
|
94
|
+
var _a;
|
|
95
|
+
var importDeclarations = (_a = (0, utils_1.getImportDeclarations)(node, utils_1.NGRX_MODULE_PATHS.effects)) !== null && _a !== void 0 ? _a : [];
|
|
96
|
+
var text = sourceCode.getText();
|
|
97
|
+
var totalEffectDecoratorOccurrences = getEffectDecoratorOccurrences(text);
|
|
98
|
+
var importRemoveFix = totalEffectDecoratorOccurrences === 1
|
|
99
|
+
? (0, utils_1.getImportRemoveFix)(sourceCode, importDeclarations, 'Effect', fixer)
|
|
100
|
+
: [];
|
|
101
|
+
return [fixer.remove(decorator)].concat(importRemoveFix);
|
|
102
|
+
}
|
|
103
|
+
function getEffectDecoratorOccurrences(text) {
|
|
104
|
+
var _a, _b;
|
|
105
|
+
return (_b = (_a = text.replace(/\s/g, '').match(/@Effect/g)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=no-effect-decorator-and-creator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-effect-decorator-and-creator.js","sourceRoot":"","sources":["../../../../../../modules/eslint-plugin/src/rules/effects/no-effect-decorator-and-creator.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';\nimport * as path from 'path';\nimport { createRule } from '../../rule-creator';\nimport {\n effectCreator,\n effectDecorator,\n getDecorator,\n getDecoratorArguments,\n getImportDeclarations,\n getImportRemoveFix,\n NGRX_MODULE_PATHS,\n} from '../../utils';\n\nexport const noEffectDecoratorAndCreator = 'noEffectDecoratorAndCreator';\nexport const noEffectDecoratorAndCreatorSuggest =\n 'noEffectDecoratorAndCreatorSuggest';\n\ntype MessageIds =\n | typeof noEffectDecoratorAndCreator\n | typeof noEffectDecoratorAndCreatorSuggest;\ntype Options = readonly [];\n\nexport default createRule<Options, MessageIds>({\n name: path.parse(__filename).name,\n meta: {\n type: 'suggestion',\n hasSuggestions: true,\n ngrxModule: 'effects',\n docs: {\n description:\n '`Effect` should use either the `createEffect` or the `@Effect` decorator, but not both.',\n recommended: 'error',\n suggestion: true,\n },\n fixable: 'code',\n schema: [],\n messages: {\n [noEffectDecoratorAndCreator]:\n 'Using the `createEffect` and the `@Effect` decorator simultaneously is forbidden.',\n [noEffectDecoratorAndCreatorSuggest]: 'Remove the `@Effect` decorator.',\n },\n },\n defaultOptions: [],\n create: (context) => {\n const sourceCode = context.getSourceCode();\n\n return {\n [`${effectCreator}:has(${effectDecorator})`](\n node: TSESTree.PropertyDefinition\n ) {\n const decorator = getDecorator(node, 'Effect');\n\n if (!decorator) {\n return;\n }\n\n const hasDecoratorArgument = Boolean(\n getDecoratorArguments(decorator)[0]\n );\n const fix: TSESLint.ReportFixFunction = (fixer) =>\n getFixes(node, sourceCode, fixer, decorator);\n\n if (hasDecoratorArgument) {\n context.report({\n node: node.key,\n messageId: noEffectDecoratorAndCreator,\n // In this case where the argument to the `@Effect({...})`\n // decorator exists, it is more appropriate to **suggest**\n // instead of **fix**, since either simply removing or merging\n // the arguments would likely generate unexpected behaviors and\n // would be quite costly.\n suggest: [\n {\n messageId: noEffectDecoratorAndCreatorSuggest,\n fix,\n },\n ],\n });\n } else {\n context.report({\n node: node.key,\n messageId: noEffectDecoratorAndCreator,\n fix,\n });\n }\n },\n };\n },\n});\n\nfunction getFixes(\n node: TSESTree.PropertyDefinition,\n sourceCode: Readonly<TSESLint.SourceCode>,\n fixer: TSESLint.RuleFixer,\n decorator: TSESTree.Decorator\n): readonly TSESLint.RuleFix[] {\n const importDeclarations =\n getImportDeclarations(node, NGRX_MODULE_PATHS.effects) ?? [];\n const text = sourceCode.getText();\n const totalEffectDecoratorOccurrences = getEffectDecoratorOccurrences(text);\n const importRemoveFix =\n totalEffectDecoratorOccurrences === 1\n ? getImportRemoveFix(sourceCode, importDeclarations, 'Effect', fixer)\n : [];\n\n return [fixer.remove(decorator)].concat(importRemoveFix);\n}\n\nfunction getEffectDecoratorOccurrences(text: string) {\n return text.replace(/\\s/g, '').match(/@Effect/g)?.length ?? 0;\n}\n"]}
|