@iviva/uxp-lint 0.0.1

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 (85) hide show
  1. package/README.md +273 -0
  2. package/bin/uxp-lint.js +2 -0
  3. package/dist/cli.d.ts +1 -0
  4. package/dist/cli.js +100 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/config.d.ts +4 -0
  7. package/dist/config.js +42 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/eslint/config.d.ts +2 -0
  10. package/dist/eslint/config.js +225 -0
  11. package/dist/eslint/config.js.map +1 -0
  12. package/dist/eslint/rules/event-name-format.d.ts +5 -0
  13. package/dist/eslint/rules/event-name-format.js +59 -0
  14. package/dist/eslint/rules/event-name-format.js.map +1 -0
  15. package/dist/eslint/rules/no-bad-hook-deps.d.ts +5 -0
  16. package/dist/eslint/rules/no-bad-hook-deps.js +57 -0
  17. package/dist/eslint/rules/no-bad-hook-deps.js.map +1 -0
  18. package/dist/eslint/rules/no-fa-prefix.d.ts +5 -0
  19. package/dist/eslint/rules/no-fa-prefix.js +59 -0
  20. package/dist/eslint/rules/no-fa-prefix.js.map +1 -0
  21. package/dist/eslint/rules/no-hardcoded-jsx-text.d.ts +5 -0
  22. package/dist/eslint/rules/no-hardcoded-jsx-text.js +55 -0
  23. package/dist/eslint/rules/no-hardcoded-jsx-text.js.map +1 -0
  24. package/dist/eslint/rules/no-inline-styles.d.ts +8 -0
  25. package/dist/eslint/rules/no-inline-styles.js +41 -0
  26. package/dist/eslint/rules/no-inline-styles.js.map +1 -0
  27. package/dist/eslint/rules/no-native-html-interactive.d.ts +5 -0
  28. package/dist/eslint/rules/no-native-html-interactive.js +81 -0
  29. package/dist/eslint/rules/no-native-html-interactive.js.map +1 -0
  30. package/dist/eslint/rules/require-memo.d.ts +9 -0
  31. package/dist/eslint/rules/require-memo.js +70 -0
  32. package/dist/eslint/rules/require-memo.js.map +1 -0
  33. package/dist/eslint/rules/service-config-shape.d.ts +5 -0
  34. package/dist/eslint/rules/service-config-shape.js +80 -0
  35. package/dist/eslint/rules/service-config-shape.js.map +1 -0
  36. package/dist/eslint/rules/url-params-form-state.d.ts +5 -0
  37. package/dist/eslint/rules/url-params-form-state.js +75 -0
  38. package/dist/eslint/rules/url-params-form-state.js.map +1 -0
  39. package/dist/reporter.d.ts +22 -0
  40. package/dist/reporter.js +260 -0
  41. package/dist/reporter.js.map +1 -0
  42. package/dist/rule-registry.d.ts +2 -0
  43. package/dist/rule-registry.js +46 -0
  44. package/dist/rule-registry.js.map +1 -0
  45. package/dist/rules-reader.d.ts +4 -0
  46. package/dist/rules-reader.js +16 -0
  47. package/dist/rules-reader.js.map +1 -0
  48. package/dist/runner.d.ts +7 -0
  49. package/dist/runner.js +62 -0
  50. package/dist/runner.js.map +1 -0
  51. package/dist/setup.d.ts +2 -0
  52. package/dist/setup.js +80 -0
  53. package/dist/setup.js.map +1 -0
  54. package/dist/types.d.ts +55 -0
  55. package/dist/types.js +39 -0
  56. package/dist/types.js.map +1 -0
  57. package/dist/validators/ai.d.ts +2 -0
  58. package/dist/validators/ai.js +115 -0
  59. package/dist/validators/ai.js.map +1 -0
  60. package/dist/validators/bulk-imports.d.ts +3 -0
  61. package/dist/validators/bulk-imports.js +94 -0
  62. package/dist/validators/bulk-imports.js.map +1 -0
  63. package/dist/validators/bundle-json.d.ts +3 -0
  64. package/dist/validators/bundle-json.js +130 -0
  65. package/dist/validators/bundle-json.js.map +1 -0
  66. package/dist/validators/bundle-size.d.ts +3 -0
  67. package/dist/validators/bundle-size.js +51 -0
  68. package/dist/validators/bundle-size.js.map +1 -0
  69. package/dist/validators/config-yml.d.ts +3 -0
  70. package/dist/validators/config-yml.js +148 -0
  71. package/dist/validators/config-yml.js.map +1 -0
  72. package/dist/validators/duplication.d.ts +3 -0
  73. package/dist/validators/duplication.js +65 -0
  74. package/dist/validators/duplication.js.map +1 -0
  75. package/dist/validators/folder-structure.d.ts +3 -0
  76. package/dist/validators/folder-structure.js +123 -0
  77. package/dist/validators/folder-structure.js.map +1 -0
  78. package/dist/validators/formatting.d.ts +3 -0
  79. package/dist/validators/formatting.js +97 -0
  80. package/dist/validators/formatting.js.map +1 -0
  81. package/dist/validators/scss-rules.d.ts +3 -0
  82. package/dist/validators/scss-rules.js +156 -0
  83. package/dist/validators/scss-rules.js.map +1 -0
  84. package/package.json +58 -0
  85. package/templates/prettier.config.js +11 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/eslint/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Rule } from 'eslint';
