@servicetitan/eslint-plugin 16.0.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.
Files changed (36) hide show
  1. package/dist/index.d.ts +11 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +18 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/processors/stub.d.ts +3 -0
  6. package/dist/processors/stub.d.ts.map +1 -0
  7. package/dist/processors/stub.js +8 -0
  8. package/dist/processors/stub.js.map +1 -0
  9. package/dist/rules/decorators-declare.d.ts +3 -0
  10. package/dist/rules/decorators-declare.d.ts.map +1 -0
  11. package/dist/rules/decorators-declare.js +44 -0
  12. package/dist/rules/decorators-declare.js.map +1 -0
  13. package/dist/rules/mobx/no-abstract-decorators.d.ts +3 -0
  14. package/dist/rules/mobx/no-abstract-decorators.d.ts.map +1 -0
  15. package/dist/rules/mobx/no-abstract-decorators.js +43 -0
  16. package/dist/rules/mobx/no-abstract-decorators.js.map +1 -0
  17. package/dist/rules/mobx/use-makeObservable-with-decorators.d.ts +3 -0
  18. package/dist/rules/mobx/use-makeObservable-with-decorators.d.ts.map +1 -0
  19. package/dist/rules/mobx/use-makeObservable-with-decorators.js +63 -0
  20. package/dist/rules/mobx/use-makeObservable-with-decorators.js.map +1 -0
  21. package/dist/rules/react/destructure-default-import.d.ts +3 -0
  22. package/dist/rules/react/destructure-default-import.d.ts.map +1 -0
  23. package/dist/rules/react/destructure-default-import.js +40 -0
  24. package/dist/rules/react/destructure-default-import.js.map +1 -0
  25. package/dist/rules/react/no-qualified-type.d.ts +3 -0
  26. package/dist/rules/react/no-qualified-type.d.ts.map +1 -0
  27. package/dist/rules/react/no-qualified-type.js +33 -0
  28. package/dist/rules/react/no-qualified-type.js.map +1 -0
  29. package/package.json +30 -0
  30. package/src/index.ts +16 -0
  31. package/src/processors/stub.ts +6 -0
  32. package/src/rules/decorators-declare.ts +43 -0
  33. package/src/rules/mobx/no-abstract-decorators.ts +43 -0
  34. package/src/rules/mobx/use-makeObservable-with-decorators.ts +68 -0
  35. package/src/rules/react/destructure-default-import.ts +41 -0
  36. package/src/rules/react/no-qualified-type.ts +31 -0
