@dereekb/dbx-web 13.21.0 → 13.23.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.
@@ -1426,7 +1426,7 @@
1426
1426
  return result;
1427
1427
  }
1428
1428
 
1429
- function _array_like_to_array(arr, len) {
1429
+ function _array_like_to_array$1(arr, len) {
1430
1430
  if (len == null || len > arr.length) len = arr.length;
1431
1431
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
1432
1432
  return arr2;
@@ -1434,10 +1434,10 @@ function _array_like_to_array(arr, len) {
1434
1434
  function _array_with_holes(arr) {
1435
1435
  if (Array.isArray(arr)) return arr;
1436
1436
  }
1437
- function _array_without_holes(arr) {
1438
- if (Array.isArray(arr)) return _array_like_to_array(arr);
1437
+ function _array_without_holes$1(arr) {
1438
+ if (Array.isArray(arr)) return _array_like_to_array$1(arr);
1439
1439
  }
1440
- function _iterable_to_array(iter) {
1440
+ function _iterable_to_array$1(iter) {
1441
1441
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
1442
1442
  }
1443
1443
  function _iterable_to_array_limit(arr, i) {
@@ -1467,26 +1467,26 @@ function _iterable_to_array_limit(arr, i) {
1467
1467
  function _non_iterable_rest() {
1468
1468
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
1469
1469
  }
1470
- function _non_iterable_spread() {
1470
+ function _non_iterable_spread$1() {
1471
1471
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
1472
1472
  }
1473
1473
  function _sliced_to_array(arr, i) {
1474
- return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
1474
+ return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array$1(arr, i) || _non_iterable_rest();
1475
1475
  }
1476
- function _to_consumable_array(arr) {
1477
- return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
1476
+ function _to_consumable_array$1(arr) {
1477
+ return _array_without_holes$1(arr) || _iterable_to_array$1(arr) || _unsupported_iterable_to_array$1(arr) || _non_iterable_spread$1();
1478
1478
  }
1479
- function _type_of(obj) {
1479
+ function _type_of$1(obj) {
1480
1480
  "@swc/helpers - typeof";
1481
1481
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
1482
1482
  }
1483
- function _unsupported_iterable_to_array(o, minLen) {
1483
+ function _unsupported_iterable_to_array$1(o, minLen) {
1484
1484
  if (!o) return;
1485
- if (typeof o === "string") return _array_like_to_array(o, minLen);
1485
+ if (typeof o === "string") return _array_like_to_array$1(o, minLen);
1486
1486
  var n = Object.prototype.toString.call(o).slice(8, -1);
1487
1487
  if (n === "Object" && o.constructor) n = o.constructor.name;
1488
1488
  if (n === "Map" || n === "Set") return Array.from(n);
1489
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
1489
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$1(o, minLen);
1490
1490
  }
1491
1491
  /**
1492
1492
  * Module that exposes the `toSignal` factory.
@@ -2036,7 +2036,7 @@ function _unsupported_iterable_to_array(o, minLen) {
2036
2036
  }
2037
2037
  }
2038
2038
  }
2039
- } else if (child && (typeof child === "undefined" ? "undefined" : _type_of(child)) === 'object' && typeof child.type === 'string') {
2039
+ } else if (child && (typeof child === "undefined" ? "undefined" : _type_of$1(child)) === 'object' && typeof child.type === 'string') {
2040
2040
  walk(child, conditional, state);
2041
2041
  }
2042
2042
  }
@@ -2436,7 +2436,7 @@ function _unsupported_iterable_to_array(o, minLen) {
2436
2436
  * @returns The expression text with every flagged call site replaced.
2437
2437
  */ function substituteInExpression(plan, sourceCode) {
2438
2438
  var bodyStart = plan.body.range[0];
2439
- var ordered = _to_consumable_array(plan.replacements).sort(function(a, b) {
2439
+ var ordered = _to_consumable_array$1(plan.replacements).sort(function(a, b) {
2440
2440
  return b.node.range[0] - a.node.range[0];
2441
2441
  });
2442
2442
  var result = sourceCode.getText(plan.body);
@@ -2514,6 +2514,411 @@ function _unsupported_iterable_to_array(o, minLen) {
2514
2514
  return preview;
2515
2515
  }
2516
2516
 
2517
+ function _array_like_to_array(arr, len) {
2518
+ if (len == null || len > arr.length) len = arr.length;
2519
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
2520
+ return arr2;
2521
+ }
2522
+ function _array_without_holes(arr) {
2523
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
2524
+ }
2525
+ function _iterable_to_array(iter) {
2526
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
2527
+ }
2528
+ function _non_iterable_spread() {
2529
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
2530
+ }
2531
+ function _to_consumable_array(arr) {
2532
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
2533
+ }
2534
+ function _type_of(obj) {
2535
+ "@swc/helpers - typeof";
2536
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
2537
+ }
2538
+ function _unsupported_iterable_to_array(o, minLen) {
2539
+ if (!o) return;
2540
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
2541
+ var n = Object.prototype.toString.call(o).slice(8, -1);
2542
+ if (n === "Object" && o.constructor) n = o.constructor.name;
2543
+ if (n === "Map" || n === "Set") return Array.from(n);
2544
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
2545
+ }
2546
+ /**
2547
+ * Attribute selector that marks an element as a `dbxAction` context host.
2548
+ */ var DBX_ACTION_SELECTOR = 'dbxAction';
2549
+ /**
2550
+ * Element selector form of the action context host (`<dbx-action>`).
2551
+ */ var DBX_ACTION_ELEMENT_SELECTOR = 'dbx-action';
2552
+ /**
2553
+ * Selector for the action handler input (`[dbxActionHandler]`).
2554
+ */ var DBX_ACTION_HANDLER_SELECTOR = 'dbxActionHandler';
2555
+ /**
2556
+ * Selector for the directive that forwards an externally-provided action store
2557
+ * (`[dbxActionSource]`). When present, the value/store may be supplied entirely
2558
+ * in TypeScript, so a static template scan cannot reason about completeness.
2559
+ */ var DBX_ACTION_SOURCE_SELECTOR = 'dbxActionSource';
2560
+ /**
2561
+ * Selectors that cause the action to enter the TRIGGERED state.
2562
+ */ var DBX_ACTION_TRIGGER_SELECTORS = [
2563
+ 'dbxActionButton',
2564
+ 'dbxActionButtonTrigger',
2565
+ 'dbxActionKeyTrigger',
2566
+ 'dbxActionAutoTrigger'
2567
+ ];
2568
+ /**
2569
+ * Selectors that provide a value to the action (advancing TRIGGERED → VALUE_READY).
2570
+ *
2571
+ * Includes the bare `dbxActionValue` (which readies the empty-string sentinel on
2572
+ * trigger) and every directive that calls `readyValue()`/`reject()` off `triggered$`.
2573
+ */ var DBX_ACTION_VALUE_SOURCE_SELECTORS = [
2574
+ 'dbxActionValue',
2575
+ 'dbxActionValueGetter',
2576
+ 'dbxActionValueStream',
2577
+ 'dbxActionForm',
2578
+ 'dbxActionConfirm',
2579
+ 'dbxActionDialog',
2580
+ 'dbxActionPopover',
2581
+ 'dbxPdfMergeUploadAction'
2582
+ ];
2583
+ /**
2584
+ * Selectors that present/handle an action's error.
2585
+ */ var DBX_ACTION_ERROR_DIRECTIVE_SELECTORS = [
2586
+ 'dbxActionSnackbarError',
2587
+ 'dbxActionError',
2588
+ 'dbxActionSnackbar',
2589
+ 'dbxActionErrorHandler'
2590
+ ];
2591
+ /**
2592
+ * Array-valued child-bearing properties of Angular template AST nodes that a
2593
+ * context scan must descend into (element/template children plus the branches and
2594
+ * cases of `@if`/`@switch` control-flow blocks).
2595
+ */ var DBX_ACTION_CHILD_LIST_KEYS = [
2596
+ 'children',
2597
+ 'branches',
2598
+ 'cases'
2599
+ ];
2600
+ /**
2601
+ * Single-node child-bearing properties of control-flow blocks (`@for` empty,
2602
+ * `@defer` placeholder/loading/error).
2603
+ */ var DBX_ACTION_CHILD_NODE_KEYS = [
2604
+ 'empty',
2605
+ 'placeholder',
2606
+ 'loading',
2607
+ 'error'
2608
+ ];
2609
+ /**
2610
+ * Returns the attribute/input selector names present on a template element node.
2611
+ *
2612
+ * Reads plain attributes (`node.attributes`, e.g. `dbxActionButton`), bound inputs
2613
+ * (`node.inputs`, e.g. `[dbxActionValue]` whose `.name` has no brackets), and the
2614
+ * structural template attributes (`node.templateAttrs`).
2615
+ *
2616
+ * @param node - The template AST node.
2617
+ * @returns The selector names found on the node.
2618
+ */ function elementTokenNames(node) {
2619
+ var _ref, _ref1, _ref2;
2620
+ var attributes = (_ref = node === null || node === void 0 ? void 0 : node.attributes) !== null && _ref !== void 0 ? _ref : [];
2621
+ var inputs = (_ref1 = node === null || node === void 0 ? void 0 : node.inputs) !== null && _ref1 !== void 0 ? _ref1 : [];
2622
+ var templateAttrs = (_ref2 = node === null || node === void 0 ? void 0 : node.templateAttrs) !== null && _ref2 !== void 0 ? _ref2 : [];
2623
+ return _to_consumable_array(attributes).concat(_to_consumable_array(inputs), _to_consumable_array(templateAttrs)).map(function(attr) {
2624
+ return attr === null || attr === void 0 ? void 0 : attr.name;
2625
+ }).filter(function(name) {
2626
+ return typeof name === 'string';
2627
+ });
2628
+ }
2629
+ /**
2630
+ * Returns true when the node is a `dbxAction` context host — either the
2631
+ * `<dbx-action>` element or any element carrying the `dbxAction` attribute.
2632
+ *
2633
+ * @param node - The template AST node.
2634
+ * @returns True when the node hosts an action context.
2635
+ */ function isActionHost(node) {
2636
+ return (node === null || node === void 0 ? void 0 : node.name) === DBX_ACTION_ELEMENT_SELECTOR || elementTokenNames(node).includes(DBX_ACTION_SELECTOR);
2637
+ }
2638
+ /**
2639
+ * Returns true when the given selector is present on the node itself or on any of
2640
+ * its ancestors (walked via the auto-populated `.parent` chain).
2641
+ *
2642
+ * @param node - The starting template AST node.
2643
+ * @param selector - The selector name to look for.
2644
+ * @returns True when the selector is found on the node or an ancestor.
2645
+ */ function hasTokenOnSelfOrAncestor(node, selector) {
2646
+ var current = node;
2647
+ var found = false;
2648
+ while(current && !found){
2649
+ if (elementTokenNames(current).includes(selector)) {
2650
+ found = true;
2651
+ } else {
2652
+ current = current.parent;
2653
+ }
2654
+ }
2655
+ return found;
2656
+ }
2657
+ /**
2658
+ * Scans the subtree rooted at a `dbxAction` element, collecting the directive
2659
+ * selectors present on the element and its descendants.
2660
+ *
2661
+ * Descent steps through structural wrappers (`Template`) and control-flow blocks
2662
+ * (`@if`/`@for`/`@switch`/`@defer`). A nested action host re-scopes the context, so
2663
+ * the scan flags `nestedAction` and does not descend into it (its value source
2664
+ * belongs to the inner context, not this one).
2665
+ *
2666
+ * @param root - The `dbxAction` element node to scan from.
2667
+ * @returns The collected selector tokens and whether a nested action was found.
2668
+ */ function collectActionContext(root) {
2669
+ var tokens = new Set();
2670
+ var state = {
2671
+ nestedAction: false
2672
+ };
2673
+ var walk = function walk1(node, isRoot) {
2674
+ if (!node || (typeof node === "undefined" ? "undefined" : _type_of(node)) !== 'object') {
2675
+ return;
2676
+ }
2677
+ if (!isRoot && isActionHost(node)) {
2678
+ state.nestedAction = true;
2679
+ return; // do not descend into a nested action context
2680
+ }
2681
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2682
+ try {
2683
+ for(var _iterator = elementTokenNames(node)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2684
+ var name = _step.value;
2685
+ tokens.add(name);
2686
+ }
2687
+ } catch (err) {
2688
+ _didIteratorError = true;
2689
+ _iteratorError = err;
2690
+ } finally{
2691
+ try {
2692
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2693
+ _iterator.return();
2694
+ }
2695
+ } finally{
2696
+ if (_didIteratorError) {
2697
+ throw _iteratorError;
2698
+ }
2699
+ }
2700
+ }
2701
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
2702
+ try {
2703
+ for(var _iterator1 = DBX_ACTION_CHILD_LIST_KEYS[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
2704
+ var key = _step1.value;
2705
+ var children = node[key];
2706
+ if (Array.isArray(children)) {
2707
+ var _iteratorNormalCompletion2 = true, _didIteratorError2 = false, _iteratorError2 = undefined;
2708
+ try {
2709
+ for(var _iterator2 = children[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true){
2710
+ var child = _step2.value;
2711
+ walk(child, false);
2712
+ }
2713
+ } catch (err) {
2714
+ _didIteratorError2 = true;
2715
+ _iteratorError2 = err;
2716
+ } finally{
2717
+ try {
2718
+ if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
2719
+ _iterator2.return();
2720
+ }
2721
+ } finally{
2722
+ if (_didIteratorError2) {
2723
+ throw _iteratorError2;
2724
+ }
2725
+ }
2726
+ }
2727
+ }
2728
+ }
2729
+ } catch (err) {
2730
+ _didIteratorError1 = true;
2731
+ _iteratorError1 = err;
2732
+ } finally{
2733
+ try {
2734
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
2735
+ _iterator1.return();
2736
+ }
2737
+ } finally{
2738
+ if (_didIteratorError1) {
2739
+ throw _iteratorError1;
2740
+ }
2741
+ }
2742
+ }
2743
+ var _iteratorNormalCompletion3 = true, _didIteratorError3 = false, _iteratorError3 = undefined;
2744
+ try {
2745
+ for(var _iterator3 = DBX_ACTION_CHILD_NODE_KEYS[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true){
2746
+ var key1 = _step3.value;
2747
+ var child1 = node[key1];
2748
+ if (child1 && (typeof child1 === "undefined" ? "undefined" : _type_of(child1)) === 'object') {
2749
+ walk(child1, false);
2750
+ }
2751
+ }
2752
+ } catch (err) {
2753
+ _didIteratorError3 = true;
2754
+ _iteratorError3 = err;
2755
+ } finally{
2756
+ try {
2757
+ if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
2758
+ _iterator3.return();
2759
+ }
2760
+ } finally{
2761
+ if (_didIteratorError3) {
2762
+ throw _iteratorError3;
2763
+ }
2764
+ }
2765
+ }
2766
+ };
2767
+ walk(root, true);
2768
+ return {
2769
+ tokens: tokens,
2770
+ nestedAction: state.nestedAction
2771
+ };
2772
+ }
2773
+ /**
2774
+ * Resolves the template parser services from the rule context, supporting both the
2775
+ * flat-config `context.sourceCode` accessor and the legacy `context.parserServices`.
2776
+ *
2777
+ * @param context - The ESLint rule context.
2778
+ * @returns The parser services object, or null when unavailable.
2779
+ */ function getTemplateParserServices(context) {
2780
+ var _context_sourceCode, _ref, _ref1;
2781
+ var sourceCode = (_context_sourceCode = context.sourceCode) !== null && _context_sourceCode !== void 0 ? _context_sourceCode : typeof context.getSourceCode === 'function' ? context.getSourceCode() : undefined;
2782
+ return (_ref = (_ref1 = sourceCode === null || sourceCode === void 0 ? void 0 : sourceCode.parserServices) !== null && _ref1 !== void 0 ? _ref1 : context.parserServices) !== null && _ref !== void 0 ? _ref : null;
2783
+ }
2784
+ /**
2785
+ * Computes the report location for an action element from its source span.
2786
+ *
2787
+ * @param parserServices - The template parser services (must expose `convertNodeSourceSpanToLoc`).
2788
+ * @param node - The element AST node being reported.
2789
+ * @returns An ESLint `SourceLocation` for the element's opening tag.
2790
+ */ function actionElementLoc(parserServices, node) {
2791
+ var _node_startSourceSpan;
2792
+ return parserServices.convertNodeSourceSpanToLoc((_node_startSourceSpan = node.startSourceSpan) !== null && _node_startSourceSpan !== void 0 ? _node_startSourceSpan : node.sourceSpan);
2793
+ }
2794
+
2795
+ /**
2796
+ * ESLint (Angular template) rule that flags a `dbxAction` whose context has a
2797
+ * trigger but no value source.
2798
+ *
2799
+ * Such an action hangs: clicking the trigger moves the store to TRIGGERED, but with
2800
+ * nothing to call `readyValue()` it never advances to VALUE_READY, so the handler
2801
+ * never runs.
2802
+ *
2803
+ * Targets simple, inline cases only. It bails (does not report) when the value may
2804
+ * be supplied in a way a static template scan cannot see:
2805
+ * - `[dbxActionSource]` on the element or an ancestor (store forwarded from TS), or
2806
+ * - a nested `dbxAction` inside the subtree (ambiguous which context owns a value source).
2807
+ *
2808
+ * For legitimate programmatic-value cases (or a demo intentionally showing the
2809
+ * TRIGGERED state) suppress with `<!-- eslint-disable-next-line dereekb-dbx-web/require-action-value-source -->`.
2810
+ */ var DBX_WEB_REQUIRE_ACTION_VALUE_SOURCE_RULE = {
2811
+ meta: {
2812
+ type: 'problem',
2813
+ fixable: undefined,
2814
+ docs: {
2815
+ description: 'Require a value source on a triggered dbxAction so it cannot hang in the TRIGGERED state.',
2816
+ recommended: true
2817
+ },
2818
+ messages: {
2819
+ missingValueSource: '`dbxAction` has a trigger (`{{trigger}}`) but no value source, so triggering it hangs — the action never reaches VALUE_READY and the handler never runs. Add a value source (`dbxActionValue`, `[dbxActionValue]`, `[dbxActionValueGetter]`, `[dbxActionValueStream]`, or `[dbxActionForm]`), trigger with `triggerWithValue()`, or disable this line if the value is supplied in TypeScript.'
2820
+ },
2821
+ schema: []
2822
+ },
2823
+ create: function create(context) {
2824
+ var parserServices = getTemplateParserServices(context);
2825
+ return {
2826
+ Element: function Element(node) {
2827
+ if (!(parserServices === null || parserServices === void 0 ? void 0 : parserServices.convertNodeSourceSpanToLoc)) {
2828
+ return; // not an Angular template (no template parser services)
2829
+ }
2830
+ if (!isActionHost(node)) {
2831
+ return;
2832
+ }
2833
+ if (hasTokenOnSelfOrAncestor(node, DBX_ACTION_SOURCE_SELECTOR)) {
2834
+ return; // store/value may be forwarded from an external (TS) source
2835
+ }
2836
+ var _collectActionContext = collectActionContext(node), tokens = _collectActionContext.tokens, nestedAction = _collectActionContext.nestedAction;
2837
+ if (nestedAction) {
2838
+ return; // multiple action contexts — ambiguous which owns a value source
2839
+ }
2840
+ var trigger = DBX_ACTION_TRIGGER_SELECTORS.find(function(selector) {
2841
+ return tokens.has(selector);
2842
+ });
2843
+ if (!trigger) {
2844
+ return; // not trigger-driven (form/auto/programmatic) — out of scope
2845
+ }
2846
+ var hasValueSource = DBX_ACTION_VALUE_SOURCE_SELECTORS.some(function(selector) {
2847
+ return tokens.has(selector);
2848
+ });
2849
+ if (!hasValueSource) {
2850
+ context.report({
2851
+ loc: actionElementLoc(parserServices, node),
2852
+ messageId: 'missingValueSource',
2853
+ data: {
2854
+ trigger: trigger
2855
+ }
2856
+ });
2857
+ }
2858
+ }
2859
+ };
2860
+ }
2861
+ };
2862
+
2863
+ /**
2864
+ * ESLint (Angular template) rule that flags a `dbxAction` which runs work (has a
2865
+ * handler or a trigger) but presents no errors to the user.
2866
+ *
2867
+ * Satisfied by ANY error directive in the context: `dbxActionSnackbarError`,
2868
+ * `[dbxActionError]`, `[dbxActionSnackbar]`, or `[dbxActionErrorHandler]`.
2869
+ *
2870
+ * Shares the same context-scoping bail conditions as `require-action-value-source`
2871
+ * (`[dbxActionSource]` on self/ancestor, or a nested `dbxAction`).
2872
+ */ var DBX_WEB_REQUIRE_ACTION_ERROR_HANDLER_RULE = {
2873
+ meta: {
2874
+ type: 'suggestion',
2875
+ fixable: undefined,
2876
+ docs: {
2877
+ description: 'Require an error-presentation directive on a dbxAction that runs a handler so failures surface to the user.',
2878
+ recommended: false
2879
+ },
2880
+ messages: {
2881
+ missingErrorHandler: '`dbxAction` runs a handler but surfaces no errors to the user. Add `dbxActionSnackbarError` (or `[dbxActionError]`, `[dbxActionSnackbar]`, or `[dbxActionErrorHandler]`) so action failures are presented.'
2882
+ },
2883
+ schema: []
2884
+ },
2885
+ create: function create(context) {
2886
+ var parserServices = getTemplateParserServices(context);
2887
+ return {
2888
+ Element: function Element(node) {
2889
+ if (!(parserServices === null || parserServices === void 0 ? void 0 : parserServices.convertNodeSourceSpanToLoc)) {
2890
+ return; // not an Angular template (no template parser services)
2891
+ }
2892
+ if (!isActionHost(node)) {
2893
+ return;
2894
+ }
2895
+ if (hasTokenOnSelfOrAncestor(node, DBX_ACTION_SOURCE_SELECTOR)) {
2896
+ return; // forwarded external context — error handling may live elsewhere
2897
+ }
2898
+ var _collectActionContext = collectActionContext(node), tokens = _collectActionContext.tokens, nestedAction = _collectActionContext.nestedAction;
2899
+ if (nestedAction) {
2900
+ return; // multiple action contexts — ambiguous
2901
+ }
2902
+ var hasHandlerOrTrigger = tokens.has(DBX_ACTION_HANDLER_SELECTOR) || DBX_ACTION_TRIGGER_SELECTORS.some(function(selector) {
2903
+ return tokens.has(selector);
2904
+ });
2905
+ if (!hasHandlerOrTrigger) {
2906
+ return; // nothing actionable here — skip
2907
+ }
2908
+ var hasErrorDirective = DBX_ACTION_ERROR_DIRECTIVE_SELECTORS.some(function(selector) {
2909
+ return tokens.has(selector);
2910
+ });
2911
+ if (!hasErrorDirective) {
2912
+ context.report({
2913
+ loc: actionElementLoc(parserServices, node),
2914
+ messageId: 'missingErrorHandler'
2915
+ });
2916
+ }
2917
+ }
2918
+ };
2919
+ }
2920
+ };
2921
+
2517
2922
  /**
2518
2923
  * ESLint plugin for dbx-web rules.
2519
2924
  *
@@ -2526,7 +2931,9 @@ function _unsupported_iterable_to_array(o, minLen) {
2526
2931
  'no-redundant-on-destroy': DBX_WEB_NO_REDUNDANT_ON_DESTROY_RULE,
2527
2932
  'require-computed-signal-suffix': DBX_WEB_REQUIRE_COMPUTED_SIGNAL_SUFFIX_RULE,
2528
2933
  'require-component-config-input': DBX_WEB_REQUIRE_COMPONENT_CONFIG_INPUT_RULE,
2529
- 'require-top-level-computed-signals': DBX_WEB_REQUIRE_TOP_LEVEL_COMPUTED_SIGNALS_RULE
2934
+ 'require-top-level-computed-signals': DBX_WEB_REQUIRE_TOP_LEVEL_COMPUTED_SIGNALS_RULE,
2935
+ 'require-action-value-source': DBX_WEB_REQUIRE_ACTION_VALUE_SOURCE_RULE,
2936
+ 'require-action-error-handler': DBX_WEB_REQUIRE_ACTION_ERROR_HANDLER_RULE
2530
2937
  }
2531
2938
  };
2532
2939
  /**
@@ -2535,4 +2942,4 @@ function _unsupported_iterable_to_array(o, minLen) {
2535
2942
  * @dbxAllowConstantName
2536
2943
  */ var dbxWebESLintPlugin = DBX_WEB_ESLINT_PLUGIN;
2537
2944
 
2538
- export { DBX_WEB_ESLINT_PLUGIN, DBX_WEB_NO_REDUNDANT_ON_DESTROY_RULE, DBX_WEB_REQUIRE_CLEAN_SUBSCRIPTION_RULE, DBX_WEB_REQUIRE_COMPLETE_ON_DESTROY_RULE, DBX_WEB_REQUIRE_COMPONENT_CONFIG_INPUT_RULE, DBX_WEB_REQUIRE_COMPUTED_SIGNAL_SUFFIX_RULE, DBX_WEB_REQUIRE_TOP_LEVEL_COMPUTED_SIGNALS_RULE, dbxWebESLintPlugin };
2945
+ export { DBX_WEB_ESLINT_PLUGIN, DBX_WEB_NO_REDUNDANT_ON_DESTROY_RULE, DBX_WEB_REQUIRE_ACTION_ERROR_HANDLER_RULE, DBX_WEB_REQUIRE_ACTION_VALUE_SOURCE_RULE, DBX_WEB_REQUIRE_CLEAN_SUBSCRIPTION_RULE, DBX_WEB_REQUIRE_COMPLETE_ON_DESTROY_RULE, DBX_WEB_REQUIRE_COMPONENT_CONFIG_INPUT_RULE, DBX_WEB_REQUIRE_COMPUTED_SIGNAL_SUFFIX_RULE, DBX_WEB_REQUIRE_TOP_LEVEL_COMPUTED_SIGNALS_RULE, dbxWebESLintPlugin };
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-web/eslint",
3
- "version": "13.21.0",
3
+ "version": "13.23.0",
4
4
  "peerDependencies": {
5
- "@dereekb/util": "13.21.0",
5
+ "@dereekb/util": "13.23.0",
6
6
  "@typescript-eslint/utils": "8.59.3"
7
7
  },
8
8
  "devDependencies": {
9
+ "@angular-eslint/template-parser": "21.4.0",
9
10
  "@angular/core": "21.2.11",
10
- "@dereekb/dbx-core": "13.21.0",
11
- "@dereekb/rxjs": "13.21.0",
11
+ "@dereekb/dbx-core": "13.23.0",
12
+ "@dereekb/rxjs": "13.23.0",
12
13
  "@typescript-eslint/parser": "8.59.3",
13
14
  "eslint": "10.4.0",
14
15
  "rxjs": "^7.8.2"
@@ -0,0 +1,106 @@
1
+ import { type AstNode } from './util';
2
+ /**
3
+ * Attribute selector that marks an element as a `dbxAction` context host.
4
+ */
5
+ export declare const DBX_ACTION_SELECTOR = "dbxAction";
6
+ /**
7
+ * Element selector form of the action context host (`<dbx-action>`).
8
+ */
9
+ export declare const DBX_ACTION_ELEMENT_SELECTOR = "dbx-action";
10
+ /**
11
+ * Selector for the action handler input (`[dbxActionHandler]`).
12
+ */
13
+ export declare const DBX_ACTION_HANDLER_SELECTOR = "dbxActionHandler";
14
+ /**
15
+ * Selector for the directive that forwards an externally-provided action store
16
+ * (`[dbxActionSource]`). When present, the value/store may be supplied entirely
17
+ * in TypeScript, so a static template scan cannot reason about completeness.
18
+ */
19
+ export declare const DBX_ACTION_SOURCE_SELECTOR = "dbxActionSource";
20
+ /**
21
+ * Selectors that cause the action to enter the TRIGGERED state.
22
+ */
23
+ export declare const DBX_ACTION_TRIGGER_SELECTORS: readonly string[];
24
+ /**
25
+ * Selectors that provide a value to the action (advancing TRIGGERED → VALUE_READY).
26
+ *
27
+ * Includes the bare `dbxActionValue` (which readies the empty-string sentinel on
28
+ * trigger) and every directive that calls `readyValue()`/`reject()` off `triggered$`.
29
+ */
30
+ export declare const DBX_ACTION_VALUE_SOURCE_SELECTORS: readonly string[];
31
+ /**
32
+ * Selectors that present/handle an action's error.
33
+ */
34
+ export declare const DBX_ACTION_ERROR_DIRECTIVE_SELECTORS: readonly string[];
35
+ /**
36
+ * Result of scanning a `dbxAction` element's context subtree.
37
+ */
38
+ export interface DbxActionContextScan {
39
+ /**
40
+ * The set of directive/attribute selector names found on the action element and
41
+ * its descendants (excluding any nested action context).
42
+ */
43
+ readonly tokens: ReadonlySet<string>;
44
+ /**
45
+ * True when a nested `dbxAction`/`dbx-action` host was found inside the subtree,
46
+ * meaning the context is ambiguous and rules should not report.
47
+ */
48
+ readonly nestedAction: boolean;
49
+ }
50
+ /**
51
+ * Returns the attribute/input selector names present on a template element node.
52
+ *
53
+ * Reads plain attributes (`node.attributes`, e.g. `dbxActionButton`), bound inputs
54
+ * (`node.inputs`, e.g. `[dbxActionValue]` whose `.name` has no brackets), and the
55
+ * structural template attributes (`node.templateAttrs`).
56
+ *
57
+ * @param node - The template AST node.
58
+ * @returns The selector names found on the node.
59
+ */
60
+ export declare function elementTokenNames(node: AstNode): string[];
61
+ /**
62
+ * Returns true when the node is a `dbxAction` context host — either the
63
+ * `<dbx-action>` element or any element carrying the `dbxAction` attribute.
64
+ *
65
+ * @param node - The template AST node.
66
+ * @returns True when the node hosts an action context.
67
+ */
68
+ export declare function isActionHost(node: AstNode): boolean;
69
+ /**
70
+ * Returns true when the given selector is present on the node itself or on any of
71
+ * its ancestors (walked via the auto-populated `.parent` chain).
72
+ *
73
+ * @param node - The starting template AST node.
74
+ * @param selector - The selector name to look for.
75
+ * @returns True when the selector is found on the node or an ancestor.
76
+ */
77
+ export declare function hasTokenOnSelfOrAncestor(node: AstNode, selector: string): boolean;
78
+ /**
79
+ * Scans the subtree rooted at a `dbxAction` element, collecting the directive
80
+ * selectors present on the element and its descendants.
81
+ *
82
+ * Descent steps through structural wrappers (`Template`) and control-flow blocks
83
+ * (`@if`/`@for`/`@switch`/`@defer`). A nested action host re-scopes the context, so
84
+ * the scan flags `nestedAction` and does not descend into it (its value source
85
+ * belongs to the inner context, not this one).
86
+ *
87
+ * @param root - The `dbxAction` element node to scan from.
88
+ * @returns The collected selector tokens and whether a nested action was found.
89
+ */
90
+ export declare function collectActionContext(root: AstNode): DbxActionContextScan;
91
+ /**
92
+ * Resolves the template parser services from the rule context, supporting both the
93
+ * flat-config `context.sourceCode` accessor and the legacy `context.parserServices`.
94
+ *
95
+ * @param context - The ESLint rule context.
96
+ * @returns The parser services object, or null when unavailable.
97
+ */
98
+ export declare function getTemplateParserServices(context: AstNode): AstNode;
99
+ /**
100
+ * Computes the report location for an action element from its source span.
101
+ *
102
+ * @param parserServices - The template parser services (must expose `convertNodeSourceSpanToLoc`).
103
+ * @param node - The element AST node being reported.
104
+ * @returns An ESLint `SourceLocation` for the element's opening tag.
105
+ */
106
+ export declare function actionElementLoc(parserServices: AstNode, node: AstNode): AstNode;
@@ -4,4 +4,6 @@ export { DBX_WEB_NO_REDUNDANT_ON_DESTROY_RULE } from './no-redundant-on-destroy.
4
4
  export { DBX_WEB_REQUIRE_COMPUTED_SIGNAL_SUFFIX_RULE } from './require-computed-signal-suffix.rule';
5
5
  export { DBX_WEB_REQUIRE_COMPONENT_CONFIG_INPUT_RULE } from './require-component-config-input.rule';
6
6
  export { DBX_WEB_REQUIRE_TOP_LEVEL_COMPUTED_SIGNALS_RULE } from './require-top-level-computed-signals.rule';
7
+ export { DBX_WEB_REQUIRE_ACTION_VALUE_SOURCE_RULE } from './require-action-value-source.rule';
8
+ export { DBX_WEB_REQUIRE_ACTION_ERROR_HANDLER_RULE } from './require-action-error-handler.rule';
7
9
  export { DBX_WEB_ESLINT_PLUGIN, dbxWebESLintPlugin, type DbxWebEslintPlugin } from './plugin';
@@ -4,6 +4,8 @@ import { DBX_WEB_NO_REDUNDANT_ON_DESTROY_RULE } from './no-redundant-on-destroy.
4
4
  import { DBX_WEB_REQUIRE_COMPUTED_SIGNAL_SUFFIX_RULE } from './require-computed-signal-suffix.rule';
5
5
  import { DBX_WEB_REQUIRE_COMPONENT_CONFIG_INPUT_RULE } from './require-component-config-input.rule';
6
6
  import { DBX_WEB_REQUIRE_TOP_LEVEL_COMPUTED_SIGNALS_RULE } from './require-top-level-computed-signals.rule';
7
+ import { DBX_WEB_REQUIRE_ACTION_VALUE_SOURCE_RULE } from './require-action-value-source.rule';
8
+ import { DBX_WEB_REQUIRE_ACTION_ERROR_HANDLER_RULE } from './require-action-error-handler.rule';
7
9
  /**
8
10
  * ESLint plugin interface for dbx-web rules.
9
11
  */
@@ -15,6 +17,8 @@ export interface DbxWebEslintPlugin {
15
17
  readonly 'require-computed-signal-suffix': typeof DBX_WEB_REQUIRE_COMPUTED_SIGNAL_SUFFIX_RULE;
16
18
  readonly 'require-component-config-input': typeof DBX_WEB_REQUIRE_COMPONENT_CONFIG_INPUT_RULE;
17
19
  readonly 'require-top-level-computed-signals': typeof DBX_WEB_REQUIRE_TOP_LEVEL_COMPUTED_SIGNALS_RULE;
20
+ readonly 'require-action-value-source': typeof DBX_WEB_REQUIRE_ACTION_VALUE_SOURCE_RULE;
21
+ readonly 'require-action-error-handler': typeof DBX_WEB_REQUIRE_ACTION_ERROR_HANDLER_RULE;
18
22
  };
19
23
  }
20
24
  /**