2
+ import type { RuleDoc } from '../../types';
3
+ export declare const doc: RuleDoc;
4
+ declare const rule: Rule.RuleModule;
5
+ export default rule;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.doc = void 0;
4
+ exports.doc = {
5
+ id: 'event-name-format',
6
+ severity: 'warn',
7
+ category: 'standards',
8
+ description: 'eventDispatcher() event names must follow Namespace:Entity:Action format.',
9
+ rationale: 'Consistent naming makes events searchable and self-documenting across all apps.',
10
+ fix: 'Use format "Namespace:Entity:Action" — e.g. "LocationApp:Location:Created". All parts uppercase-first.',
11
+ };
12
+ /**
13
+ * Warn when eventDispatcher() is called with an event name that doesn't follow
14
+ * the Namespace:Entity:Action convention used across all iviva apps.
15
+ * Examples: "LocationApp:Location:Created", "System:UserGroup:Updated"
16
+ */
17
+ const EVENT_FORMAT_RE = /^[A-Z][A-Za-z]+:[A-Z][A-Za-z]+:[A-Z][A-Za-z]+$/;
18
+ const rule = {
19
+ meta: {
20
+ type: 'suggestion',
21
+ docs: {
22
+ description: 'eventDispatcher() event names must follow Namespace:Entity:Action format',
23
+ },
24
+ schema: [],
25
+ messages: {
26
+ badFormat: 'Event name "{{name}}" should follow Namespace:Entity:Action format ' +
27
+ '(e.g. "LocationApp:Location:Created"). All parts must start with uppercase.',
28
+ },
29
+ },
30
+ create(context) {
31
+ return {
32
+ CallExpression(node) {
33
+ const callee = node.callee;
34
+ const isEventDispatcher = (callee.type === 'Identifier' && callee.name === 'eventDispatcher') ||
35
+ (callee.type === 'MemberExpression' &&
36
+ callee.property.type === 'Identifier' &&
37
+ callee.property.name === 'eventDispatcher');
38
+ if (!isEventDispatcher)
39
+ return;
40
+ // eventDispatcher(uuid, eventName, payload)
41
+ // The event name is the second argument
42
+ const nameArg = node.arguments[1];
43
+ if (!nameArg || nameArg.type !== 'Literal')
44
+ return;
45
+ if (typeof nameArg.value !== 'string')
46
+ return;
47
+ if (!EVENT_FORMAT_RE.test(nameArg.value)) {
48
+ context.report({
49
+ node: nameArg,
50
+ messageId: 'badFormat',
51
+ data: { name: nameArg.value },
52
+ });
53
+ }
54
+ },
55
+ };
56
+ },
57
+ };
58
+ exports.default = rule;
59
+ //# sourceMappingURL=event-name-format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-name-format.js","sourceRoot":"","sources":["../../../src/eslint/rules/event-name-format.ts"],"names":[],"mappings":";;;AAGa,QAAA,GAAG,GAAY;IAC1B,EAAE,EAAE,mBAAmB;IACvB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,WAAW;IACrB,WAAW,EAAE,2EAA2E;IACxF,SAAS,EAAE,iFAAiF;IAC5F,GAAG,EAAE,wGAAwG;CAC9G,CAAC;AAEF;;;;GAIG;AACH,MAAM,eAAe,GAAG,gDAAgD,CAAC;AAEzE,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EACT,0EAA0E;SAC7E;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,SAAS,EACP,qEAAqE;gBACrE,6EAA6E;SAChF;KACF;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,cAAc,CAAC,IAAI;gBACjB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;gBAC3B,MAAM,iBAAiB,GACrB,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,IAAI,KAAK,iBAAiB,CAAC;oBACnE,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;wBACjC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;wBACrC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,iBAAiB,CAAC,CAAC;gBAEhD,IAAI,CAAC,iBAAiB;oBAAE,OAAO;gBAE/B,4CAA4C;gBAC5C,wCAAwC;gBACxC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBAClC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;oBAAE,OAAO;gBACnD,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ;oBAAE,OAAO;gBAE9C,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;oBACzC,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,OAAO;wBACb,SAAS,EAAE,WAAW;wBACtB,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE;qBAC9B,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Rule } from 'eslint';
2
+ import type { RuleDoc } from '../../types';
3
+ export declare const doc: RuleDoc;
4
+ declare const rule: Rule.RuleModule;
5
+ export default rule;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.doc = void 0;
4
+ exports.doc = {
5
+ id: 'no-bad-hook-deps',
6
+ severity: 'warn',
7
+ category: 'react',
8
+ description: 'useCallback/useMemo deps should not include stable refs like navigate, toast, or alert.',
9
+ rationale: 'These references never change — including them triggers needless re-memoization on every render.',
10
+ fix: 'Remove navigate, toast, alert, generateURL from the deps array.',
11
+ };
12
+ /**
13
+ * useCallback/useMemo deps should not include toast, alert, navigate, or generateURL
14
+ * as these are stable references that cause unnecessary re-renders when listed.
15
+ */
16
+ const BAD_DEPS = new Set(['toast', 'alert', 'navigate', 'generateURL', 'generateUrl']);
17
+ const rule = {
18
+ meta: {
19
+ type: 'suggestion',
20
+ docs: {
21
+ description: 'useCallback/useMemo deps should not include stable refs like navigate, toast, alert',
22
+ },
23
+ schema: [],
24
+ messages: {
25
+ badDep: '"{{dep}}" is a stable reference and should not be in useCallback/useMemo deps array. Remove it.',
26
+ },
27
+ },
28
+ create(context) {
29
+ return {
30
+ CallExpression(node) {
31
+ const callee = node.callee;
32
+ const hookName = callee.type === 'Identifier' && (callee.name === 'useCallback' || callee.name === 'useMemo')
33
+ ? callee.name
34
+ : null;
35
+ if (!hookName)
36
+ return;
37
+ // Second argument is the deps array
38
+ const depsArg = node.arguments[1];
39
+ if (!depsArg || depsArg.type !== 'ArrayExpression')
40
+ return;
41
+ for (const el of depsArg.elements) {
42
+ if (!el || el.type !== 'Identifier')
43
+ continue;
44
+ if (BAD_DEPS.has(el.name)) {
45
+ context.report({
46
+ node: el,
47
+ messageId: 'badDep',
48
+ data: { dep: el.name },
49
+ });
50
+ }
51
+ }
52
+ },
53
+ };
54
+ },
55
+ };
56
+ exports.default = rule;
57
+ //# sourceMappingURL=no-bad-hook-deps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-bad-hook-deps.js","sourceRoot":"","sources":["../../../src/eslint/rules/no-bad-hook-deps.ts"],"names":[],"mappings":";;;AAGa,QAAA,GAAG,GAAY;IAC1B,EAAE,EAAE,kBAAkB;IACtB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,OAAO;IACjB,WAAW,EAAE,yFAAyF;IACtG,SAAS,EAAE,kGAAkG;IAC7G,GAAG,EAAE,iEAAiE;CACvE,CAAC;AAEF;;;GAGG;AACH,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC;AAEvF,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EAAE,qFAAqF;SACnG;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,MAAM,EACJ,iGAAiG;SACpG;KACF;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,cAAc,CAAC,IAAI;gBACjB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;gBAC3B,MAAM,QAAQ,GACZ,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC;oBAC1F,CAAC,CAAC,MAAM,CAAC,IAAI;oBACb,CAAC,CAAC,IAAI,CAAC;gBAEX,IAAI,CAAC,QAAQ;oBAAE,OAAO;gBAEtB,oCAAoC;gBACpC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBAClC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,iBAAiB;oBAAE,OAAO;gBAE3D,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;oBAClC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,IAAI,KAAK,YAAY;wBAAE,SAAS;oBAC9C,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC1B,OAAO,CAAC,MAAM,CAAC;4BACb,IAAI,EAAE,EAAE;4BACR,SAAS,EAAE,QAAQ;4BACnB,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,IAAI,EAAE;yBACvB,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Rule } from 'eslint';
2
+ import type { RuleDoc } from '../../types';
3
+ export declare const doc: RuleDoc;
4
+ declare const rule: Rule.RuleModule;
5
+ export default rule;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.doc = void 0;
4
+ exports.doc = {
5
+ id: 'no-fa-prefix',
6
+ severity: 'error',
7
+ category: 'standards',
8
+ description: 'Icon strings must not use the fa- prefix (e.g. "fal bell" not "fal fa-bell").',
9
+ rationale: 'UXP icon components strip the fa- prefix internally — including it renders no icon.',
10
+ fix: 'Remove fa- from icon names: `"fal bell"` not `"fal fa-bell"`. Auto-fixable.',
11
+ };
12
+ /**
13
+ * Icon strings must not use the fa- prefix.
14
+ * Correct: "fal bell" Wrong: "fal fa-bell"
15
+ */
16
+ const FA_PREFIX_RE = /\b(fa[lsdbr]?|ph[b]?)\s+fa-[a-z]/;
17
+ const rule = {
18
+ meta: {
19
+ type: 'problem',
20
+ docs: {
21
+ description: 'Icon strings must not use the fa- prefix (e.g. "fal bell" not "fal fa-bell")',
22
+ },
23
+ schema: [],
24
+ messages: {
25
+ noFaPrefix: 'Icon "{{value}}" uses the fa- prefix. Remove it: "{{fixed}}"',
26
+ },
27
+ fixable: 'code',
28
+ },
29
+ create(context) {
30
+ function checkString(node, value, quote = "'") {
31
+ if (!FA_PREFIX_RE.test(value))
32
+ return;
33
+ const fixed = value.replace(/\bfa-/g, '');
34
+ context.report({
35
+ node,
36
+ messageId: 'noFaPrefix',
37
+ data: { value, fixed },
38
+ fix: (fixer) => fixer.replaceText(node, `${quote}${fixed}${quote}`),
39
+ });
40
+ }
41
+ return {
42
+ Literal(node) {
43
+ if (typeof node.value === 'string') {
44
+ checkString(node, node.value, "'");
45
+ }
46
+ },
47
+ // JSXAttribute: icon="fal fa-bell" — access via any since @types/eslint doesn't expose JSX types
48
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
+ JSXAttribute(node) {
50
+ const val = node.value;
51
+ if (val && val.type === 'Literal' && typeof val.value === 'string') {
52
+ checkString(val, val.value, '"');
53
+ }
54
+ },
55
+ };
56
+ },
57
+ };
58
+ exports.default = rule;
59
+ //# sourceMappingURL=no-fa-prefix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-fa-prefix.js","sourceRoot":"","sources":["../../../src/eslint/rules/no-fa-prefix.ts"],"names":[],"mappings":";;;AAGa,QAAA,GAAG,GAAY;IAC1B,EAAE,EAAE,cAAc;IAClB,QAAQ,EAAE,OAAO;IACjB,QAAQ,EAAE,WAAW;IACrB,WAAW,EAAE,+EAA+E;IAC5F,SAAS,EAAE,qFAAqF;IAChG,GAAG,EAAE,6EAA6E;CACnF,CAAC;AAEF;;;GAGG;AACH,MAAM,YAAY,GAAG,kCAAkC,CAAC;AAExD,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,8EAA8E;SAC5F;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,UAAU,EAAE,8DAA8D;SAC3E;QACD,OAAO,EAAE,MAAM;KAChB;IACD,MAAM,CAAC,OAAO;QACZ,SAAS,WAAW,CAAC,IAAe,EAAE,KAAa,EAAE,KAAK,GAAG,GAAG;YAC9D,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;gBAAE,OAAO;YACtC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC1C,OAAO,CAAC,MAAM,CAAC;gBACb,IAAI;gBACJ,SAAS,EAAE,YAAY;gBACvB,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;gBACtB,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,EAAE,CAAC;aACpE,CAAC,CAAC;QACL,CAAC;QAED,OAAO;YACL,OAAO,CAAC,IAAI;gBACV,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;oBACnC,WAAW,CAAC,IAAiB,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBAClD,CAAC;YACH,CAAC;YACD,iGAAiG;YACjG,8DAA8D;YAC9D,YAAY,CAAC,IAAS;gBACpB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC;gBACvB,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;oBACnE,WAAW,CAAC,GAAgB,EAAE,GAAG,CAAC,KAAe,EAAE,GAAG,CAAC,CAAC;gBAC1D,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Rule } from 'eslint';
2
+ import type { RuleDoc } from '../../types';
3
+ export declare const doc: RuleDoc;
4
+ declare const rule: Rule.RuleModule;
5
+ export default rule;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.doc = void 0;
4
+ exports.doc = {
5
+ id: 'no-hardcoded-jsx-text',
6
+ severity: 'warn',
7
+ category: 'patterns',
8
+ description: 'Visible JSX text must use uxpContext.$L() for localization, not raw strings.',
9
+ rationale: 'All 3 reference apps localize every visible string. Hardcoded text will not be translated.',
10
+ fix: 'Replace text with `{uxpContext.$L("app.key")}`. Exempt: whitespace, single chars, pure numbers.',
11
+ };
12
+ /**
13
+ * Warn when JSX contains a literal text node instead of a localization call.
14
+ * All visible strings in iviva apps use uxpContext.$L('key').
15
+ */
16
+ // Strings that are exempt — punctuation, single chars, pure numbers
17
+ const EXEMPT_RE = /^[\s|/\-.,;:!?()[\]{}*+=#@%^&~`'"<>_]*$|^\d+(\.\d+)?$/;
18
+ const rule = {
19
+ meta: {
20
+ type: 'suggestion',
21
+ docs: {
22
+ description: 'Visible JSX text must use uxpContext.$L() for localization, not raw strings',
23
+ },
24
+ schema: [],
25
+ messages: {
26
+ hardcodedText: 'Hardcoded text "{{text}}" — use uxpContext.$L(\'app.key\') for localization',
27
+ },
28
+ },
29
+ create(context) {
30
+ // Only apply to .tsx files (JSX)
31
+ const filename = context.getFilename();
32
+ if (!filename.endsWith('.tsx'))
33
+ return {};
34
+ return {
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ JSXText(node) {
37
+ const raw = node.value;
38
+ const trimmed = raw.trim();
39
+ if (!trimmed)
40
+ return; // whitespace only
41
+ if (EXEMPT_RE.test(trimmed))
42
+ return; // punctuation / numbers
43
+ if (trimmed.length <= 1)
44
+ return; // single char
45
+ context.report({
46
+ node: node,
47
+ messageId: 'hardcodedText',
48
+ data: { text: trimmed.length > 40 ? trimmed.slice(0, 40) + '…' : trimmed },
49
+ });
50
+ },
51
+ };
52
+ },
53
+ };
54
+ exports.default = rule;
55
+ //# sourceMappingURL=no-hardcoded-jsx-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-hardcoded-jsx-text.js","sourceRoot":"","sources":["../../../src/eslint/rules/no-hardcoded-jsx-text.ts"],"names":[],"mappings":";;;AAGa,QAAA,GAAG,GAAY;IAC1B,EAAE,EAAE,uBAAuB;IAC3B,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,UAAU;IACpB,WAAW,EAAE,8EAA8E;IAC3F,SAAS,EAAE,4FAA4F;IACvG,GAAG,EAAE,iGAAiG;CACvG,CAAC;AAEF;;;GAGG;AAEH,oEAAoE;AACpE,MAAM,SAAS,GAAG,uDAAuD,CAAC;AAE1E,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EAAE,6EAA6E;SAC3F;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,aAAa,EACX,6EAA6E;SAChF;KACF;IACD,MAAM,CAAC,OAAO;QACZ,iCAAiC;QACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;QACvC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QAE1C,OAAO;YACL,8DAA8D;YAC9D,OAAO,CAAC,IAAS;gBACf,MAAM,GAAG,GAAG,IAAI,CAAC,KAAe,CAAC;gBACjC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;gBAC3B,IAAI,CAAC,OAAO;oBAAE,OAAO,CAAC,kBAAkB;gBACxC,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;oBAAE,OAAO,CAAC,wBAAwB;gBAC7D,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC;oBAAE,OAAO,CAAC,cAAc;gBAE/C,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,IAAiB;oBACvB,SAAS,EAAE,eAAe;oBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE;iBAC3E,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Rule } from 'eslint';
2
+ import type { RuleDoc } from '../../types';
3
+ export declare const doc: RuleDoc;
4
+ /**
5
+ * Disallow inline style props in JSX: style={{ ... }}
6
+ */
7
+ declare const rule: Rule.RuleModule;
8
+ export default rule;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.doc = void 0;
4
+ exports.doc = {
5
+ id: 'no-inline-styles',
6
+ severity: 'error',
7
+ category: 'react',
8
+ description: 'JSX elements must not use inline style={{...}} props.',
9
+ rationale: 'Inline styles bypass the design system, break theming, and cause performance issues.',
10
+ fix: 'Move styles to a SCSS file and use className instead.',
11
+ };
12
+ /**
13
+ * Disallow inline style props in JSX: style={{ ... }}
14
+ */
15
+ const rule = {
16
+ meta: {
17
+ type: 'problem',
18
+ docs: {
19
+ description: 'Disallow inline style={{...}} in JSX — use SCSS classes instead',
20
+ },
21
+ schema: [],
22
+ messages: {
23
+ noInlineStyles: 'Avoid inline styles. Move styles to SCSS and use className.',
24
+ },
25
+ },
26
+ create(context) {
27
+ return {
28
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
+ JSXAttribute(node) {
30
+ if (node.name &&
31
+ node.name.type === 'JSXIdentifier' &&
32
+ node.name.name === 'style' &&
33
+ node.value !== null) {
34
+ context.report({ node: node, messageId: 'noInlineStyles' });
35
+ }
36
+ },
37
+ };
38
+ },
39
+ };
40
+ exports.default = rule;
41
+ //# sourceMappingURL=no-inline-styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-inline-styles.js","sourceRoot":"","sources":["../../../src/eslint/rules/no-inline-styles.ts"],"names":[],"mappings":";;;AAGa,QAAA,GAAG,GAAY;IAC1B,EAAE,EAAE,kBAAkB;IACtB,QAAQ,EAAE,OAAO;IACjB,QAAQ,EAAE,OAAO;IACjB,WAAW,EAAE,uDAAuD;IACpE,SAAS,EAAE,sFAAsF;IACjG,GAAG,EAAE,uDAAuD;CAC7D,CAAC;AAEF;;GAEG;AACH,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,iEAAiE;SAC/E;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,cAAc,EAAE,6DAA6D;SAC9E;KACF;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,8DAA8D;YAC9D,YAAY,CAAC,IAAS;gBACpB,IACE,IAAI,CAAC,IAAI;oBACT,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe;oBAClC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO;oBAC1B,IAAI,CAAC,KAAK,KAAK,IAAI,EACnB,CAAC;oBACD,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAiB,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,CAAC;gBAC3E,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Rule } from 'eslint';
2
+ import type { RuleDoc } from '../../types';
3
+ export declare const doc: RuleDoc;
4
+ declare const rule: Rule.RuleModule;
5
+ export default rule;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.doc = void 0;
4
+ exports.doc = {
5
+ id: 'no-native-html-interactive',
6
+ severity: 'warn',
7
+ category: 'patterns',
8
+ description: 'Use UXP component equivalents instead of raw interactive HTML elements.',
9
+ rationale: 'Raw HTML bypasses the design system — no theming, accessibility, or localization support.',
10
+ fix: 'Use ButtonComponent, Input, Select, ObjectSearchComponent, SlideInForm, etc. instead of button/input/table/form.',
11
+ };
12
+ /**
13
+ * Warn when raw interactive HTML elements are used instead of UXP equivalents.
14
+ * All 3 reference apps use UXP ButtonComponent, Input, etc. — never raw HTML for interactive UI.
15
+ * Layout elements (div, span, section, article, p, h1-h6, img) are fine.
16
+ */
17
+ const INTERACTIVE_ELEMENTS = new Set([
18
+ 'button',
19
+ 'input',
20
+ 'select',
21
+ 'textarea',
22
+ 'table',
23
+ 'thead',
24
+ 'tbody',
25
+ 'tfoot',
26
+ 'tr',
27
+ 'th',
28
+ 'td',
29
+ 'form',
30
+ 'fieldset',
31
+ ]);
32
+ const UXP_SUGGESTIONS = {
33
+ button: 'ButtonComponent or IconButton',
34
+ input: 'Input, PasswordInput, or FormField',
35
+ select: 'Select or MultiSelect',
36
+ textarea: 'TextArea',
37
+ table: 'ObjectSearchComponent or SimpleConfigurationTable',
38
+ thead: 'ObjectSearchComponent (manages table structure)',
39
+ tbody: 'ObjectSearchComponent (manages table structure)',
40
+ tr: 'ObjectSearchComponent (manages table structure)',
41
+ th: 'ObjectSearchComponent (manages table structure)',
42
+ td: 'ObjectSearchComponent (manages table structure)',
43
+ form: 'SlideInForm with formStructure',
44
+ fieldset: 'FormField with sections',
45
+ };
46
+ const rule = {
47
+ meta: {
48
+ type: 'suggestion',
49
+ docs: {
50
+ description: 'Use UXP component equivalents instead of raw interactive HTML elements',
51
+ },
52
+ schema: [],
53
+ messages: {
54
+ nativeElement: 'Use UXP {{suggestion}} instead of <{{element}}>. Raw interactive elements bypass the design system.',
55
+ },
56
+ },
57
+ create(context) {
58
+ return {
59
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
60
+ JSXOpeningElement(node) {
61
+ var _a;
62
+ const nameNode = node.name;
63
+ if (!nameNode || nameNode.type !== 'JSXIdentifier')
64
+ return;
65
+ const name = nameNode.name;
66
+ if (!INTERACTIVE_ELEMENTS.has(name))
67
+ return;
68
+ context.report({
69
+ node: node,
70
+ messageId: 'nativeElement',
71
+ data: {
72
+ element: name,
73
+ suggestion: (_a = UXP_SUGGESTIONS[name]) !== null && _a !== void 0 ? _a : 'a UXP equivalent',
74
+ },
75
+ });
76
+ },
77
+ };
78
+ },
79
+ };
80
+ exports.default = rule;
81
+ //# sourceMappingURL=no-native-html-interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-native-html-interactive.js","sourceRoot":"","sources":["../../../src/eslint/rules/no-native-html-interactive.ts"],"names":[],"mappings":";;;AAGa,QAAA,GAAG,GAAY;IAC1B,EAAE,EAAE,4BAA4B;IAChC,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,UAAU;IACpB,WAAW,EAAE,yEAAyE;IACtF,SAAS,EAAE,2FAA2F;IACtG,GAAG,EAAE,kHAAkH;CACxH,CAAC;AAEF;;;;GAIG;AACH,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,UAAU;IACV,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,MAAM;IACN,UAAU;CACX,CAAC,CAAC;AAEH,MAAM,eAAe,GAA2B;IAC9C,MAAM,EAAE,+BAA+B;IACvC,KAAK,EAAE,oCAAoC;IAC3C,MAAM,EAAE,uBAAuB;IAC/B,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,mDAAmD;IAC1D,KAAK,EAAE,iDAAiD;IACxD,KAAK,EAAE,iDAAiD;IACxD,EAAE,EAAE,iDAAiD;IACrD,EAAE,EAAE,iDAAiD;IACrD,EAAE,EAAE,iDAAiD;IACrD,IAAI,EAAE,gCAAgC;IACtC,QAAQ,EAAE,yBAAyB;CACpC,CAAC;AAEF,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EAAE,wEAAwE;SACtF;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,aAAa,EACX,qGAAqG;SACxG;KACF;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,8DAA8D;YAC9D,iBAAiB,CAAC,IAAS;;gBACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;gBAC3B,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,eAAe;oBAAE,OAAO;gBAC3D,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAc,CAAC;gBACrC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC;oBAAE,OAAO;gBAE5C,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,IAAiB;oBACvB,SAAS,EAAE,eAAe;oBAC1B,IAAI,EAAE;wBACJ,OAAO,EAAE,IAAI;wBACb,UAAU,EAAE,MAAA,eAAe,CAAC,IAAI,CAAC,mCAAI,kBAAkB;qBACxD;iBACF,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Rule } from 'eslint';
2
+ import type { RuleDoc } from '../../types';
3
+ export declare const doc: RuleDoc;
4
+ /**
5
+ * Require view components to be wrapped with React.memo().
6
+ * Targets files under src/views/ — exported const components must use memo().
7
+ */
8
+ declare const rule: Rule.RuleModule;
9
+ export default rule;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.doc = void 0;
4
+ exports.doc = {
5
+ id: 'require-memo',
6
+ severity: 'error',
7
+ category: 'react',
8
+ description: 'View components exported from src/views/ must be wrapped with memo().',
9
+ rationale: 'Prevents unnecessary re-renders in the UXP host shell when parent state changes.',
10
+ fix: 'Wrap with memo: `export const MyView = memo(MyViewBase);`',
11
+ };
12
+ /**
13
+ * Require view components to be wrapped with React.memo().
14
+ * Targets files under src/views/ — exported const components must use memo().
15
+ */
16
+ const rule = {
17
+ meta: {
18
+ type: 'problem',
19
+ docs: {
20
+ description: 'View components exported from src/views/ must be wrapped with memo()',
21
+ },
22
+ schema: [],
23
+ messages: {
24
+ requireMemo: 'Component "{{name}}" should be wrapped with memo(). Use: export const {{name}} = memo({{name}}Base);',
25
+ },
26
+ },
27
+ create(context) {
28
+ // Only apply to files inside a views/ directory
29
+ const filename = context.getFilename();
30
+ if (!filename.includes(`${require('path').sep}views${require('path').sep}`) &&
31
+ !filename.includes('/views/')) {
32
+ return {};
33
+ }
34
+ return {
35
+ ExportNamedDeclaration(node) {
36
+ if (!node.declaration)
37
+ return;
38
+ // export const Foo = ...
39
+ if (node.declaration.type === 'VariableDeclaration') {
40
+ for (const decl of node.declaration.declarations) {
41
+ if (decl.id.type !== 'Identifier')
42
+ continue;
43
+ const name = decl.id.name;
44
+ if (!decl.init)
45
+ continue;
46
+ const init = decl.init;
47
+ // Check if the init is a memo(...) call
48
+ const isMemo = (init.type === 'CallExpression' &&
49
+ ((init.callee.type === 'Identifier' && init.callee.name === 'memo') ||
50
+ (init.callee.type === 'MemberExpression' &&
51
+ init.callee.property.type === 'Identifier' &&
52
+ init.callee.property.name === 'memo')));
53
+ if (!isMemo) {
54
+ // Only flag if it looks like a component (PascalCase)
55
+ if (/^[A-Z]/.test(name)) {
56
+ context.report({
57
+ node: decl,
58
+ messageId: 'requireMemo',
59
+ data: { name },
60
+ });
61
+ }
62
+ }
63
+ }
64
+ }
65
+ },
66
+ };
67
+ },
68
+ };
69
+ exports.default = rule;
70
+ //# sourceMappingURL=require-memo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-memo.js","sourceRoot":"","sources":["../../../src/eslint/rules/require-memo.ts"],"names":[],"mappings":";;;AAGa,QAAA,GAAG,GAAY;IAC1B,EAAE,EAAE,cAAc;IAClB,QAAQ,EAAE,OAAO;IACjB,QAAQ,EAAE,OAAO;IACjB,WAAW,EAAE,uEAAuE;IACpF,SAAS,EAAE,kFAAkF;IAC7F,GAAG,EAAE,2DAA2D;CACjE,CAAC;AAEF;;;GAGG;AACH,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,sEAAsE;SACpF;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,WAAW,EAAE,sGAAsG;SACpH;KACF;IACD,MAAM,CAAC,OAAO;QACZ,gDAAgD;QAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;QACvC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,QAAQ,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC;YACvE,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAClC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO;YACL,sBAAsB,CAAC,IAAI;gBACzB,IAAI,CAAC,IAAI,CAAC,WAAW;oBAAE,OAAO;gBAE9B,yBAAyB;gBACzB,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;oBACpD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC;wBACjD,IAAI,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,YAAY;4BAAE,SAAS;wBAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;wBAC1B,IAAI,CAAC,IAAI,CAAC,IAAI;4BAAE,SAAS;wBAEzB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;wBACvB,wCAAwC;wBACxC,MAAM,MAAM,GACV,CAAC,IAAI,CAAC,IAAI,KAAK,gBAAgB;4BAC7B,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC;gCACjE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;oCACtC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oCAC1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;wBAEhD,IAAI,CAAC,MAAM,EAAE,CAAC;4BACZ,sDAAsD;4BACtD,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gCACxB,OAAO,CAAC,MAAM,CAAC;oCACb,IAAI,EAAE,IAAI;oCACV,SAAS,EAAE,aAAa;oCACxB,IAAI,EAAE,EAAE,IAAI,EAAE;iCACf,CAAC,CAAC;4BACL,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Rule } from 'eslint';
2
+ import type { RuleDoc } from '../../types';
3
+ export declare const doc: RuleDoc;
4
+ declare const rule: Rule.RuleModule;
5
+ export default rule;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.doc = void 0;
4
+ exports.doc = {
5
+ id: 'service-config-shape',
6
+ severity: 'error',
7
+ category: 'standards',
8
+ description: 'ExecuteServiceConfig objects must have type, app, service, options, and defaultValue.',
9
+ rationale: 'Missing fields cause silent runtime failures — the service call silently returns undefined.',
10
+ fix: 'Ensure all 5 fields are present: `{ type: "service", app: "App", service: "Svc:Method", options: { json: true }, defaultValue: null }`',
11
+ };
12
+ /**
13
+ * ExecuteServiceConfig objects must have type, app, service, options, defaultValue.
14
+ * Detects object literals returned from service config functions in services.ts.
15
+ */
16
+ const REQUIRED_KEYS = ['type', 'app', 'service', 'options', 'defaultValue'];
17
+ const rule = {
18
+ meta: {
19
+ type: 'problem',
20
+ docs: {
21
+ description: 'ExecuteServiceConfig must have type, app, service, options, defaultValue',
22
+ },
23
+ schema: [],
24
+ messages: {
25
+ missingKeys: 'Service config object is missing required keys: {{missing}}. ' +
26
+ 'All ExecuteServiceConfig objects need: type, app, service, options: {json:true}, defaultValue',
27
+ },
28
+ },
29
+ create(context) {
30
+ // Only apply to files named services.ts or services.tsx
31
+ const filename = context.getFilename();
32
+ if (!filename.endsWith('services.ts') && !filename.endsWith('services.tsx'))
33
+ return {};
34
+ return {
35
+ // Arrow function returning an object literal: (params) => ({ type: 'service', ... })
36
+ ArrowFunctionExpression(node) {
37
+ let objExpr = node.body.type === 'ObjectExpression'
38
+ ? node.body
39
+ : node.body.type === 'BlockStatement'
40
+ ? null
41
+ : null;
42
+ // Handle: () => ({ ... }) — parenthesized object
43
+ if (!objExpr && node.body.type === 'ObjectExpression') {
44
+ objExpr = node.body;
45
+ }
46
+ if (!objExpr)
47
+ return;
48
+ checkObjectExpression(objExpr, node, context);
49
+ },
50
+ // Regular return statement: return { type: 'service', ... }
51
+ ReturnStatement(node) {
52
+ if (!node.argument || node.argument.type !== 'ObjectExpression')
53
+ return;
54
+ checkObjectExpression(node.argument, node, context);
55
+ },
56
+ };
57
+ },
58
+ };
59
+ function checkObjectExpression(obj, reportNode, context) {
60
+ const keys = obj.properties
61
+ .filter((p) => p.type === 'Property')
62
+ .map((p) => {
63
+ const prop = p;
64
+ return prop.key.type === 'Identifier' ? prop.key.name : null;
65
+ })
66
+ .filter(Boolean);
67
+ // Only check if this looks like a service config (has 'type' or 'service')
68
+ if (!keys.includes('type') && !keys.includes('service'))
69
+ return;
70
+ const missing = REQUIRED_KEYS.filter((k) => !keys.includes(k));
71
+ if (missing.length > 0) {
72
+ context.report({
73
+ node: reportNode,
74
+ messageId: 'missingKeys',
75
+ data: { missing: missing.join(', ') },
76
+ });
77
+ }
78
+ }
79
+ exports.default = rule;
80
+ //# sourceMappingURL=service-config-shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-config-shape.js","sourceRoot":"","sources":["../../../src/eslint/rules/service-config-shape.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Rule } from 'eslint';
2
+ import type { RuleDoc } from '../../types';
3
+ export declare const doc: RuleDoc;
4
+ declare const rule: Rule.RuleModule;
5
+ export default rule;