tutuca 0.9.19 → 0.9.21

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.
@@ -667,191 +667,17 @@ __export(exports_md, {
667
667
  supports: () => supports2,
668
668
  format: () => format2
669
669
  });
670
-
671
- // src/util/docs.js
672
- function getSignature(name, fn) {
673
- const s = fn.toString();
674
- const m = s.match(/^(?:\w+|function\s*\w*)\s*\(([^)]*)\)/);
675
- const params = m ? m[1].trim() : "";
676
- return `${name}(${params})`;
677
- }
678
- function getFieldMethods(field) {
679
- const { name, type } = field;
680
- const uname = name[0].toUpperCase() + name.slice(1);
681
- const methods = [
682
- { name: `set${uname}`, sig: `set${uname}(v)`, desc: "Set value" },
683
- {
684
- name: `update${uname}`,
685
- sig: `update${uname}(fn)`,
686
- desc: "Update value with function"
687
- },
688
- {
689
- name: `reset${uname}`,
690
- sig: `reset${uname}()`,
691
- desc: "Reset to default value"
692
- },
693
- {
694
- name: `is${uname}NotSet`,
695
- sig: `is${uname}NotSet()`,
696
- desc: "Check if null/undefined"
697
- },
698
- {
699
- name: `is${uname}Set`,
700
- sig: `is${uname}Set()`,
701
- desc: "Check if not null/undefined"
702
- }
703
- ];
704
- switch (type) {
705
- case "bool":
706
- methods[0].desc = "Set value (coerces to boolean)";
707
- methods.push({
708
- name: `toggle${uname}`,
709
- sig: `toggle${uname}()`,
710
- desc: "Toggle boolean value"
711
- });
712
- break;
713
- case "text":
714
- methods.push({
715
- name: `is${uname}Empty`,
716
- sig: `is${uname}Empty()`,
717
- desc: "Check if string is empty"
718
- }, { name: `${name}Len`, sig: `${name}Len()`, desc: "Get string length" });
719
- break;
720
- case "list":
721
- methods.push({
722
- name: `is${uname}Empty`,
723
- sig: `is${uname}Empty()`,
724
- desc: "Check if list is empty"
725
- }, { name: `${name}Len`, sig: `${name}Len()`, desc: "Get list size" }, {
726
- name: `setIn${uname}At`,
727
- sig: `setIn${uname}At(i, v)`,
728
- desc: "Set item at index"
729
- }, {
730
- name: `getIn${uname}At`,
731
- sig: `getIn${uname}At(i, defaultValue)`,
732
- desc: "Get item at index"
733
- }, {
734
- name: `updateIn${uname}At`,
735
- sig: `updateIn${uname}At(i, fn)`,
736
- desc: "Update item at index with function"
737
- }, {
738
- name: `deleteIn${uname}At`,
739
- sig: `deleteIn${uname}At(i)`,
740
- desc: "Delete item at index"
741
- }, {
742
- name: `removeIn${uname}At`,
743
- sig: `removeIn${uname}At(i)`,
744
- desc: "Delete item at index (alias)"
745
- }, {
746
- name: `pushIn${uname}`,
747
- sig: `pushIn${uname}(v)`,
748
- desc: "Push item to end"
749
- }, {
750
- name: `insertIn${uname}At`,
751
- sig: `insertIn${uname}At(i, v)`,
752
- desc: "Insert item at index"
753
- });
754
- break;
755
- case "map":
756
- case "omap": {
757
- const label = type === "omap" ? "ordered map" : "map";
758
- methods.push({
759
- name: `is${uname}Empty`,
760
- sig: `is${uname}Empty()`,
761
- desc: `Check if ${label} is empty`
762
- }, {
763
- name: `${name}Len`,
764
- sig: `${name}Len()`,
765
- desc: `Get ${label} size`
766
- }, {
767
- name: `setIn${uname}At`,
768
- sig: `setIn${uname}At(key, v)`,
769
- desc: "Set value at key"
770
- }, {
771
- name: `getIn${uname}At`,
772
- sig: `getIn${uname}At(key, defaultValue)`,
773
- desc: "Get value at key"
774
- }, {
775
- name: `updateIn${uname}At`,
776
- sig: `updateIn${uname}At(key, fn)`,
777
- desc: "Update value at key with function"
778
- }, {
779
- name: `deleteIn${uname}At`,
780
- sig: `deleteIn${uname}At(key)`,
781
- desc: "Delete entry at key"
782
- }, {
783
- name: `removeIn${uname}At`,
784
- sig: `removeIn${uname}At(key)`,
785
- desc: "Delete entry at key (alias)"
786
- });
787
- break;
788
- }
789
- case "set":
790
- methods.push({
791
- name: `is${uname}Empty`,
792
- sig: `is${uname}Empty()`,
793
- desc: "Check if set is empty"
794
- }, { name: `${name}Len`, sig: `${name}Len()`, desc: "Get set size" }, {
795
- name: `addIn${uname}`,
796
- sig: `addIn${uname}(v)`,
797
- desc: "Add value to set"
798
- }, {
799
- name: `deleteIn${uname}`,
800
- sig: `deleteIn${uname}(v)`,
801
- desc: "Remove value from set"
802
- }, {
803
- name: `removeIn${uname}`,
804
- sig: `removeIn${uname}(v)`,
805
- desc: "Remove value from set (alias)"
806
- }, {
807
- name: `hasIn${uname}`,
808
- sig: `hasIn${uname}(v)`,
809
- desc: "Check if value is in set"
810
- }, {
811
- name: `toggleIn${uname}`,
812
- sig: `toggleIn${uname}(v)`,
813
- desc: "Toggle value in set"
814
- });
815
- break;
816
- }
817
- return methods;
818
- }
819
- function serializeDefault(v) {
820
- if (v === null || v === undefined)
821
- return v;
822
- if (v?.toJS)
823
- return v.toJS();
824
- return v;
825
- }
826
- function getComponentDoc(comp) {
827
- const meta = comp.Class.getMetaClass();
828
- const { fields, name, methods } = meta;
829
- const userMethods = Object.keys(methods).map((k) => ({
830
- name: k,
831
- sig: getSignature(k, methods[k])
832
- }));
833
- const inputHandlers = Object.keys(comp.input).map((k) => ({
834
- name: k,
835
- sig: getSignature(k, comp.input[k])
836
- }));
837
- const fieldDocs = [];
838
- for (const fieldName in fields) {
839
- const field = fields[fieldName];
840
- fieldDocs.push({
841
- name: fieldName,
842
- type: field.type,
843
- default: serializeDefault(field.defaultValue),
844
- methods: getFieldMethods(field)
845
- });
846
- }
847
- return { name, methods: userMethods, input: inputHandlers, fields: fieldDocs };
848
- }
849
- function getComponentsDocs(components) {
850
- return components.map((comp) => getComponentDoc(comp));
851
- }
852
- function docsToMarkdown(docs) {
670
+ var supports2 = new Set([
671
+ "ComponentDocs",
672
+ "RenderBatch",
673
+ "ExampleIndex",
674
+ "LintReport",
675
+ "ModuleInfo",
676
+ "ComponentList"
677
+ ]);
678
+ function fmtComponentDocs2(docs) {
853
679
  const lines = [];
854
- for (const comp of docs) {
680
+ for (const comp of docs.items) {
855
681
  lines.push(`# ${comp.name}
856
682
  `);
857
683
  if (comp.methods.length > 0) {
@@ -882,19 +708,6 @@ function docsToMarkdown(docs) {
882
708
  return lines.join(`
883
709
  `);
884
710
  }
885
-
886
- // tools/format/md.js
887
- var supports2 = new Set([
888
- "ComponentDocs",
889
- "RenderBatch",
890
- "ExampleIndex",
891
- "LintReport",
892
- "ModuleInfo",
893
- "ComponentList"
894
- ]);
895
- function fmtComponentDocs2(docs) {
896
- return docsToMarkdown(docs.items);
897
- }
898
711
  async function fmtRenderBatch2(batch, { pretty = false } = {}) {
899
712
  const prettify = pretty ? (await import("prettier")).format : null;
900
713
  const lines = [];
@@ -1212,6 +1025,186 @@ __export(exports_docs, {
1212
1025
  });
1213
1026
 
1214
1027
  // tools/core/docs.js
1028
+ function getSignature(name, fn) {
1029
+ const s = fn.toString();
1030
+ const m = s.match(/^(?:\w+|function\s*\w*)\s*\(([^)]*)\)/);
1031
+ const params = m ? m[1].trim() : "";
1032
+ return `${name}(${params})`;
1033
+ }
1034
+ function getFieldMethods(field) {
1035
+ const { name, type } = field;
1036
+ const uname = name[0].toUpperCase() + name.slice(1);
1037
+ const methods = [
1038
+ { name: `set${uname}`, sig: `set${uname}(v)`, desc: "Set value" },
1039
+ {
1040
+ name: `update${uname}`,
1041
+ sig: `update${uname}(fn)`,
1042
+ desc: "Update value with function"
1043
+ },
1044
+ {
1045
+ name: `reset${uname}`,
1046
+ sig: `reset${uname}()`,
1047
+ desc: "Reset to default value"
1048
+ },
1049
+ {
1050
+ name: `is${uname}NotSet`,
1051
+ sig: `is${uname}NotSet()`,
1052
+ desc: "Check if null/undefined"
1053
+ },
1054
+ {
1055
+ name: `is${uname}Set`,
1056
+ sig: `is${uname}Set()`,
1057
+ desc: "Check if not null/undefined"
1058
+ }
1059
+ ];
1060
+ switch (type) {
1061
+ case "bool":
1062
+ methods[0].desc = "Set value (coerces to boolean)";
1063
+ methods.push({
1064
+ name: `toggle${uname}`,
1065
+ sig: `toggle${uname}()`,
1066
+ desc: "Toggle boolean value"
1067
+ });
1068
+ break;
1069
+ case "text":
1070
+ methods.push({
1071
+ name: `is${uname}Empty`,
1072
+ sig: `is${uname}Empty()`,
1073
+ desc: "Check if string is empty"
1074
+ }, { name: `${name}Len`, sig: `${name}Len()`, desc: "Get string length" });
1075
+ break;
1076
+ case "list":
1077
+ methods.push({
1078
+ name: `is${uname}Empty`,
1079
+ sig: `is${uname}Empty()`,
1080
+ desc: "Check if list is empty"
1081
+ }, { name: `${name}Len`, sig: `${name}Len()`, desc: "Get list size" }, {
1082
+ name: `setIn${uname}At`,
1083
+ sig: `setIn${uname}At(i, v)`,
1084
+ desc: "Set item at index"
1085
+ }, {
1086
+ name: `getIn${uname}At`,
1087
+ sig: `getIn${uname}At(i, defaultValue)`,
1088
+ desc: "Get item at index"
1089
+ }, {
1090
+ name: `updateIn${uname}At`,
1091
+ sig: `updateIn${uname}At(i, fn)`,
1092
+ desc: "Update item at index with function"
1093
+ }, {
1094
+ name: `deleteIn${uname}At`,
1095
+ sig: `deleteIn${uname}At(i)`,
1096
+ desc: "Delete item at index"
1097
+ }, {
1098
+ name: `removeIn${uname}At`,
1099
+ sig: `removeIn${uname}At(i)`,
1100
+ desc: "Delete item at index (alias)"
1101
+ }, {
1102
+ name: `pushIn${uname}`,
1103
+ sig: `pushIn${uname}(v)`,
1104
+ desc: "Push item to end"
1105
+ }, {
1106
+ name: `insertIn${uname}At`,
1107
+ sig: `insertIn${uname}At(i, v)`,
1108
+ desc: "Insert item at index"
1109
+ });
1110
+ break;
1111
+ case "map":
1112
+ case "omap": {
1113
+ const label = type === "omap" ? "ordered map" : "map";
1114
+ methods.push({
1115
+ name: `is${uname}Empty`,
1116
+ sig: `is${uname}Empty()`,
1117
+ desc: `Check if ${label} is empty`
1118
+ }, {
1119
+ name: `${name}Len`,
1120
+ sig: `${name}Len()`,
1121
+ desc: `Get ${label} size`
1122
+ }, {
1123
+ name: `setIn${uname}At`,
1124
+ sig: `setIn${uname}At(key, v)`,
1125
+ desc: "Set value at key"
1126
+ }, {
1127
+ name: `getIn${uname}At`,
1128
+ sig: `getIn${uname}At(key, defaultValue)`,
1129
+ desc: "Get value at key"
1130
+ }, {
1131
+ name: `updateIn${uname}At`,
1132
+ sig: `updateIn${uname}At(key, fn)`,
1133
+ desc: "Update value at key with function"
1134
+ }, {
1135
+ name: `deleteIn${uname}At`,
1136
+ sig: `deleteIn${uname}At(key)`,
1137
+ desc: "Delete entry at key"
1138
+ }, {
1139
+ name: `removeIn${uname}At`,
1140
+ sig: `removeIn${uname}At(key)`,
1141
+ desc: "Delete entry at key (alias)"
1142
+ });
1143
+ break;
1144
+ }
1145
+ case "set":
1146
+ methods.push({
1147
+ name: `is${uname}Empty`,
1148
+ sig: `is${uname}Empty()`,
1149
+ desc: "Check if set is empty"
1150
+ }, { name: `${name}Len`, sig: `${name}Len()`, desc: "Get set size" }, {
1151
+ name: `addIn${uname}`,
1152
+ sig: `addIn${uname}(v)`,
1153
+ desc: "Add value to set"
1154
+ }, {
1155
+ name: `deleteIn${uname}`,
1156
+ sig: `deleteIn${uname}(v)`,
1157
+ desc: "Remove value from set"
1158
+ }, {
1159
+ name: `removeIn${uname}`,
1160
+ sig: `removeIn${uname}(v)`,
1161
+ desc: "Remove value from set (alias)"
1162
+ }, {
1163
+ name: `hasIn${uname}`,
1164
+ sig: `hasIn${uname}(v)`,
1165
+ desc: "Check if value is in set"
1166
+ }, {
1167
+ name: `toggleIn${uname}`,
1168
+ sig: `toggleIn${uname}(v)`,
1169
+ desc: "Toggle value in set"
1170
+ });
1171
+ break;
1172
+ }
1173
+ return methods;
1174
+ }
1175
+ function serializeDefault(v) {
1176
+ if (v === null || v === undefined)
1177
+ return v;
1178
+ if (v?.toJS)
1179
+ return v.toJS();
1180
+ return v;
1181
+ }
1182
+ function getComponentDoc(comp) {
1183
+ const meta = comp.Class.getMetaClass();
1184
+ const { fields, name, methods } = meta;
1185
+ const userMethods = Object.keys(methods).map((k) => ({
1186
+ name: k,
1187
+ sig: getSignature(k, methods[k])
1188
+ }));
1189
+ const inputHandlers = Object.keys(comp.input).map((k) => ({
1190
+ name: k,
1191
+ sig: getSignature(k, comp.input[k])
1192
+ }));
1193
+ const fieldDocs = [];
1194
+ for (const fieldName in fields) {
1195
+ const field = fields[fieldName];
1196
+ fieldDocs.push({
1197
+ name: fieldName,
1198
+ type: field.type,
1199
+ default: serializeDefault(field.defaultValue),
1200
+ methods: getFieldMethods(field)
1201
+ });
1202
+ }
1203
+ return { name, methods: userMethods, input: inputHandlers, fields: fieldDocs };
1204
+ }
1205
+ function getComponentsDocs(components) {
1206
+ return components.map((comp) => getComponentDoc(comp));
1207
+ }
1215
1208
  function docComponents(normalized, { name = null } = {}) {
1216
1209
  const comps = normalized.components;
1217
1210
  const picked = name === null ? comps : comps.filter((c) => c.name === name);
@@ -2848,9 +2841,14 @@ class ComponentStack {
2848
2841
  comp.scope = this.enter();
2849
2842
  this.comps.registerComponent(comp);
2850
2843
  this.byName[comp.name] = comp;
2851
- const alias = aliases[comp.name];
2852
- if (alias)
2844
+ }
2845
+ for (const alias in aliases) {
2846
+ const comp = this.byName[aliases[alias]];
2847
+ console.assert(this.byName[alias] === undefined, "alias overrides component", alias);
2848
+ if (comp !== undefined)
2853
2849
  this.byName[alias] = comp;
2850
+ else
2851
+ console.warn("alias", alias, "to inexistent component", aliases[alias]);
2854
2852
  }
2855
2853
  }
2856
2854
  registerMacros(macros) {
@@ -2877,34 +2875,43 @@ function defaultOnStackEnter(stack) {
2877
2875
  return stack;
2878
2876
  }
2879
2877
 
2880
- // src/lint/index.js
2878
+ // tools/core/lint-check.js
2881
2879
  var ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED";
2880
+ var ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED";
2882
2881
  var RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP";
2883
2882
  var UNKNOWN_EVENT_MODIFIER = "UNKNOWN_EVENT_MODIFIER";
2884
2883
  var UNKNOWN_HANDLER_ARG_NAME = "UNKNOWN_HANDLER_ARG_NAME";
2885
2884
  var INPUT_HANDLER_NOT_IMPLEMENTED = "INPUT_HANDLER_NOT_IMPLEMENTED";
2885
+ var INPUT_HANDLER_NOT_REFERENCED = "INPUT_HANDLER_NOT_REFERENCED";
2886
2886
  var INPUT_HANDLER_METHOD_NOT_IMPLEMENTED = "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED";
2887
2887
  var INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD = "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD";
2888
2888
  var INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER = "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER";
2889
2889
  var FIELD_VAL_NOT_DEFINED = "FIELD_VAL_NOT_DEFINED";
2890
2890
  var COMPUTED_VAL_NOT_DEFINED = "COMPUTED_VAL_NOT_DEFINED";
2891
+ var COMPUTED_NOT_REFERENCED = "COMPUTED_NOT_REFERENCED";
2891
2892
  var UNKNOWN_REQUEST_NAME = "UNKNOWN_REQUEST_NAME";
2892
2893
  var UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME";
2893
2894
  var LEVEL_WARN = "warn";
2894
2895
  var LEVEL_ERROR = "error";
2895
2896
  var LEVEL_HINT = "hint";
2896
2897
  function checkComponent(Comp, lx = new LintContext) {
2897
- checkEventHandlersHaveImpls(lx, Comp);
2898
- checkConsistentAttrs(lx, Comp);
2898
+ const referencedAlters = new Set;
2899
+ const referencedInputs = new Set;
2900
+ const referencedComputed = new Set;
2901
+ checkEventHandlersHaveImpls(lx, Comp, referencedInputs);
2902
+ checkConsistentAttrs(lx, Comp, referencedAlters, referencedComputed);
2899
2903
  for (const name in Comp.views) {
2900
- checkView(lx, Comp.views[name], Comp);
2904
+ checkView(lx, Comp.views[name], Comp, referencedAlters, referencedComputed);
2901
2905
  }
2906
+ checkUnreferencedAlterHandlers(lx, Comp, referencedAlters);
2907
+ checkUnreferencedInputHandlers(lx, Comp, referencedInputs);
2908
+ checkUnreferencedComputed(lx, Comp, referencedComputed);
2902
2909
  return lx;
2903
2910
  }
2904
- function checkView(lx, view, Comp) {
2911
+ function checkView(lx, view, Comp, referencedAlters, referencedComputed) {
2905
2912
  checkRenderItInLoop(lx, view);
2906
2913
  checkEventModifiers(lx, view);
2907
- checkKnownHandlerNames(lx, view, Comp);
2914
+ checkKnownHandlerNames(lx, view, Comp, referencedAlters, referencedComputed);
2908
2915
  }
2909
2916
  function checkRenderItInLoop(lx, view) {
2910
2917
  const { nodes } = view.ctx;
@@ -2956,7 +2963,7 @@ var KNOWN_HANDLER_NAMES = new Set([
2956
2963
  function isKnownHandlerName(name) {
2957
2964
  return KNOWN_HANDLER_NAMES.has(name);
2958
2965
  }
2959
- function checkKnownHandlerNames(lx, view, Comp) {
2966
+ function checkKnownHandlerNames(lx, view, Comp, referencedAlters, referencedComputed) {
2960
2967
  const { computed, scope, alter, Class } = Comp;
2961
2968
  const { prototype: proto } = Class;
2962
2969
  const { fields } = Class.getMetaClass();
@@ -2965,12 +2972,12 @@ function checkKnownHandlerNames(lx, view, Comp) {
2965
2972
  const { args } = handler.handlerCall;
2966
2973
  for (let i = 0;i < args.length; i++) {
2967
2974
  const arg = args[i];
2968
- checkConsistentAttrVal(lx, arg, fields, proto, computed, scope, alter);
2975
+ checkConsistentAttrVal(lx, arg, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
2969
2976
  }
2970
2977
  }
2971
2978
  }
2972
2979
  }
2973
- function checkEventHandlersHaveImpls(lx, Comp) {
2980
+ function checkEventHandlersHaveImpls(lx, Comp, referencedInputs) {
2974
2981
  const { input, views, Class } = Comp;
2975
2982
  const { prototype: proto } = Class;
2976
2983
  for (const viewName in views) {
@@ -2980,6 +2987,7 @@ function checkEventHandlersHaveImpls(lx, Comp) {
2980
2987
  const { handlerVal } = handler.handlerCall;
2981
2988
  const hvName = handlerVal?.constructor.name;
2982
2989
  if (hvName === "InputHandlerNameVal") {
2990
+ referencedInputs?.add(handlerVal.name);
2983
2991
  if (input[handlerVal.name] === undefined) {
2984
2992
  lx.warn(INPUT_HANDLER_NOT_IMPLEMENTED, {
2985
2993
  name: handlerVal.name,
@@ -2995,6 +3003,7 @@ function checkEventHandlersHaveImpls(lx, Comp) {
2995
3003
  }
2996
3004
  }
2997
3005
  } else if (hvName === "RawFieldVal") {
3006
+ referencedInputs?.add(handlerVal.name);
2998
3007
  if (proto[handlerVal.name] === undefined) {
2999
3008
  lx.warn(INPUT_HANDLER_METHOD_NOT_IMPLEMENTED, {
3000
3009
  name: handlerVal.name,
@@ -3014,7 +3023,7 @@ function checkEventHandlersHaveImpls(lx, Comp) {
3014
3023
  }
3015
3024
  }
3016
3025
  }
3017
- function checkConsistentAttrVal(lx, val, fields, proto, computed, scope, alter) {
3026
+ function checkConsistentAttrVal(lx, val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed) {
3018
3027
  const valName = val?.constructor.name;
3019
3028
  if (valName === "FieldVal" || valName === "RawFieldVal") {
3020
3029
  const { name } = val;
@@ -3023,12 +3032,13 @@ function checkConsistentAttrVal(lx, val, fields, proto, computed, scope, alter)
3023
3032
  }
3024
3033
  } else if (valName === "ComputedVal") {
3025
3034
  const { name } = val;
3035
+ referencedComputed?.add(name);
3026
3036
  if (computed[name] === undefined) {
3027
3037
  lx.error(COMPUTED_VAL_NOT_DEFINED, { val, name });
3028
3038
  }
3029
3039
  } else if (valName === "SeqAccessVal") {
3030
- checkConsistentAttrVal(lx, val.seqVal, fields, proto, computed, scope, alter);
3031
- checkConsistentAttrVal(lx, val.keyVal, fields, proto, computed, scope, alter);
3040
+ checkConsistentAttrVal(lx, val.seqVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
3041
+ checkConsistentAttrVal(lx, val.keyVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
3032
3042
  } else if (valName === "RequestVal") {
3033
3043
  if (scope.lookupRequest(val.name) === null) {
3034
3044
  lx.warn(UNKNOWN_REQUEST_NAME, { name: val.name });
@@ -3043,9 +3053,10 @@ function checkConsistentAttrVal(lx, val, fields, proto, computed, scope, alter)
3043
3053
  }
3044
3054
  } else if (valName === "StrTplVal") {
3045
3055
  for (const subVal of val.vals) {
3046
- checkConsistentAttrVal(lx, subVal, fields, proto, computed, scope, alter);
3056
+ checkConsistentAttrVal(lx, subVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
3047
3057
  }
3048
3058
  } else if (valName === "AlterHandlerNameVal") {
3059
+ referencedAlters?.add(val.name);
3049
3060
  if (alter[val.name] === undefined) {
3050
3061
  lx.warn(ALT_HANDLER_NOT_DEFINED, { name: val.name });
3051
3062
  }
@@ -3053,7 +3064,7 @@ function checkConsistentAttrVal(lx, val, fields, proto, computed, scope, alter)
3053
3064
  console.log(val);
3054
3065
  }
3055
3066
  }
3056
- function checkConsistentAttrs(lx, Comp) {
3067
+ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedComputed) {
3057
3068
  const { computed, scope, views, alter, Class } = Comp;
3058
3069
  const { prototype: proto } = Class;
3059
3070
  const { fields } = Class.getMetaClass();
@@ -3064,7 +3075,7 @@ function checkConsistentAttrs(lx, Comp) {
3064
3075
  if (attrs?.constructor.name === "DynAttrs") {
3065
3076
  for (const attr2 of attrs.items) {
3066
3077
  if (attr2?.constructor.name === "Attr") {
3067
- checkConsistentAttrVal(lx, attr2.val, fields, proto, computed, scope, alter);
3078
+ checkConsistentAttrVal(lx, attr2.val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
3068
3079
  }
3069
3080
  }
3070
3081
  }
@@ -3072,27 +3083,48 @@ function checkConsistentAttrs(lx, Comp) {
3072
3083
  for (const w of wrapperAttrs) {
3073
3084
  if (w.name === "each") {
3074
3085
  if (w.whenVal)
3075
- checkConsistentAttrVal(lx, w.whenVal, fields, proto, computed, scope, alter);
3086
+ checkConsistentAttrVal(lx, w.whenVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
3076
3087
  if (w.enrichWithVal)
3077
- checkConsistentAttrVal(lx, w.enrichWithVal, fields, proto, computed, scope, alter);
3088
+ checkConsistentAttrVal(lx, w.enrichWithVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
3078
3089
  if (w.loopWithVal)
3079
- checkConsistentAttrVal(lx, w.loopWithVal, fields, proto, computed, scope, alter);
3090
+ checkConsistentAttrVal(lx, w.loopWithVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
3080
3091
  } else if (w.name !== "scope") {
3081
- checkConsistentAttrVal(lx, w.val, fields, proto, computed, scope, alter);
3092
+ checkConsistentAttrVal(lx, w.val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
3082
3093
  }
3083
3094
  }
3084
3095
  }
3085
3096
  if (textChild) {
3086
- checkConsistentAttrVal(lx, textChild, fields, proto, computed, scope, alter);
3097
+ checkConsistentAttrVal(lx, textChild, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
3087
3098
  }
3088
3099
  }
3089
3100
  for (const node of view.ctx.nodes) {
3090
3101
  if (node.val) {
3091
- checkConsistentAttrVal(lx, node.val, fields, proto, computed, scope, alter);
3102
+ checkConsistentAttrVal(lx, node.val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
3092
3103
  }
3093
3104
  }
3094
3105
  }
3095
3106
  }
3107
+ function checkUnreferencedAlterHandlers(lx, Comp, referencedAlters) {
3108
+ for (const name in Comp.alter) {
3109
+ if (!referencedAlters.has(name)) {
3110
+ lx.hint(ALT_HANDLER_NOT_REFERENCED, { name });
3111
+ }
3112
+ }
3113
+ }
3114
+ function checkUnreferencedInputHandlers(lx, Comp, referencedInputs) {
3115
+ for (const name in Comp.input) {
3116
+ if (!referencedInputs.has(name)) {
3117
+ lx.hint(INPUT_HANDLER_NOT_REFERENCED, { name });
3118
+ }
3119
+ }
3120
+ }
3121
+ function checkUnreferencedComputed(lx, Comp, referencedComputed) {
3122
+ for (const name in Comp.computed) {
3123
+ if (!referencedComputed.has(name)) {
3124
+ lx.hint(COMPUTED_NOT_REFERENCED, { name });
3125
+ }
3126
+ }
3127
+ }
3096
3128
 
3097
3129
  class LintContext {
3098
3130
  constructor() {
@@ -3405,9 +3437,10 @@ class Transactor {
3405
3437
  }
3406
3438
  }
3407
3439
  function mkReq404(name) {
3408
- return () => {
3440
+ const fn = () => {
3409
3441
  throw new Error(`Request not found: ${name}`);
3410
3442
  };
3443
+ return { fn };
3411
3444
  }
3412
3445
  function nullHandler() {
3413
3446
  return this;
@@ -4048,15 +4081,13 @@ class App {
4048
4081
  _dispatchEvent(e) {
4049
4082
  const { type } = e;
4050
4083
  const isDrag = type === "dragover" || type === "dragstart" || type === "dragend";
4051
- const { rootNode: root, maxEventNodeDepth: maxDepth, comps } = this;
4084
+ const { rootNode: root, maxEventNodeDepth: maxDepth, comps, transactor } = this;
4052
4085
  const [path, handlers] = Path.fromEvent(e, root, maxDepth, comps, !isDrag);
4053
4086
  if (isDrag)
4054
4087
  this._handleDragEvent(e, type, path);
4055
- if (path !== null && handlers !== null) {
4056
- for (const handler of handlers) {
4057
- this.transactor.transactInputNow(path, e, handler, this.dragInfo);
4058
- }
4059
- }
4088
+ if (path !== null && handlers !== null)
4089
+ for (const handler of handlers)
4090
+ transactor.transactInputNow(path, e, handler, this.dragInfo);
4060
4091
  }
4061
4092
  _handleTouchEvent(e) {
4062
4093
  const { type } = e;