eslint-plugin-mobx 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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # eslint-plugin-mobx
2
2
 
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`f7af259df425280aebeb0ccdb13350ba6d24270a`](https://github.com/mobxjs/mobx/commit/f7af259df425280aebeb0ccdb13350ba6d24270a) [#4699](https://github.com/mobxjs/mobx/pull/4699) Thanks [@rakleed](https://github.com/rakleed)! - Add TypeScript types for `configs.recommended` and `flatConfigs.recommended`, so they're typed when used from a TypeScript `eslint.config.ts`.
8
+
3
9
  ## 0.0.14
4
10
 
5
11
  ### Patch Changes
@@ -0,0 +1,3 @@
1
+ import type { Rule } from "eslint";
2
+ declare const rule: Rule.RuleModule;
3
+ export default rule;
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ var __read = (this && this.__read) || function (o, n) {
3
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
4
+ if (!m) return o;
5
+ var i = m.call(o), r, ar = [], e;
6
+ try {
7
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
8
+ }
9
+ catch (error) { e = { error: error }; }
10
+ finally {
11
+ try {
12
+ if (r && !r.done && (m = i["return"])) m.call(i);
13
+ }
14
+ finally { if (e) throw e.error; }
15
+ }
16
+ return ar;
17
+ };
18
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
19
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
20
+ if (ar || !(i in from)) {
21
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
22
+ ar[i] = from[i];
23
+ }
24
+ }
25
+ return to.concat(ar || Array.prototype.slice.call(from));
26
+ };
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ var utils_1 = require("./utils");
29
+ // TODO support this.foo = 5; in constructor
30
+ // TODO? report on field as well
31
+ function create(context) {
32
+ var _a, _b, _c;
33
+ var sourceCode = (_a = context.sourceCode) !== null && _a !== void 0 ? _a : context.getSourceCode();
34
+ var autofixAnnotation = (_c = (_b = context.options[0]) === null || _b === void 0 ? void 0 : _b.autofixAnnotation) !== null && _c !== void 0 ? _c : true;
35
+ function fieldToKey(field) {
36
+ // TODO cache on field?
37
+ var key = sourceCode.getText(field.key);
38
+ return field.computed ? "[".concat(key, "]") : key;
39
+ }
40
+ return {
41
+ 'CallExpression[callee.name="makeObservable"]': function (makeObservable) {
42
+ var _a;
43
+ // Only interested about makeObservable(this, ...) in constructor or makeObservable({}, ...)
44
+ // ClassDeclaration
45
+ // ClassBody
46
+ // MethodDefinition[kind="constructor"]
47
+ // FunctionExpression
48
+ // BlockStatement
49
+ // ExpressionStatement
50
+ // CallExpression[callee.name="makeObservable"]
51
+ var _b = __read(makeObservable.arguments, 2), firstArg = _b[0], secondArg = _b[1];
52
+ if (!firstArg)
53
+ return;
54
+ var members;
55
+ if (firstArg.type === "ThisExpression") {
56
+ var closestFunction = (0, utils_1.findAncestor)(makeObservable, function (node) {
57
+ return node.type === "FunctionExpression" || node.type === "FunctionDeclaration";
58
+ });
59
+ if (((_a = closestFunction === null || closestFunction === void 0 ? void 0 : closestFunction.parent) === null || _a === void 0 ? void 0 : _a.kind) !== "constructor")
60
+ return;
61
+ members = closestFunction.parent.parent.parent.body.body;
62
+ }
63
+ else if (firstArg.type === "ObjectExpression") {
64
+ members = firstArg.properties;
65
+ }
66
+ else {
67
+ return;
68
+ }
69
+ var annotationProps = (secondArg === null || secondArg === void 0 ? void 0 : secondArg.properties) || [];
70
+ var nonAnnotatedMembers = [];
71
+ var hasAnyDecorator = false;
72
+ members.forEach(function (member) {
73
+ var _a;
74
+ if (member.static)
75
+ return;
76
+ if (member.kind === "constructor")
77
+ return;
78
+ //if (member.type !== 'MethodDefinition' && member.type !== 'ClassProperty') return;
79
+ hasAnyDecorator =
80
+ hasAnyDecorator || ((_a = member.decorators) === null || _a === void 0 ? void 0 : _a.some(utils_1.isMobxDecorator)) || false;
81
+ if (!annotationProps.some(function (prop) { return fieldToKey(prop) === fieldToKey(member); })) {
82
+ // TODO optimize?
83
+ nonAnnotatedMembers.push(member);
84
+ }
85
+ });
86
+ /*
87
+ // With decorators, second arg must be null/undefined or not provided
88
+ if (hasAnyDecorator && secondArg && secondArg.name !== "undefined" && secondArg.value !== null) {
89
+ context.report({
90
+ node: makeObservable,
91
+ message: 'When using decorators, second arg must be `null`, `undefined` or not provided.',
92
+ })
93
+ }
94
+ // Without decorators, in constructor, second arg must be object literal
95
+ if (!hasAnyDecorator && firstArg.type === 'ThisExpression' && (!secondArg || secondArg.type !== 'ObjectExpression')) {
96
+ context.report({
97
+ node: makeObservable,
98
+ message: 'Second argument must be object in form of `{ key: annotation }`.',
99
+ })
100
+ }
101
+ */
102
+ if (!hasAnyDecorator && nonAnnotatedMembers.length) {
103
+ // Set avoids reporting twice for setter+getter pair or actual duplicates
104
+ var keys_1 = __spreadArray([], __read(new Set(nonAnnotatedMembers.map(fieldToKey))), false);
105
+ var keyList = keys_1.map(function (key) { return "`".concat(key, "`"); }).join(", ");
106
+ var fix = function (fixer) {
107
+ var annotationList = keys_1.map(function (key) { return "".concat(key, ": ").concat(autofixAnnotation); }).join(", ") + ",";
108
+ if (!secondArg) {
109
+ return fixer.insertTextAfter(firstArg, ", { ".concat(annotationList, " }"));
110
+ }
111
+ else if (secondArg.type !== "ObjectExpression") {
112
+ return fixer.replaceText(secondArg, "{ ".concat(annotationList, " }"));
113
+ }
114
+ else {
115
+ var openingBracket = sourceCode.getFirstToken(secondArg);
116
+ return fixer.insertTextAfter(openingBracket, " ".concat(annotationList, " "));
117
+ }
118
+ };
119
+ context.report({
120
+ node: makeObservable,
121
+ messageId: "missingAnnotation",
122
+ data: { keyList: keyList },
123
+ fix: fix
124
+ });
125
+ }
126
+ }
127
+ };
128
+ }
129
+ var rule = {
130
+ meta: {
131
+ type: "suggestion",
132
+ fixable: "code",
133
+ schema: [
134
+ {
135
+ type: "object",
136
+ properties: {
137
+ autofixAnnotation: {
138
+ type: "boolean"
139
+ }
140
+ },
141
+ additionalProperties: false
142
+ }
143
+ ],
144
+ docs: {
145
+ description: "enforce all fields being listen in `makeObservable`",
146
+ recommended: true
147
+ },
148
+ messages: {
149
+ missingAnnotation: "Missing annotation for {{ keyList }}. To exclude a field, use `false` as annotation."
150
+ }
151
+ },
152
+ create: create
153
+ };
154
+ exports.default = rule;
@@ -0,0 +1,11 @@
1
+ import type { ESLint, Linter } from "eslint";
2
+ declare const pluginMobx: ESLint.Plugin;
3
+ declare const plugin: typeof pluginMobx & {
4
+ configs: {
5
+ recommended: Linter.LegacyConfig;
6
+ };
7
+ flatConfigs: {
8
+ recommended: Linter.Config;
9
+ };
10
+ };
11
+ export = plugin;