@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.
- package/README.md +273 -0
- package/bin/uxp-lint.js +2 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +100 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.js +42 -0
- package/dist/config.js.map +1 -0
- package/dist/eslint/config.d.ts +2 -0
- package/dist/eslint/config.js +225 -0
- package/dist/eslint/config.js.map +1 -0
- package/dist/eslint/rules/event-name-format.d.ts +5 -0
- package/dist/eslint/rules/event-name-format.js +59 -0
- package/dist/eslint/rules/event-name-format.js.map +1 -0
- package/dist/eslint/rules/no-bad-hook-deps.d.ts +5 -0
- package/dist/eslint/rules/no-bad-hook-deps.js +57 -0
- package/dist/eslint/rules/no-bad-hook-deps.js.map +1 -0
- package/dist/eslint/rules/no-fa-prefix.d.ts +5 -0
- package/dist/eslint/rules/no-fa-prefix.js +59 -0
- package/dist/eslint/rules/no-fa-prefix.js.map +1 -0
- package/dist/eslint/rules/no-hardcoded-jsx-text.d.ts +5 -0
- package/dist/eslint/rules/no-hardcoded-jsx-text.js +55 -0
- package/dist/eslint/rules/no-hardcoded-jsx-text.js.map +1 -0
- package/dist/eslint/rules/no-inline-styles.d.ts +8 -0
- package/dist/eslint/rules/no-inline-styles.js +41 -0
- package/dist/eslint/rules/no-inline-styles.js.map +1 -0
- package/dist/eslint/rules/no-native-html-interactive.d.ts +5 -0
- package/dist/eslint/rules/no-native-html-interactive.js +81 -0
- package/dist/eslint/rules/no-native-html-interactive.js.map +1 -0
- package/dist/eslint/rules/require-memo.d.ts +9 -0
- package/dist/eslint/rules/require-memo.js +70 -0
- package/dist/eslint/rules/require-memo.js.map +1 -0
- package/dist/eslint/rules/service-config-shape.d.ts +5 -0
- package/dist/eslint/rules/service-config-shape.js +80 -0
- package/dist/eslint/rules/service-config-shape.js.map +1 -0
- package/dist/eslint/rules/url-params-form-state.d.ts +5 -0
- package/dist/eslint/rules/url-params-form-state.js +75 -0
- package/dist/eslint/rules/url-params-form-state.js.map +1 -0
- package/dist/reporter.d.ts +22 -0
- package/dist/reporter.js +260 -0
- package/dist/reporter.js.map +1 -0
- package/dist/rule-registry.d.ts +2 -0
- package/dist/rule-registry.js +46 -0
- package/dist/rule-registry.js.map +1 -0
- package/dist/rules-reader.d.ts +4 -0
- package/dist/rules-reader.js +16 -0
- package/dist/rules-reader.js.map +1 -0
- package/dist/runner.d.ts +7 -0
- package/dist/runner.js +62 -0
- package/dist/runner.js.map +1 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.js +80 -0
- package/dist/setup.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.js +39 -0
- package/dist/types.js.map +1 -0
- package/dist/validators/ai.d.ts +2 -0
- package/dist/validators/ai.js +115 -0
- package/dist/validators/ai.js.map +1 -0
- package/dist/validators/bulk-imports.d.ts +3 -0
- package/dist/validators/bulk-imports.js +94 -0
- package/dist/validators/bulk-imports.js.map +1 -0
- package/dist/validators/bundle-json.d.ts +3 -0
- package/dist/validators/bundle-json.js +130 -0
- package/dist/validators/bundle-json.js.map +1 -0
- package/dist/validators/bundle-size.d.ts +3 -0
- package/dist/validators/bundle-size.js +51 -0
- package/dist/validators/bundle-size.js.map +1 -0
- package/dist/validators/config-yml.d.ts +3 -0
- package/dist/validators/config-yml.js +148 -0
- package/dist/validators/config-yml.js.map +1 -0
- package/dist/validators/duplication.d.ts +3 -0
- package/dist/validators/duplication.js +65 -0
- package/dist/validators/duplication.js.map +1 -0
- package/dist/validators/folder-structure.d.ts +3 -0
- package/dist/validators/folder-structure.js +123 -0
- package/dist/validators/folder-structure.js.map +1 -0
- package/dist/validators/formatting.d.ts +3 -0
- package/dist/validators/formatting.js +97 -0
- package/dist/validators/formatting.js.map +1 -0
- package/dist/validators/scss-rules.d.ts +3 -0
- package/dist/validators/scss-rules.js +156 -0
- package/dist/validators/scss-rules.js.map +1 -0
- package/package.json +58 -0
- 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,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,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,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,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,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,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,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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"}
|