@@ -0,0 +1,11 @@
1
+ export declare const rules: {
2
+ 'use-declare-with-decorators': import("eslint").Rule.RuleModule;
3
+ 'mobx/use-makeObservable-with-decorators': import("eslint").Rule.RuleModule;
4
+ 'mobx/no-abstract-decorators': import("eslint").Rule.RuleModule;
5
+ 'react/destructure-default-import': import("eslint").Rule.RuleModule;
6
+ 'react/no-qualified-type': import("eslint").Rule.RuleModule;
7
+ };
8
+ export declare const processors: {
9
+ stub: import("eslint").Linter.LintOptions;
10
+ };
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,KAAK;;;;;;CAMjB,CAAC;AAEF,eAAO,MAAM,UAAU;;CAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processors = exports.rules = void 0;
4
+ const decorators_declare_1 = require("./rules/decorators-declare");
5
+ const use_makeObservable_with_decorators_1 = require("./rules/mobx/use-makeObservable-with-decorators");
6
+ const no_abstract_decorators_1 = require("./rules/mobx/no-abstract-decorators");
7
+ const destructure_default_import_1 = require("./rules/react/destructure-default-import");
8
+ const no_qualified_type_1 = require("./rules/react/no-qualified-type");
9
+ const stub_1 = require("./processors/stub");
10
+ exports.rules = {
11
+ 'use-declare-with-decorators': decorators_declare_1.useDeclareWithDecorators,
12
+ 'mobx/use-makeObservable-with-decorators': use_makeObservable_with_decorators_1.mobxUseMakeObservableWithDecorators,
13
+ 'mobx/no-abstract-decorators': no_abstract_decorators_1.mobxNoAbstractDecorators,
14
+ 'react/destructure-default-import': destructure_default_import_1.reactDestructureDefaultImport,
15
+ 'react/no-qualified-type': no_qualified_type_1.reactNoQualifiedType,
16
+ };
17
+ exports.processors = { stub: stub_1.stub };
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mEAAsE;AACtE,wGAAsG;AACtG,gFAA+E;AAC/E,yFAAyF;AACzF,uEAAuE;AACvE,4CAAyC;AAE5B,QAAA,KAAK,GAAG;IACjB,6BAA6B,EAAE,6CAAwB;IACvD,yCAAyC,EAAE,wEAAmC;IAC9E,6BAA6B,EAAE,iDAAwB;IACvD,kCAAkC,EAAE,0DAA6B;IACjE,yBAAyB,EAAE,wCAAoB;CAClD,CAAC;AAEW,QAAA,UAAU,GAAG,EAAE,IAAI,EAAJ,WAAI,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Linter } from 'eslint';
2
+ export declare const stub: Linter.LintOptions;
3
+ //# sourceMappingURL=stub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stub.d.ts","sourceRoot":"","sources":["../../src/processors/stub.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,eAAO,MAAM,IAAI,EAAE,MAAM,CAAC,WAGzB,CAAC"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stub = void 0;
4
+ exports.stub = {
5
+ preprocess: () => [''],
6
+ postprocess: ([messages]) => messages,
7
+ };
8
+ //# sourceMappingURL=stub.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stub.js","sourceRoot":"","sources":["../../src/processors/stub.ts"],"names":[],"mappings":";;;AAEa,QAAA,IAAI,GAAuB;IACpC,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;IACtB,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,QAAQ;CACxC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Rule } from 'eslint';
2
+ export declare const useDeclareWithDecorators: Rule.RuleModule;
3
+ //# sourceMappingURL=decorators-declare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decorators-declare.d.ts","sourceRoot":"","sources":["../../src/rules/decorators-declare.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAI9B,eAAO,MAAM,wBAAwB,EAAE,IAAI,CAAC,UAsC3C,CAAC"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useDeclareWithDecorators = void 0;
4
+ const customDecorators = ['injectDependency', 'koObservableToMobx'];
5
+ exports.useDeclareWithDecorators = {
6
+ meta: {
7
+ type: 'problem',
8
+ docs: {
9
+ description: 'Disallow custom @servicetitan class field decorators without declare',
10
+ category: 'Possible Errors',
11
+ recommended: false,
12
+ url: 'https://github.com/servicetitan/uikit.git',
13
+ },
14
+ messages: {
15
+ decoratorsDeclare: "Use declare when decorating with '@{{name}}'",
16
+ },
17
+ },
18
+ create(context) {
19
+ return {
20
+ ClassProperty(node) {
21
+ var _a;
22
+ if (node.declare) {
23
+ return; // field is already defined with declare
24
+ }
25
+ if ((_a = node === null || node === void 0 ? void 0 : node.decorators) === null || _a === void 0 ? void 0 : _a.length) {
26
+ node.decorators.forEach((decorator) => {
27
+ var _a, _b;
28
+ const name = (_b = (_a = decorator.expression) === null || _a === void 0 ? void 0 : _a.callee) === null || _b === void 0 ? void 0 : _b.name;
29
+ if (name && customDecorators.includes(name)) {
30
+ context.report({
31
+ node,
32
+ messageId: 'decoratorsDeclare',
33
+ data: {
34
+ name,
35
+ },
36
+ });
37
+ }
38
+ });
39
+ }
40
+ },
41
+ };
42
+ },
43
+ };
44
+ //# sourceMappingURL=decorators-declare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decorators-declare.js","sourceRoot":"","sources":["../../src/rules/decorators-declare.ts"],"names":[],"mappings":";;;AAEA,MAAM,gBAAgB,GAAG,CAAC,kBAAkB,EAAE,oBAAoB,CAAC,CAAC;AAEvD,QAAA,wBAAwB,GAAoB;IACrD,IAAI,EAAE;QACF,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACF,WAAW,EAAE,sEAAsE;YACnF,QAAQ,EAAE,iBAAiB;YAC3B,WAAW,EAAE,KAAK;YAClB,GAAG,EAAE,2CAA2C;SACnD;QACD,QAAQ,EAAE;YACN,iBAAiB,EAAE,8CAA8C;SACpE;KACJ;IACD,MAAM,CAAC,OAAO;QACV,OAAO;YACH,aAAa,CAAC,IAAS;;gBACnB,IAAI,IAAI,CAAC,OAAO,EAAE;oBACd,OAAO,CAAC,wCAAwC;iBACnD;gBAED,IAAI,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,UAAU,0CAAE,MAAM,EAAE;oBAC1B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAc,EAAE,EAAE;;wBACvC,MAAM,IAAI,GAAG,MAAA,MAAA,SAAS,CAAC,UAAU,0CAAE,MAAM,0CAAE,IAAI,CAAC;wBAEhD,IAAI,IAAI,IAAI,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;4BACzC,OAAO,CAAC,MAAM,CAAC;gCACX,IAAI;gCACJ,SAAS,EAAE,mBAAmB;gCAC9B,IAAI,EAAE;oCACF,IAAI;iCACP;6BACJ,CAAC,CAAC;yBACN;oBACL,CAAC,CAAC,CAAC;iBACN;YACL,CAAC;SACJ,CAAC;IACN,CAAC;CACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Rule } from 'eslint';
2
+ export declare const mobxNoAbstractDecorators: Rule.RuleModule;
3
+ //# sourceMappingURL=no-abstract-decorators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-abstract-decorators.d.ts","sourceRoot":"","sources":["../../../src/rules/mobx/no-abstract-decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAI9B,eAAO,MAAM,wBAAwB,EAAE,IAAI,CAAC,UAsC3C,CAAC"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mobxNoAbstractDecorators = void 0;
4
+ const mobxDecorators = ['observable', 'action', 'computed', 'override'];
5
+ exports.mobxNoAbstractDecorators = {
6
+ meta: {
7
+ type: 'problem',
8
+ docs: {
9
+ description: 'Disallow MobX decorators on abstract class fields',
10
+ category: 'Possible Errors',
11
+ recommended: false,
12
+ url: 'https://github.com/servicetitan/uikit.git',
13
+ },
14
+ messages: {
15
+ noAbstractMobxDecorators: "Don't decorate abstract class fields or methods with '@{{name}}'",
16
+ },
17
+ },
18
+ create(context) {
19
+ function checkFn(node) {
20
+ var _a;
21
+ if ((_a = node === null || node === void 0 ? void 0 : node.decorators) === null || _a === void 0 ? void 0 : _a.length) {
22
+ node.decorators.forEach((decorator) => {
23
+ var _a, _b, _c;
24
+ const name = ((_a = decorator === null || decorator === void 0 ? void 0 : decorator.expression) === null || _a === void 0 ? void 0 : _a.name) || ((_c = (_b = decorator === null || decorator === void 0 ? void 0 : decorator.expression) === null || _b === void 0 ? void 0 : _b.object) === null || _c === void 0 ? void 0 : _c.name);
25
+ if (name && mobxDecorators.includes(name)) {
26
+ context.report({
27
+ node,
28
+ messageId: 'noAbstractMobxDecorators',
29
+ data: {
30
+ name,
31
+ },
32
+ });
33
+ }
34
+ });
35
+ }
36
+ }
37
+ return {
38
+ TSAbstractClassProperty: checkFn,
39
+ TSAbstractMethodDefinition: checkFn,
40
+ };
41
+ },
42
+ };
43
+ //# sourceMappingURL=no-abstract-decorators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-abstract-decorators.js","sourceRoot":"","sources":["../../../src/rules/mobx/no-abstract-decorators.ts"],"names":[],"mappings":";;;AAEA,MAAM,cAAc,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAE3D,QAAA,wBAAwB,GAAoB;IACrD,IAAI,EAAE;QACF,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACF,WAAW,EAAE,mDAAmD;YAChE,QAAQ,EAAE,iBAAiB;YAC3B,WAAW,EAAE,KAAK;YAClB,GAAG,EAAE,2CAA2C;SACnD;QACD,QAAQ,EAAE;YACN,wBAAwB,EACpB,kEAAkE;SACzE;KACJ;IACD,MAAM,CAAC,OAAY;QACf,SAAS,OAAO,CAAC,IAAS;;YACtB,IAAI,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,UAAU,0CAAE,MAAM,EAAE;gBAC1B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAc,EAAE,EAAE;;oBACvC,MAAM,IAAI,GAAG,CAAA,MAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,UAAU,0CAAE,IAAI,MAAI,MAAA,MAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,UAAU,0CAAE,MAAM,0CAAE,IAAI,CAAA,CAAC;oBAEhF,IAAI,IAAI,IAAI,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;wBACvC,OAAO,CAAC,MAAM,CAAC;4BACX,IAAI;4BACJ,SAAS,EAAE,0BAA0B;4BACrC,IAAI,EAAE;gCACF,IAAI;6BACP;yBACJ,CAAC,CAAC;qBACN;gBACL,CAAC,CAAC,CAAC;aACN;QACL,CAAC;QAED,OAAO;YACH,uBAAuB,EAAE,OAAO;YAChC,0BAA0B,EAAE,OAAO;SACtC,CAAC;IACN,CAAC;CACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Rule } from 'eslint';
2
+ export declare const mobxUseMakeObservableWithDecorators: Rule.RuleModule;
3
+ //# sourceMappingURL=use-makeObservable-with-decorators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-makeObservable-with-decorators.d.ts","sourceRoot":"","sources":["../../../src/rules/mobx/use-makeObservable-with-decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAK9B,eAAO,MAAM,mCAAmC,EAAE,IAAI,CAAC,UA8DtD,CAAC"}
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mobxUseMakeObservableWithDecorators = void 0;
4
+ // NOTE: "action" also covers "action.bound"
5
+ const mobxDecorators = ['observable', 'action', 'computed', 'override'];
6
+ exports.mobxUseMakeObservableWithDecorators = {
7
+ meta: {
8
+ type: 'problem',
9
+ docs: {
10
+ description: 'Testing makeObservable used with decorators',
11
+ category: 'Possible Errors',
12
+ recommended: false,
13
+ url: 'https://github.com/servicetitan/uikit.git',
14
+ },
15
+ messages: {
16
+ makeObservable: 'Use makeObservable in the constructor with MobX decorators',
17
+ constructor: 'Add constructor with makeObservable when using MobX decorators',
18
+ },
19
+ },
20
+ create(context) {
21
+ return {
22
+ ClassDeclaration(node) {
23
+ let hasMobxDecorator = false;
24
+ let hasConstructor = false;
25
+ let hasMakeObservable = false;
26
+ node.body.body.forEach((methodOrProperty) => {
27
+ var _a, _b;
28
+ if (methodOrProperty.decorators) {
29
+ methodOrProperty.decorators.forEach((decorator) => {
30
+ var _a, _b, _c;
31
+ if (mobxDecorators.includes(((_a = decorator === null || decorator === void 0 ? void 0 : decorator.expression) === null || _a === void 0 ? void 0 : _a.name) ||
32
+ ((_c = (_b = decorator === null || decorator === void 0 ? void 0 : decorator.expression) === null || _b === void 0 ? void 0 : _b.object) === null || _c === void 0 ? void 0 : _c.name))) {
33
+ hasMobxDecorator = true;
34
+ }
35
+ });
36
+ }
37
+ if (methodOrProperty.kind === 'constructor') {
38
+ hasConstructor = true;
39
+ (_b = (_a = methodOrProperty.value) === null || _a === void 0 ? void 0 : _a.body) === null || _b === void 0 ? void 0 : _b.body.forEach((statement) => {
40
+ var _a, _b;
41
+ if (((_b = (_a = statement === null || statement === void 0 ? void 0 : statement.expression) === null || _a === void 0 ? void 0 : _a.callee) === null || _b === void 0 ? void 0 : _b.name) === 'makeObservable') {
42
+ hasMakeObservable = true;
43
+ }
44
+ });
45
+ }
46
+ });
47
+ if (hasMobxDecorator && !hasMakeObservable && hasConstructor) {
48
+ context.report({
49
+ node,
50
+ messageId: 'makeObservable',
51
+ });
52
+ }
53
+ if (hasMobxDecorator && !hasMakeObservable && !hasConstructor) {
54
+ context.report({
55
+ node,
56
+ messageId: 'constructor',
57
+ });
58
+ }
59
+ },
60
+ };
61
+ },
62
+ };
63
+ //# sourceMappingURL=use-makeObservable-with-decorators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-makeObservable-with-decorators.js","sourceRoot":"","sources":["../../../src/rules/mobx/use-makeObservable-with-decorators.ts"],"names":[],"mappings":";;;AAEA,4CAA4C;AAC5C,MAAM,cAAc,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAE3D,QAAA,mCAAmC,GAAoB;IAChE,IAAI,EAAE;QACF,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACF,WAAW,EAAE,6CAA6C;YAC1D,QAAQ,EAAE,iBAAiB;YAC3B,WAAW,EAAE,KAAK;YAClB,GAAG,EAAE,2CAA2C;SACnD;QACD,QAAQ,EAAE;YACN,cAAc,EAAE,4DAA4D;YAC5E,WAAW,EAAE,gEAAgE;SAChF;KACJ;IACD,MAAM,CAAC,OAAO;QACV,OAAO;YACH,gBAAgB,CAAC,IAAI;gBACjB,IAAI,gBAAgB,GAAG,KAAK,CAAC;gBAC7B,IAAI,cAAc,GAAG,KAAK,CAAC;gBAC3B,IAAI,iBAAiB,GAAG,KAAK,CAAC;gBAE9B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,gBAAqB,EAAE,EAAE;;oBAC7C,IAAI,gBAAgB,CAAC,UAAU,EAAE;wBAC7B,gBAAgB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAc,EAAE,EAAE;;4BACnD,IACI,cAAc,CAAC,QAAQ,CACnB,CAAA,MAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,UAAU,0CAAE,IAAI;iCACvB,MAAA,MAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,UAAU,0CAAE,MAAM,0CAAE,IAAI,CAAA,CAC1C,EACH;gCACE,gBAAgB,GAAG,IAAI,CAAC;6BAC3B;wBACL,CAAC,CAAC,CAAC;qBACN;oBAED,IAAI,gBAAgB,CAAC,IAAI,KAAK,aAAa,EAAE;wBACzC,cAAc,GAAG,IAAI,CAAC;wBAEtB,MAAA,MAAA,gBAAgB,CAAC,KAAK,0CAAE,IAAI,0CAAE,IAAI,CAAC,OAAO,CAAC,CAAC,SAAc,EAAE,EAAE;;4BAC1D,IAAI,CAAA,MAAA,MAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,UAAU,0CAAE,MAAM,0CAAE,IAAI,MAAK,gBAAgB,EAAE;gCAC1D,iBAAiB,GAAG,IAAI,CAAC;6BAC5B;wBACL,CAAC,CAAC,CAAC;qBACN;gBACL,CAAC,CAAC,CAAC;gBAEH,IAAI,gBAAgB,IAAI,CAAC,iBAAiB,IAAI,cAAc,EAAE;oBAC1D,OAAO,CAAC,MAAM,CAAC;wBACX,IAAI;wBACJ,SAAS,EAAE,gBAAgB;qBAC9B,CAAC,CAAC;iBACN;gBAED,IAAI,gBAAgB,IAAI,CAAC,iBAAiB,IAAI,CAAC,cAAc,EAAE;oBAC3D,OAAO,CAAC,MAAM,CAAC;wBACX,IAAI;wBACJ,SAAS,EAAE,aAAa;qBAC3B,CAAC,CAAC;iBACN;YACL,CAAC;SACJ,CAAC;IACN,CAAC;CACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Rule } from 'eslint';
2
+ export declare const reactDestructureDefaultImport: Rule.RuleModule;
3
+ //# sourceMappingURL=destructure-default-import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destructure-default-import.d.ts","sourceRoot":"","sources":["../../../src/rules/react/destructure-default-import.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,eAAO,MAAM,6BAA6B,EAAE,IAAI,CAAC,UAsChD,CAAC"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reactDestructureDefaultImport = void 0;
4
+ exports.reactDestructureDefaultImport = {
5
+ meta: {
6
+ type: 'suggestion',
7
+ docs: {
8
+ description: "Disallow importing React's default export",
9
+ category: 'Best Practices',
10
+ recommended: false,
11
+ url: 'https://github.com/servicetitan/uikit.git',
12
+ },
13
+ messages: {
14
+ importDefault: 'Avoid importing React default export',
15
+ },
16
+ },
17
+ create(context) {
18
+ return {
19
+ ImportDeclaration(node) {
20
+ const reactImportSpecifiers = new Set();
21
+ if (node.source.value !== 'react') {
22
+ return;
23
+ }
24
+ node.specifiers.forEach(specifier => {
25
+ if (specifier.type === 'ImportDefaultSpecifier' ||
26
+ specifier.type === 'ImportNamespaceSpecifier') {
27
+ context.report({
28
+ node,
29
+ messageId: 'importDefault',
30
+ });
31
+ }
32
+ else {
33
+ reactImportSpecifiers.add(specifier.imported);
34
+ }
35
+ });
36
+ },
37
+ };
38
+ },
39
+ };
40
+ //# sourceMappingURL=destructure-default-import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destructure-default-import.js","sourceRoot":"","sources":["../../../src/rules/react/destructure-default-import.ts"],"names":[],"mappings":";;;AAEa,QAAA,6BAA6B,GAAoB;IAC1D,IAAI,EAAE;QACF,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACF,WAAW,EAAE,2CAA2C;YACxD,QAAQ,EAAE,gBAAgB;YAC1B,WAAW,EAAE,KAAK;YAClB,GAAG,EAAE,2CAA2C;SACnD;QACD,QAAQ,EAAE;YACN,aAAa,EAAE,sCAAsC;SACxD;KACJ;IACD,MAAM,CAAC,OAAO;QACV,OAAO;YACH,iBAAiB,CAAC,IAAI;gBAClB,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAAE,CAAC;gBAExC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,OAAO,EAAE;oBAC/B,OAAO;iBACV;gBAED,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;oBAChC,IACI,SAAS,CAAC,IAAI,KAAK,wBAAwB;wBAC3C,SAAS,CAAC,IAAI,KAAK,0BAA0B,EAC/C;wBACE,OAAO,CAAC,MAAM,CAAC;4BACX,IAAI;4BACJ,SAAS,EAAE,eAAe;yBAC7B,CAAC,CAAC;qBACN;yBAAM;wBACH,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;qBACjD;gBACL,CAAC,CAAC,CAAC;YACP,CAAC;SACJ,CAAC;IACN,CAAC;CACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Rule } from 'eslint';
2
+ export declare const reactNoQualifiedType: Rule.RuleModule;
3
+ //# sourceMappingURL=no-qualified-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-qualified-type.d.ts","sourceRoot":"","sources":["../../../src/rules/react/no-qualified-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,eAAO,MAAM,oBAAoB,EAAE,IAAI,CAAC,UA4BvC,CAAC"}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reactNoQualifiedType = void 0;
4
+ exports.reactNoQualifiedType = {
5
+ meta: {
6
+ type: 'suggestion',
7
+ docs: {
8
+ description: 'Disallow using React types from default export',
9
+ category: 'Best Practices',
10
+ recommended: false,
11
+ url: 'https://github.com/servicetitan/uikit.git',
12
+ },
13
+ messages: {
14
+ importDefault: "Import {{right}} from 'react' instead of using React.{{right}}",
15
+ },
16
+ },
17
+ create(context) {
18
+ return {
19
+ TSQualifiedName(node) {
20
+ if (node.left && node.left.name === 'React') {
21
+ context.report({
22
+ node,
23
+ messageId: 'importDefault',
24
+ data: {
25
+ right: node.right.name,
26
+ },
27
+ });
28
+ }
29
+ },
30
+ };
31
+ },
32
+ };
33
+ //# sourceMappingURL=no-qualified-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-qualified-type.js","sourceRoot":"","sources":["../../../src/rules/react/no-qualified-type.ts"],"names":[],"mappings":";;;AAEa,QAAA,oBAAoB,GAAoB;IACjD,IAAI,EAAE;QACF,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACF,WAAW,EAAE,gDAAgD;YAC7D,QAAQ,EAAE,gBAAgB;YAC1B,WAAW,EAAE,KAAK;YAClB,GAAG,EAAE,2CAA2C;SACnD;QACD,QAAQ,EAAE;YACN,aAAa,EAAE,gEAAgE;SAClF;KACJ;IACD,MAAM,CAAC,OAAO;QACV,OAAO;YACH,eAAe,CAAC,IAAS;gBACrB,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE;oBACzC,OAAO,CAAC,MAAM,CAAC;wBACX,IAAI;wBACJ,SAAS,EAAE,eAAe;wBAC1B,IAAI,EAAE;4BACF,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;yBACzB;qBACJ,CAAC,CAAC;iBACN;YACL,CAAC;SACJ,CAAC;IACN,CAAC;CACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@servicetitan/eslint-plugin",
3
+ "version": "16.0.0",
4
+ "description": "",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/servicetitan/uikit.git",
8
+ "directory": "packages/eslint-plugin"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "typings": "./dist/index.d.ts",
12
+ "files": [
13
+ "dist",
14
+ "src"
15
+ ],
16
+ "devDependencies": {
17
+ "@types/eslint": "~7.28.0",
18
+ "eslint": "~7.31.0"
19
+ },
20
+ "peerDependencies": {
21
+ "eslint": "~7.31.0"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "cli": {
27
+ "webpack": false
28
+ },
29
+ "gitHead": "d2d6e21f4f639bcde5a9ab274a6fd47b14b26974"
30
+ }
package/src/index.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { useDeclareWithDecorators } from './rules/decorators-declare';
2
+ import { mobxUseMakeObservableWithDecorators } from './rules/mobx/use-makeObservable-with-decorators';
3
+ import { mobxNoAbstractDecorators } from './rules/mobx/no-abstract-decorators';
4
+ import { reactDestructureDefaultImport } from './rules/react/destructure-default-import';
5
+ import { reactNoQualifiedType } from './rules/react/no-qualified-type';
6
+ import { stub } from './processors/stub';
7
+
8
+ export const rules = {
9
+ 'use-declare-with-decorators': useDeclareWithDecorators,
10
+ 'mobx/use-makeObservable-with-decorators': mobxUseMakeObservableWithDecorators,
11
+ 'mobx/no-abstract-decorators': mobxNoAbstractDecorators,
12
+ 'react/destructure-default-import': reactDestructureDefaultImport,
13
+ 'react/no-qualified-type': reactNoQualifiedType,
14
+ };
15
+
16
+ export const processors = { stub };
@@ -0,0 +1,6 @@
1
+ import { Linter } from 'eslint';
2
+
3
+ export const stub: Linter.LintOptions = {
4
+ preprocess: () => [''],
5
+ postprocess: ([messages]) => messages,
6
+ };
@@ -0,0 +1,43 @@
1
+ import { Rule } from 'eslint';
2
+
3
+ const customDecorators = ['injectDependency', 'koObservableToMobx'];
4
+
5
+ export const useDeclareWithDecorators: Rule.RuleModule = {
6
+ meta: {
7
+ type: 'problem',
8
+ docs: {
9
+ description: 'Disallow custom @servicetitan class field decorators without declare',
10
+ category: 'Possible Errors',
11
+ recommended: false,
12
+ url: 'https://github.com/servicetitan/uikit.git',
13
+ },
14
+ messages: {
15
+ decoratorsDeclare: "Use declare when decorating with '@{{name}}'",
16
+ },
17
+ },
18
+ create(context) {
19
+ return {
20
+ ClassProperty(node: any) {
21
+ if (node.declare) {
22
+ return; // field is already defined with declare
23
+ }
24
+
25
+ if (node?.decorators?.length) {
26
+ node.decorators.forEach((decorator: any) => {
27
+ const name = decorator.expression?.callee?.name;
28
+
29
+ if (name && customDecorators.includes(name)) {
30
+ context.report({
31
+ node,
32
+ messageId: 'decoratorsDeclare',
33
+ data: {
34
+ name,
35
+ },
36
+ });
37
+ }
38
+ });
39
+ }
40
+ },
41
+ };
42
+ },
43
+ };
@@ -0,0 +1,43 @@
1
+ import { Rule } from 'eslint';
2
+
3
+ const mobxDecorators = ['observable', 'action', 'computed', 'override'];
4
+
5
+ export const mobxNoAbstractDecorators: Rule.RuleModule = {
6
+ meta: {
7
+ type: 'problem',
8
+ docs: {
9
+ description: 'Disallow MobX decorators on abstract class fields',
10
+ category: 'Possible Errors',
11
+ recommended: false,
12
+ url: 'https://github.com/servicetitan/uikit.git',
13
+ },
14
+ messages: {
15
+ noAbstractMobxDecorators:
16
+ "Don't decorate abstract class fields or methods with '@{{name}}'",
17
+ },
18
+ },
19
+ create(context: any) {
20
+ function checkFn(node: any) {
21
+ if (node?.decorators?.length) {
22
+ node.decorators.forEach((decorator: any) => {
23
+ const name = decorator?.expression?.name || decorator?.expression?.object?.name;
24
+
25
+ if (name && mobxDecorators.includes(name)) {
26
+ context.report({
27
+ node,
28
+ messageId: 'noAbstractMobxDecorators',
29
+ data: {
30
+ name,
31
+ },
32
+ });
33
+ }
34
+ });
35
+ }
36
+ }
37
+
38
+ return {
39
+ TSAbstractClassProperty: checkFn,
40
+ TSAbstractMethodDefinition: checkFn,
41
+ };
42
+ },
43
+ };
@@ -0,0 +1,68 @@
1
+ import { Rule } from 'eslint';
2
+
3
+ // NOTE: "action" also covers "action.bound"
4
+ const mobxDecorators = ['observable', 'action', 'computed', 'override'];
5
+
6
+ export const mobxUseMakeObservableWithDecorators: Rule.RuleModule = {
7
+ meta: {
8
+ type: 'problem',
9
+ docs: {
10
+ description: 'Testing makeObservable used with decorators',
11
+ category: 'Possible Errors',
12
+ recommended: false,
13
+ url: 'https://github.com/servicetitan/uikit.git',
14
+ },
15
+ messages: {
16
+ makeObservable: 'Use makeObservable in the constructor with MobX decorators',
17
+ constructor: 'Add constructor with makeObservable when using MobX decorators',
18
+ },
19
+ },
20
+ create(context) {
21
+ return {
22
+ ClassDeclaration(node) {
23
+ let hasMobxDecorator = false;
24
+ let hasConstructor = false;
25
+ let hasMakeObservable = false;
26
+
27
+ node.body.body.forEach((methodOrProperty: any) => {
28
+ if (methodOrProperty.decorators) {
29
+ methodOrProperty.decorators.forEach((decorator: any) => {
30
+ if (
31
+ mobxDecorators.includes(
32
+ decorator?.expression?.name ||
33
+ decorator?.expression?.object?.name
34
+ )
35
+ ) {
36
+ hasMobxDecorator = true;
37
+ }
38
+ });
39
+ }
40
+
41
+ if (methodOrProperty.kind === 'constructor') {
42
+ hasConstructor = true;
43
+
44
+ methodOrProperty.value?.body?.body.forEach((statement: any) => {
45
+ if (statement?.expression?.callee?.name === 'makeObservable') {
46
+ hasMakeObservable = true;
47
+ }
48
+ });
49
+ }
50
+ });
51
+
52
+ if (hasMobxDecorator && !hasMakeObservable && hasConstructor) {
53
+ context.report({
54
+ node,
55
+ messageId: 'makeObservable',
56
+ });
57
+ }
58
+
59
+ if (hasMobxDecorator && !hasMakeObservable && !hasConstructor) {
60
+ context.report({
61
+ node,
62
+ messageId: 'constructor',
63
+ });
64
+ }
65
+ },
66
+ };
67
+ },
68
+ };
@@ -0,0 +1,41 @@
1
+ import { Rule } from 'eslint';
2
+
3
+ export const reactDestructureDefaultImport: Rule.RuleModule = {
4
+ meta: {
5
+ type: 'suggestion',
6
+ docs: {
7
+ description: "Disallow importing React's default export",
8
+ category: 'Best Practices',
9
+ recommended: false,
10
+ url: 'https://github.com/servicetitan/uikit.git',
11
+ },
12
+ messages: {
13
+ importDefault: 'Avoid importing React default export',
14
+ },
15
+ },
16
+ create(context) {
17
+ return {
18
+ ImportDeclaration(node) {
19
+ const reactImportSpecifiers = new Set();
20
+
21
+ if (node.source.value !== 'react') {
22
+ return;
23
+ }
24
+
25
+ node.specifiers.forEach(specifier => {
26
+ if (
27
+ specifier.type === 'ImportDefaultSpecifier' ||
28
+ specifier.type === 'ImportNamespaceSpecifier'
29
+ ) {
30
+ context.report({
31
+ node,
32
+ messageId: 'importDefault',
33
+ });
34
+ } else {
35
+ reactImportSpecifiers.add(specifier.imported);
36
+ }
37
+ });
38
+ },
39
+ };
40
+ },
41
+ };
@@ -0,0 +1,31 @@
1
+ import { Rule } from 'eslint';
2
+
3
+ export const reactNoQualifiedType: Rule.RuleModule = {
4
+ meta: {
5
+ type: 'suggestion',
6
+ docs: {
7
+ description: 'Disallow using React types from default export',
8
+ category: 'Best Practices',
9
+ recommended: false,
10
+ url: 'https://github.com/servicetitan/uikit.git',
11
+ },
12
+ messages: {
13
+ importDefault: "Import {{right}} from 'react' instead of using React.{{right}}",
14
+ },
15
+ },
16
+ create(context) {
17
+ return {
18
+ TSQualifiedName(node: any) {
19
+ if (node.left && node.left.name === 'React') {
20
+ context.report({
21
+ node,
22
+ messageId: 'importDefault',
23
+ data: {
24
+ right: node.right.name,
25
+ },
26
+ });
27
+ }
28
+ },
29
+ };
30
+ },
31
+ };