@ethisyscore/eslint-plugin-coreconnect 1.76.0 → 1.77.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethisyscore/eslint-plugin-coreconnect",
3
- "version": "1.76.0",
3
+ "version": "1.77.0",
4
4
  "description": "ESLint rules enforcing EthisysCore plugin frontend conventions. Published so a new rule reaches every plugin on a version bump, rather than being copied into each scaffold and drifting.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -4,6 +4,7 @@ import noInlineStringUnion from "./rules/no-inline-string-union.js";
4
4
  import noLocalDataGrid from "./rules/no-local-data-grid.js";
5
5
  import noLocalDateInput from "./rules/no-local-date-input.js";
6
6
  import noLocalEmptyState from "./rules/no-local-empty-state.js";
7
+ import noLocalMappingEditor from "./rules/no-local-mapping-editor.js";
7
8
  import noLocalSearchInput from "./rules/no-local-search-input.js";
8
9
  import noParamInNavPath from "./rules/no-param-in-nav-path.js";
9
10
 
@@ -14,6 +15,7 @@ const rules = {
14
15
  "no-local-data-grid": noLocalDataGrid,
15
16
  "no-local-date-input": noLocalDateInput,
16
17
  "no-local-empty-state": noLocalEmptyState,
18
+ "no-local-mapping-editor": noLocalMappingEditor,
17
19
  "no-local-search-input": noLocalSearchInput,
18
20
  "no-param-in-nav-path": noParamInNavPath,
19
21
  };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Disallow a plugin declaring its own connector-mapping field-translation editor.
3
+ *
4
+ * The backstop to the promotion that finished the Tool Mappings surface. Measured on origin/develop:
5
+ * `ConnectorMappingTranslationEditorView.tsx` existed in FOUR places - the host's gogo-ui adapter
6
+ * plus `self-healing`, `tech` and `timesheets` - at 592/522/527/527 lines, and the copies had
7
+ * already drifted in three ways, one of them a live defect:
8
+ *
9
+ * - `self-healing` rendered the "Test mapping" button unconditionally. Its enclosing block opens
10
+ * on `(onTestMapping || onSuggestTranslation)`, so a consumer wiring only auto-configure got a
11
+ * button whose handler returns on its first line - a DEAD CONTROL. Nobody noticed, because
12
+ * there was no single source to notice it against.
13
+ * - `self-healing` washed two panels with a literal `rgba(0,0,0,0.03)`, invisible in dark mode.
14
+ * - `self-healing` carried emoji in the extraction chips, on top of the icon and colour the chip
15
+ * already had.
16
+ *
17
+ * Meanwhile the three plugin copies had dropped the HOST's `?? []` coalescing on the canonical field
18
+ * lists, which is the only thing standing between an operation with no canonical schema and a
19
+ * TypeError - the host copy carries a comment recording that exact crash. So each copy held a fix
20
+ * the others lacked, in both directions. That is what makes duplication here expensive rather than
21
+ * merely untidy, and it is why the rule reports rather than warns.
22
+ *
23
+ * Fires on a DECLARATION, never a use, so importing the shared component from
24
+ * `@ethisyscore/plugin-ui/components/connectors` and rendering it is exactly what the rule wants -
25
+ * as is a local wrapper that composes it, which the shared helper exempts.
26
+ *
27
+ * @type {import("eslint").Rule.RuleModule}
28
+ */
29
+ import { createNoLocalComponentRule } from "./componentDeclarations.js";
30
+
31
+ export default createNoLocalComponentRule({
32
+ // Every branch requires the MAPPING context, and that is the whole design of this pattern.
33
+ //
34
+ // A bare `Editor$` is unusable here: measured across the plugin repos, legitimate local editors
35
+ // ending in `Editor` include `BreachAssessmentTaskTemplateEditor`, `BusinessHoursHolidaysEditor`,
36
+ // `SlaPolicyEscalationRulesEditor`, `SupplierDdIntervalDaysByTierEditor`,
37
+ // `SupplementSequenceEditorView` and `InlineMessageEditor` - none of them this component. A bare
38
+ // `TranslationEditor$` is no better, because the estate runs i18next and a localisation admin
39
+ // screen would carry exactly that name.
40
+ //
41
+ // So branch one needs the literal `Mapping` before `Editor`, which also spares
42
+ // `LicenceTypeSeverityMapEditor` (`Map`, not `Mapping`); branch two allows the `Mapping` token to
43
+ // be dropped only when `Connector` or `Tool` is present instead, which is how a rename would most
44
+ // plausibly still mean this component. `(View|Dialog)` is optional so both the adapter-view
45
+ // spelling and a dialog-named rewrite match. Hook names are excluded by the shared helper, so
46
+ // `useTranslationEditor` and `useMappingEditor` do not match, and lowercase `translationEditorView`
47
+ // - a real local variable in two of these repos - is excluded as a non-component name.
48
+ pattern: /(Mapping(Translation)?Editor|(Connector|Tool)Translation(Field)?Editor)(View|Dialog)?$/,
49
+ canonical: {
50
+ source: "@ethisyscore/plugin-ui/components/connectors",
51
+ name: "ConnectorMappingTranslationEditorView",
52
+ },
53
+ messageId: "noLocalMappingEditor",
54
+ description:
55
+ "Disallow a locally-declared connector-mapping translation editor - import ConnectorMappingTranslationEditorView from @ethisyscore/plugin-ui/components/connectors",
56
+ message:
57
+ "'{{name}}' re-declares the connector-mapping translation editor. Import { ConnectorMappingTranslationEditorView } from '@ethisyscore/plugin-ui/components/connectors' instead: four copies had already drifted, one of them rendering a dead 'Test mapping' button and three of them dropping the null tolerance on the canonical field lists. If this edits something other than a connector mapping, rename it so it does not read as one.",
58
+ });