@tinya-code/gas-admin-ui 0.2.0-alpha.15 → 0.2.0-alpha.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (368) hide show
  1. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs +84 -0
  2. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs.map +1 -0
  3. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs +140 -0
  4. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs.map +1 -0
  5. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs +113 -0
  6. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs.map +1 -0
  7. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs +163 -0
  8. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs.map +1 -0
  9. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs +1027 -0
  10. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs.map +1 -0
  11. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs +278 -0
  12. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs.map +1 -0
  13. package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs +107 -0
  14. package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs.map +1 -0
  15. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs +101 -0
  16. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs.map +1 -0
  17. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs +141 -0
  18. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs.map +1 -0
  19. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs +88 -0
  20. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs.map +1 -0
  21. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs +107 -0
  22. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs.map +1 -0
  23. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs +140 -0
  24. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs.map +1 -0
  25. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs +119 -0
  26. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs.map +1 -0
  27. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs +125 -0
  28. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs.map +1 -0
  29. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs +152 -0
  30. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs.map +1 -0
  31. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs +211 -0
  32. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs.map +1 -0
  33. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs +116 -0
  34. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs.map +1 -0
  35. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs +111 -0
  36. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs.map +1 -0
  37. package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs +122 -0
  38. package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs.map +1 -0
  39. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs +107 -0
  40. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs.map +1 -0
  41. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs +109 -0
  42. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs.map +1 -0
  43. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs +45 -0
  44. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs.map +1 -0
  45. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs +50 -0
  46. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs.map +1 -0
  47. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs +24 -0
  48. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs.map +1 -0
  49. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs +27 -0
  50. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs.map +1 -0
  51. package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs +408 -0
  52. package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs.map +1 -0
  53. package/fesm2022/tinya-code-gas-admin-ui-form-view-CEe7aZ4m.mjs +4516 -0
  54. package/fesm2022/tinya-code-gas-admin-ui-form-view-CEe7aZ4m.mjs.map +1 -0
  55. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs +82 -0
  56. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs.map +1 -0
  57. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs +105 -0
  58. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs.map +1 -0
  59. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs +65 -0
  60. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs.map +1 -0
  61. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs +65 -0
  62. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs.map +1 -0
  63. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs +65 -0
  64. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs.map +1 -0
  65. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs +59 -0
  66. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs.map +1 -0
  67. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs +94 -0
  68. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs.map +1 -0
  69. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs +72 -0
  70. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs.map +1 -0
  71. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs +238 -0
  72. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs.map +1 -0
  73. package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs +416 -0
  74. package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs.map +1 -0
  75. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs +439 -0
  76. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs.map +1 -0
  77. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs +513 -0
  78. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs.map +1 -0
  79. package/fesm2022/tinya-code-gas-admin-ui-list-DTtCYS4d.mjs +637 -0
  80. package/fesm2022/tinya-code-gas-admin-ui-list-DTtCYS4d.mjs.map +1 -0
  81. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs +127 -0
  82. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs.map +1 -0
  83. package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs +251 -0
  84. package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs.map +1 -0
  85. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs +66 -0
  86. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs.map +1 -0
  87. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs +114 -0
  88. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs.map +1 -0
  89. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs +116 -0
  90. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs.map +1 -0
  91. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs +235 -0
  92. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs.map +1 -0
  93. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs +8 -0
  94. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs.map +1 -0
  95. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs +124 -0
  96. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs.map +1 -0
  97. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs +249 -0
  98. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs.map +1 -0
  99. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs +39 -0
  100. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs.map +1 -0
  101. package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs +309 -0
  102. package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs.map +1 -0
  103. package/fesm2022/tinya-code-gas-admin-ui-render-registry-B88Pme-y.mjs +576 -0
  104. package/fesm2022/tinya-code-gas-admin-ui-render-registry-B88Pme-y.mjs.map +1 -0
  105. package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs +161 -0
  106. package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs.map +1 -0
  107. package/fesm2022/tinya-code-gas-admin-ui-rolldown-runtime-DpJrqANO.mjs +11 -0
  108. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs +685 -0
  109. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs.map +1 -0
  110. package/fesm2022/tinya-code-gas-admin-ui-seed-DkVZbxPP.mjs +80 -0
  111. package/fesm2022/tinya-code-gas-admin-ui-seed-DkVZbxPP.mjs.map +1 -0
  112. package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs +296 -0
  113. package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs.map +1 -0
  114. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs +119 -0
  115. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs.map +1 -0
  116. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs +158 -0
  117. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs.map +1 -0
  118. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs +26 -0
  119. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs.map +1 -0
  120. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs +205 -0
  121. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs.map +1 -0
  122. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs +432 -0
  123. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs.map +1 -0
  124. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs +36 -0
  125. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs.map +1 -0
  126. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs +107 -0
  127. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs.map +1 -0
  128. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs +223 -0
  129. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs.map +1 -0
  130. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs +107 -0
  131. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs.map +1 -0
  132. package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs +60 -0
  133. package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs.map +1 -0
  134. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs +141 -0
  135. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs.map +1 -0
  136. package/fesm2022/tinya-code-gas-admin-ui.mjs +4738 -0
  137. package/fesm2022/tinya-code-gas-admin-ui.mjs.map +1 -0
  138. package/package.json +15 -3
  139. package/types/tinya-code-gas-admin-ui.d.ts +3634 -0
  140. package/ng-package.json +0 -7
  141. package/src/lib/actions/action-registry.spec.ts +0 -52
  142. package/src/lib/actions/action-registry.ts +0 -126
  143. package/src/lib/actions/action-service.spec.ts +0 -215
  144. package/src/lib/actions/action-service.ts +0 -87
  145. package/src/lib/actions/descriptors.spec.ts +0 -155
  146. package/src/lib/actions/descriptors.ts +0 -154
  147. package/src/lib/columns/column-cell.ts +0 -33
  148. package/src/lib/columns/column-defaults.spec.ts +0 -99
  149. package/src/lib/columns/column-defaults.ts +0 -84
  150. package/src/lib/columns/column-format.spec.ts +0 -274
  151. package/src/lib/columns/descriptors.ts +0 -113
  152. package/src/lib/columns/format-badge.ts +0 -51
  153. package/src/lib/columns/format-boolean.ts +0 -58
  154. package/src/lib/columns/format-currency.ts +0 -30
  155. package/src/lib/columns/format-date.ts +0 -35
  156. package/src/lib/columns/format-number.ts +0 -32
  157. package/src/lib/columns/format-text.ts +0 -23
  158. package/src/lib/columns/format-thumbnail.ts +0 -63
  159. package/src/lib/core/adapters/firebase-auth.adapter.ts +0 -6
  160. package/src/lib/core/guards/auth.guard.spec.ts +0 -88
  161. package/src/lib/core/guards/auth.guard.ts +0 -48
  162. package/src/lib/core/guards/unsaved-changes.guard.ts +0 -16
  163. package/src/lib/core/interceptors/api-error.interceptor.spec.ts +0 -182
  164. package/src/lib/core/interceptors/api-error.interceptor.ts +0 -87
  165. package/src/lib/core/models/api.model.ts +0 -104
  166. package/src/lib/core/models/schema-descriptions.ts +0 -118
  167. package/src/lib/core/models/schema.model.ts +0 -1097
  168. package/src/lib/core/registry/composition-validator.spec.ts +0 -358
  169. package/src/lib/core/registry/composition-validator.ts +0 -270
  170. package/src/lib/core/registry/field-validators.spec.ts +0 -199
  171. package/src/lib/core/registry/field-validators.ts +0 -440
  172. package/src/lib/core/registry/render-host.spec.ts +0 -208
  173. package/src/lib/core/registry/render-host.ts +0 -646
  174. package/src/lib/core/registry/render-registry.spec.ts +0 -96
  175. package/src/lib/core/registry/render-registry.ts +0 -312
  176. package/src/lib/core/registry/schema-catalog.ts +0 -156
  177. package/src/lib/core/services/api.service.spec.ts +0 -1142
  178. package/src/lib/core/services/api.service.ts +0 -371
  179. package/src/lib/core/services/auth.service.spec.ts +0 -653
  180. package/src/lib/core/services/auth.service.ts +0 -503
  181. package/src/lib/core/services/config.service.spec.ts +0 -121
  182. package/src/lib/core/services/config.service.ts +0 -119
  183. package/src/lib/core/services/data-source.service.spec.ts +0 -179
  184. package/src/lib/core/services/data-source.service.ts +0 -142
  185. package/src/lib/core/services/error-mapper.service.spec.ts +0 -50
  186. package/src/lib/core/services/error-mapper.service.ts +0 -49
  187. package/src/lib/core/services/notification.service.ts +0 -73
  188. package/src/lib/core/services/relation-drawer.service.ts +0 -41
  189. package/src/lib/core/services/theme.service.spec.ts +0 -106
  190. package/src/lib/core/services/theme.service.ts +0 -86
  191. package/src/lib/core/services/transport.spec.ts +0 -198
  192. package/src/lib/core/services/transport.ts +0 -164
  193. package/src/lib/core/services/upload.service.ts +0 -81
  194. package/src/lib/core/testing/categories.schema.ts +0 -125
  195. package/src/lib/core/testing/orders.schema.ts +0 -372
  196. package/src/lib/core/testing/products.schema.ts +0 -258
  197. package/src/lib/core/testing/site.schema.ts +0 -195
  198. package/src/lib/core/testing/test-catalog.ts +0 -21
  199. package/src/lib/core/tokens.ts +0 -112
  200. package/src/lib/core/utils/clipboard.spec.ts +0 -55
  201. package/src/lib/core/utils/clipboard.ts +0 -90
  202. package/src/lib/core/utils/context-resolver.spec.ts +0 -95
  203. package/src/lib/core/utils/context-resolver.ts +0 -101
  204. package/src/lib/core/utils/response-unwrapper.spec.ts +0 -70
  205. package/src/lib/core/utils/response-unwrapper.ts +0 -103
  206. package/src/lib/core/utils/source-options.spec.ts +0 -96
  207. package/src/lib/core/utils/source-options.ts +0 -54
  208. package/src/lib/core/utils/template-interpolator.spec.ts +0 -59
  209. package/src/lib/core/utils/template-interpolator.ts +0 -56
  210. package/src/lib/core/view-navigation/view-navigation.service.spec.ts +0 -207
  211. package/src/lib/core/view-navigation/view-navigation.service.ts +0 -132
  212. package/src/lib/fields/boolean/boolean.descriptor.ts +0 -11
  213. package/src/lib/fields/boolean/boolean.ts +0 -40
  214. package/src/lib/fields/color/color.descriptor.ts +0 -12
  215. package/src/lib/fields/color/color.ts +0 -34
  216. package/src/lib/fields/currency/currency.descriptor.ts +0 -12
  217. package/src/lib/fields/currency/currency.ts +0 -67
  218. package/src/lib/fields/date/date.descriptor.ts +0 -12
  219. package/src/lib/fields/date/date.ts +0 -36
  220. package/src/lib/fields/descriptors.ts +0 -122
  221. package/src/lib/fields/display/display-badge.ts +0 -65
  222. package/src/lib/fields/display/display-date.ts +0 -39
  223. package/src/lib/fields/display/display-defaults.ts +0 -84
  224. package/src/lib/fields/display/display-file.ts +0 -41
  225. package/src/lib/fields/display/display-image.ts +0 -54
  226. package/src/lib/fields/display/display-list.ts +0 -107
  227. package/src/lib/fields/display/display-number.ts +0 -41
  228. package/src/lib/fields/display/display-text.ts +0 -42
  229. package/src/lib/fields/display/display.spec.ts +0 -242
  230. package/src/lib/fields/dropdown/dropdown.descriptor.ts +0 -12
  231. package/src/lib/fields/dropdown/dropdown.ts +0 -45
  232. package/src/lib/fields/email/email.descriptor.ts +0 -12
  233. package/src/lib/fields/email/email.ts +0 -28
  234. package/src/lib/fields/field-aria.ts +0 -60
  235. package/src/lib/fields/field-host/field-host.spec.ts +0 -118
  236. package/src/lib/fields/field-host/field-host.ts +0 -47
  237. package/src/lib/fields/field-node.ts +0 -88
  238. package/src/lib/fields/file/file.descriptor.ts +0 -14
  239. package/src/lib/fields/file/file.spec.ts +0 -134
  240. package/src/lib/fields/file/file.ts +0 -281
  241. package/src/lib/fields/group/group.descriptor.ts +0 -21
  242. package/src/lib/fields/group/group.ts +0 -110
  243. package/src/lib/fields/image/image.descriptor.ts +0 -12
  244. package/src/lib/fields/image/image.spec.ts +0 -117
  245. package/src/lib/fields/image/image.ts +0 -281
  246. package/src/lib/fields/key-value/key-value.descriptor.ts +0 -11
  247. package/src/lib/fields/key-value/key-value.ts +0 -283
  248. package/src/lib/fields/list/list.descriptor.ts +0 -21
  249. package/src/lib/fields/list/list.ts +0 -376
  250. package/src/lib/fields/multiselect/multiselect.descriptor.ts +0 -11
  251. package/src/lib/fields/multiselect/multiselect.spec.ts +0 -142
  252. package/src/lib/fields/multiselect/multiselect.ts +0 -152
  253. package/src/lib/fields/number/number.descriptor.ts +0 -12
  254. package/src/lib/fields/number/number.ts +0 -40
  255. package/src/lib/fields/phone/phone.descriptor.ts +0 -12
  256. package/src/lib/fields/phone/phone.ts +0 -46
  257. package/src/lib/fields/readonly-text/readonly-text.descriptor.ts +0 -12
  258. package/src/lib/fields/readonly-text/readonly-text.ts +0 -58
  259. package/src/lib/fields/relation/relation.descriptor.ts +0 -12
  260. package/src/lib/fields/relation/relation.spec.ts +0 -193
  261. package/src/lib/fields/relation/relation.ts +0 -224
  262. package/src/lib/fields/rich-select/rich-select.descriptor.ts +0 -12
  263. package/src/lib/fields/rich-select/rich-select.ts +0 -175
  264. package/src/lib/fields/select/radio-mode.ts +0 -25
  265. package/src/lib/fields/select/select.descriptor.ts +0 -12
  266. package/src/lib/fields/select/select.spec.ts +0 -162
  267. package/src/lib/fields/select/select.ts +0 -210
  268. package/src/lib/fields/slug/slug.descriptor.ts +0 -19
  269. package/src/lib/fields/slug/slug.ts +0 -67
  270. package/src/lib/fields/string-list/string-list.descriptor.ts +0 -11
  271. package/src/lib/fields/string-list/string-list.ts +0 -222
  272. package/src/lib/fields/text/text.descriptor.ts +0 -12
  273. package/src/lib/fields/text/text.ts +0 -35
  274. package/src/lib/fields/textarea/textarea.descriptor.ts +0 -12
  275. package/src/lib/fields/textarea/textarea.spec.ts +0 -117
  276. package/src/lib/fields/textarea/textarea.ts +0 -126
  277. package/src/lib/fields/time/time.descriptor.ts +0 -12
  278. package/src/lib/fields/time/time.ts +0 -28
  279. package/src/lib/fields/unknown-render/unknown-render.ts +0 -49
  280. package/src/lib/fields/url/url.descriptor.ts +0 -12
  281. package/src/lib/fields/url/url.ts +0 -53
  282. package/src/lib/gas-admin-ui.spec.ts +0 -21
  283. package/src/lib/gas-admin-ui.ts +0 -9
  284. package/src/lib/layouts/descriptors.ts +0 -9
  285. package/src/lib/pages/dashboard/dashboard.ts +0 -167
  286. package/src/lib/pages/detail-view/detail-view.spec.ts +0 -333
  287. package/src/lib/pages/detail-view/detail-view.ts +0 -570
  288. package/src/lib/pages/drawer-form/drawer-form.ts +0 -228
  289. package/src/lib/pages/form-view/form-model.ts +0 -88
  290. package/src/lib/pages/form-view/form-schema.ts +0 -255
  291. package/src/lib/pages/form-view/form-view.ts +0 -1622
  292. package/src/lib/pages/list-view/list-view.formats.spec.ts +0 -214
  293. package/src/lib/pages/list-view/list-view.ts +0 -882
  294. package/src/lib/pages/login/login.spec.ts +0 -109
  295. package/src/lib/pages/login/login.ts +0 -227
  296. package/src/lib/pages/resource-page/resource-page.ts +0 -234
  297. package/src/lib/shared/components/badge/badge.ts +0 -35
  298. package/src/lib/shared/components/button/button.ts +0 -65
  299. package/src/lib/shared/components/confirm-dialog/confirm-dialog.ts +0 -48
  300. package/src/lib/shared/components/copy-button/copy-button.ts +0 -56
  301. package/src/lib/shared/components/copy-share/copy-share.spec.ts +0 -122
  302. package/src/lib/shared/components/copy-share/copy-share.ts +0 -107
  303. package/src/lib/shared/components/drawer/drawer.spec.ts +0 -127
  304. package/src/lib/shared/components/drawer/drawer.ts +0 -172
  305. package/src/lib/shared/components/empty-state/empty-state.ts +0 -30
  306. package/src/lib/shared/components/modal/modal.spec.ts +0 -149
  307. package/src/lib/shared/components/modal/modal.ts +0 -145
  308. package/src/lib/shared/components/post-create-modal/post-create-modal.spec.ts +0 -165
  309. package/src/lib/shared/components/post-create-modal/post-create-modal.ts +0 -159
  310. package/src/lib/shared/components/skeleton/skeleton.ts +0 -31
  311. package/src/lib/shared/components/toast/toast.ts +0 -58
  312. package/src/lib/shared/utils/col-span.ts +0 -25
  313. package/src/lib/shared/utils/condition-evaluator.ts +0 -53
  314. package/src/lib/shared/utils/depends-on.ts +0 -48
  315. package/src/lib/shared/utils/dialog-focus.ts +0 -28
  316. package/src/lib/shared/utils/field-path.ts +0 -49
  317. package/src/lib/shared/utils/gap-sorting.ts +0 -144
  318. package/src/lib/shared/utils/seed.spec.ts +0 -64
  319. package/src/lib/shared/utils/seed.ts +0 -149
  320. package/src/lib/shared/utils/slugify.ts +0 -13
  321. package/src/lib/shared/utils/validators.ts +0 -41
  322. package/src/lib/shell/layout/layout.ts +0 -63
  323. package/src/lib/shell/shell.routes.spec.ts +0 -59
  324. package/src/lib/shell/shell.routes.ts +0 -122
  325. package/src/lib/shell/sidebar/sidebar.ts +0 -139
  326. package/src/lib/shell/theme-toggle/theme-toggle.ts +0 -74
  327. package/src/lib/views/calendar-view/calendar-model.ts +0 -426
  328. package/src/lib/views/calendar-view/calendar-view.spec.ts +0 -557
  329. package/src/lib/views/calendar-view/calendar-view.ts +0 -568
  330. package/src/lib/views/composer/composer-host.spec.ts +0 -301
  331. package/src/lib/views/composer/composer-host.ts +0 -248
  332. package/src/lib/views/composer/composer-imports.spec.ts +0 -54
  333. package/src/lib/views/composer/view-context.spec.ts +0 -117
  334. package/src/lib/views/composer/view-context.ts +0 -109
  335. package/src/lib/views/composer/view-slot.spec.ts +0 -130
  336. package/src/lib/views/composer/view-slot.ts +0 -178
  337. package/src/lib/views/descriptors.ts +0 -46
  338. package/src/lib/views/kanban-view/kanban-model.ts +0 -173
  339. package/src/lib/views/kanban-view/kanban-view.spec.ts +0 -540
  340. package/src/lib/views/kanban-view/kanban-view.ts +0 -327
  341. package/src/lib/widgets/bar-chart/bar-chart.descriptor.ts +0 -17
  342. package/src/lib/widgets/bar-chart/bar-chart.spec.ts +0 -66
  343. package/src/lib/widgets/bar-chart/bar-chart.ts +0 -76
  344. package/src/lib/widgets/chart-line/chart-line.descriptor.ts +0 -17
  345. package/src/lib/widgets/chart-line/chart-line.spec.ts +0 -113
  346. package/src/lib/widgets/chart-line/chart-line.ts +0 -219
  347. package/src/lib/widgets/descriptors.ts +0 -29
  348. package/src/lib/widgets/metric-card/metric-card.descriptor.ts +0 -41
  349. package/src/lib/widgets/metric-card/metric-card.spec.ts +0 -52
  350. package/src/lib/widgets/metric-card/metric-card.ts +0 -48
  351. package/src/lib/widgets/quick-actions/quick-actions.descriptor.ts +0 -13
  352. package/src/lib/widgets/quick-actions/quick-actions.spec.ts +0 -61
  353. package/src/lib/widgets/quick-actions/quick-actions.ts +0 -100
  354. package/src/lib/widgets/record-list/record-list.descriptor.ts +0 -16
  355. package/src/lib/widgets/record-list/record-list.spec.ts +0 -79
  356. package/src/lib/widgets/record-list/record-list.ts +0 -115
  357. package/src/lib/widgets/series.spec.ts +0 -42
  358. package/src/lib/widgets/series.ts +0 -56
  359. package/src/lib/widgets/status-progress/status-progress.descriptor.ts +0 -19
  360. package/src/lib/widgets/status-progress/status-progress.spec.ts +0 -63
  361. package/src/lib/widgets/status-progress/status-progress.ts +0 -104
  362. package/src/lib/widgets/widget-host/widget-host.spec.ts +0 -179
  363. package/src/lib/widgets/widget-host/widget-host.ts +0 -99
  364. package/src/public-api.ts +0 -104
  365. package/tinya-code-gas-admin-ui-0.2.0-alpha.15.tgz +0 -0
  366. package/tsconfig.lib.json +0 -13
  367. package/tsconfig.lib.prod.json +0 -11
  368. package/tsconfig.spec.json +0 -10
@@ -1,358 +0,0 @@
1
- import { setSchemaCatalog } from './schema-catalog';
2
- import { testCatalog } from '../testing/test-catalog';
3
-
4
- setSchemaCatalog(testCatalog);
5
-
6
- import { describe, expect, it } from 'vitest';
7
-
8
- import type {
9
- DataSource,
10
- NavigationTarget,
11
- ResourceSchema,
12
- SelectionBinding,
13
- UiViewTabs,
14
- ViewChildNode,
15
- } from '../models/schema.model';
16
- import {
17
- MAX_DEPTH,
18
- MAX_NODES,
19
- SchemaCompositionError,
20
- validateComposition,
21
- } from './composition-validator';
22
-
23
- /** Schema sintético mínimo para ejercitar el validador (D2 · R9.9.2). */
24
- function esquemaCon(uiViews: NonNullable<ResourceSchema['uiViews']>): ResourceSchema {
25
- return {
26
- id: 'orders',
27
- label: 'Pedidos',
28
- labelPlural: 'Pedidos',
29
- kind: 'collection',
30
- endpoint: {},
31
- keyField: 'id',
32
- titleField: 'title',
33
- listColumns: [],
34
- fields: [],
35
- uiViews,
36
- };
37
- }
38
-
39
- function tabs(children: ViewChildNode[]): UiViewTabs {
40
- return { type: 'tabs', path: 'panel', config: { children } };
41
- }
42
-
43
- function hijo(id: string, type = 'list'): ViewChildNode {
44
- return { id, label: `Hijo ${id}`, type };
45
- }
46
-
47
- /** Exige un `SchemaCompositionError` cuyo mensaje nombra todos los fragmentos. */
48
- function expectaError(fn: () => void, ...fragmentos: string[]): void {
49
- let error: unknown;
50
- try {
51
- fn();
52
- } catch (caught) {
53
- error = caught;
54
- }
55
- expect(error, 'se esperaba un SchemaCompositionError').toBeInstanceOf(SchemaCompositionError);
56
- for (const fragmento of fragmentos) {
57
- expect((error as Error).message).toContain(fragmento);
58
- }
59
- }
60
-
61
- describe('composition-validator', () => {
62
- it('acepta una composición heterogénea válida', () => {
63
- const schema = esquemaCon({
64
- panel: tabs([
65
- {
66
- id: 'cal',
67
- label: 'Calendario',
68
- type: 'calendar',
69
- config: { startField: 'pickup_date', titleField: 'customer_name' },
70
- },
71
- {
72
- id: 'board',
73
- label: 'Tablero',
74
- type: 'kanban',
75
- config: { groupField: 'status', columns: [] },
76
- },
77
- { id: 'rows', label: 'Filas', type: 'list' },
78
- ]),
79
- list: { type: 'list' },
80
- });
81
-
82
- expect(() => validateComposition(schema)).not.toThrow();
83
- });
84
-
85
- it('deja pasar un schema sin composición (uiViews base)', () => {
86
- const schema = esquemaCon({
87
- list: { type: 'list' },
88
- create: { type: 'form', path: 'new' },
89
- detail: { type: 'detail', path: ':key' },
90
- });
91
-
92
- expect(() => validateComposition(schema)).not.toThrow();
93
- });
94
-
95
- it('falla con id duplicado nombrando contenedor e id', () => {
96
- const schema = esquemaCon({ panel: tabs([hijo('cal'), hijo('cal')]) });
97
-
98
- expectaError(() => validateComposition(schema), 'orders.panel', 'cal', 'duplicado');
99
- });
100
-
101
- it('falla con un hijo sin id nombrando el contenedor', () => {
102
- const sinId = { label: 'Sin id', type: 'list' } as ViewChildNode;
103
- const schema = esquemaCon({ panel: tabs([sinId]) });
104
-
105
- expectaError(() => validateComposition(schema), 'orders.panel', 'sin id');
106
- });
107
-
108
- it('falla con tipo de hijo sin descriptor nombrando recurso, contenedor e hijo (get, no resolve)', () => {
109
- const schema = esquemaCon({ panel: tabs([hijo('cal', 'heatmap')]) });
110
-
111
- expectaError(() => validateComposition(schema), 'orders', 'panel', 'cal', 'heatmap');
112
- });
113
-
114
- // ── Ciclos y refs (R9.9.2 · los `ref` hacen posible el ciclo) ──────────────
115
-
116
- it('detecta un ciclo directo por ref nombrando hijo y contenedor', () => {
117
- const schema = esquemaCon({
118
- panel: tabs([{ id: 'self', label: 'Autorreferencia', ref: 'panel' }]),
119
- });
120
-
121
- expectaError(() => validateComposition(schema), 'orders.panel', 'self', 'ciclo');
122
- });
123
-
124
- it('detecta un ciclo transitivo por ref', () => {
125
- const schema = esquemaCon({
126
- a: tabs([{ id: 'ab', label: 'AB', ref: 'b' }]),
127
- b: tabs([{ id: 'ba', label: 'BA', ref: 'a' }]),
128
- });
129
-
130
- expectaError(() => validateComposition(schema), 'ba', 'ciclo');
131
- });
132
-
133
- it('falla con un ref roto nombrando el hijo y el destino inexistente', () => {
134
- const schema = esquemaCon({
135
- panel: tabs([{ id: 'rows', label: 'Filas', ref: 'no-existe' }]),
136
- });
137
-
138
- expectaError(() => validateComposition(schema), 'orders.panel', 'rows', 'no-existe');
139
- });
140
-
141
- // ── Topes configurables (D2: MAX_DEPTH / MAX_NODES) ────────────────────────
142
-
143
- it('acepta un anidamiento justo en el límite de profundidad', () => {
144
- // a → b → c: los hijos de `c` quedan en profundidad MAX_DEPTH.
145
- const schema = esquemaCon({
146
- a: tabs([{ id: 'n1', label: 'N1', ref: 'b' }]),
147
- b: tabs([{ id: 'n2', label: 'N2', ref: 'c' }]),
148
- c: tabs([{ id: 'n3', label: 'N3', type: 'list' }]),
149
- });
150
-
151
- expect(() => validateComposition(schema)).not.toThrow();
152
- });
153
-
154
- it('falla con profundidad sobre el límite nombrando el hijo y la profundidad observada', () => {
155
- const schema = esquemaCon({
156
- a: tabs([{ id: 'n1', label: 'N1', ref: 'b' }]),
157
- b: tabs([{ id: 'n2', label: 'N2', ref: 'c' }]),
158
- c: tabs([{ id: 'n3', label: 'N3', ref: 'd' }]),
159
- d: tabs([{ id: 'n4', label: 'N4', type: 'list' }]),
160
- });
161
-
162
- expectaError(() => validateComposition(schema), 'n4', '4', String(MAX_DEPTH));
163
- });
164
-
165
- it('valida la profundidad ANIDADA dentro de un contenedor inline (no sólo vía ref)', () => {
166
- // panel → n1 → n2 → n3 (todos tabs inline) ⇒ los hijos de n3 están en
167
- // profundidad 4 y deben reventar ANTES del render (D2).
168
- const schema = esquemaCon({
169
- panel: tabs([
170
- {
171
- id: 'n1',
172
- label: 'N1',
173
- type: 'tabs',
174
- config: {
175
- children: [
176
- {
177
- id: 'n2',
178
- label: 'N2',
179
- type: 'tabs',
180
- config: {
181
- children: [
182
- {
183
- id: 'n3',
184
- label: 'N3',
185
- type: 'tabs',
186
- config: { children: [hijo('n4')] },
187
- },
188
- ],
189
- },
190
- },
191
- ],
192
- },
193
- },
194
- ]),
195
- });
196
-
197
- expectaError(() => validateComposition(schema), 'n4', 'profundidad', String(MAX_DEPTH));
198
- });
199
-
200
- it('detecta un ciclo que atraviesa un contenedor inline (D2)', () => {
201
- const schema = esquemaCon({
202
- panel: tabs([
203
- {
204
- id: 'hijo',
205
- label: 'Hijo',
206
- type: 'tabs',
207
- config: { children: [{ id: 'loop', label: 'Loop', ref: 'panel' }] },
208
- },
209
- ]),
210
- });
211
-
212
- expectaError(() => validateComposition(schema), 'ciclo', 'panel');
213
- });
214
-
215
- it('acepta una composición con exactamente MAX_NODES nodos', () => {
216
- const hijos = Array.from({ length: MAX_NODES }, (_, i) => hijo(`n${i}`));
217
- const schema = esquemaCon({ panel: tabs(hijos) });
218
-
219
- expect(() => validateComposition(schema)).not.toThrow();
220
- });
221
-
222
- it('falla al superar MAX_NODES nombrando el tope', () => {
223
- const hijos = Array.from({ length: MAX_NODES + 1 }, (_, i) => hijo(`n${i}`));
224
- const schema = esquemaCon({ panel: tabs(hijos) });
225
-
226
- expectaError(() => validateComposition(schema), 'límite de', String(MAX_NODES));
227
- });
228
-
229
- // ── Destino de navegación (spec view-navigation: URL cruda rechazada) ──────
230
-
231
- it('rechaza una URL cruda como destino nombrando recurso, contenedor e hijo', () => {
232
- const schema = esquemaCon({
233
- panel: tabs([
234
- {
235
- id: 'rows',
236
- label: 'Filas',
237
- type: 'list',
238
- select: {
239
- on: 'open',
240
- mode: 'route',
241
- target: 'https://evil.com/x' as unknown as NavigationTarget,
242
- },
243
- },
244
- ]),
245
- });
246
-
247
- expectaError(
248
- () => validateComposition(schema),
249
- 'orders.panel',
250
- 'rows',
251
- 'URL cruda',
252
- 'https://evil.com/x',
253
- );
254
- });
255
-
256
- it('rechaza una URL cruda declarada en una uiView raíz', () => {
257
- const schema = esquemaCon({
258
- list: {
259
- type: 'list',
260
- select: {
261
- on: 'open',
262
- mode: 'route',
263
- target: '/dashboard' as unknown as NavigationTarget,
264
- },
265
- },
266
- });
267
-
268
- expectaError(() => validateComposition(schema), 'orders.list', 'URL cruda', '/dashboard');
269
- });
270
-
271
- function esquemaConSelect(target: NavigationTarget): ResourceSchema {
272
- return esquemaCon({
273
- list: { type: 'list', select: { on: 'open', mode: 'route', target } },
274
- });
275
- }
276
-
277
- it('valida que el destino nombre un recurso y una uiView declarados', () => {
278
- expectaError(
279
- () => validateComposition(esquemaConSelect({ resource: 'fantasma', view: 'detail' })),
280
- 'orders.list',
281
- 'fantasma',
282
- );
283
- expectaError(
284
- () => validateComposition(esquemaConSelect({ resource: 'orders', view: 'no-existe' })),
285
- 'orders.list',
286
- 'no-existe',
287
- );
288
- });
289
-
290
- it('valida los params declarados contra la ruta del destino', () => {
291
- // Param que la ruta del destino no tiene.
292
- expectaError(
293
- () =>
294
- validateComposition(
295
- esquemaConSelect({ resource: 'orders', view: 'detail', params: ['nope'] }),
296
- ),
297
- 'nope',
298
- );
299
- // Falta declarar el param que la ruta `orders/:key` exige.
300
- expectaError(
301
- () => validateComposition(esquemaConSelect({ resource: 'orders', view: 'detail' })),
302
- 'key',
303
- );
304
- });
305
-
306
- it('acepta un destino declarado con resource + view + params válidos', () => {
307
- const schema = esquemaConSelect({
308
- resource: 'orders',
309
- view: 'detail',
310
- params: ['key'],
311
- });
312
-
313
- expect(() => validateComposition(schema)).not.toThrow();
314
- });
315
-
316
- // ── Fuente de filas incompatible (R9.9.2 · "incompatible sources") ─────────
317
-
318
- function esquemaConSource(source: DataSource): ResourceSchema {
319
- return esquemaCon({
320
- panel: tabs([
321
- {
322
- id: 'cal',
323
- label: 'Calendario',
324
- type: 'calendar',
325
- config: { startField: 'pickup_date', titleField: 'customer_name', source },
326
- },
327
- ]),
328
- });
329
- }
330
-
331
- it('falla con una source sobre un recurso no declarado', () => {
332
- expectaError(
333
- () => validateComposition(esquemaConSource({ resource: 'fantasma' })),
334
- 'orders.panel',
335
- 'cal',
336
- 'fantasma',
337
- );
338
- });
339
-
340
- it('falla con una source sobre una vista no declarada del recurso', () => {
341
- expectaError(
342
- () => validateComposition(esquemaConSource({ resource: 'orders', view: 'vista-fantasma' })),
343
- 'vista-fantasma',
344
- );
345
- });
346
-
347
- it('acepta una source con recurso declarado y sin vista', () => {
348
- expect(() => validateComposition(esquemaConSource({ resource: 'orders' }))).not.toThrow();
349
- });
350
-
351
- it('un binding mode none/inline no exige target', () => {
352
- const schema = esquemaCon({
353
- list: { type: 'list', select: { on: 'open', mode: 'inline' } satisfies SelectionBinding },
354
- });
355
-
356
- expect(() => validateComposition(schema)).not.toThrow();
357
- });
358
- });
@@ -1,270 +0,0 @@
1
- import { getSchema } from './schema-catalog';
2
- import type {
3
- DataSource,
4
- NavigationTarget,
5
- ResourceSchema,
6
- SelectionBinding,
7
- UiViewDescriptor,
8
- ViewChildNode,
9
- } from '../models/schema.model';
10
- import { get } from './render-registry';
11
-
12
- /**
13
- * Validador de composición de vistas (R9.9.2 · D2/D3).
14
- *
15
- * Una composición (un `uiView` contenedor con `config.children`, p. ej.
16
- * `tabs`) se valida ANTES del render con esta única función pura y síncrona:
17
- *
18
- * - identidad de hijos (`id` presente y único entre hermanos);
19
- * - tipos resueltos con `get('view', type)` — **nunca** `resolve()`, cuyo
20
- * `fallback` silencioso dejaría un hijo inválido pintándose de todos modos;
21
- * - `ref` rotos y ciclos (directos o transitivos) que los `ref` permiten;
22
- * - profundidad y cantidad de nodos con topes configurables;
23
- * - destinos de navegación (`resource` + `view` + params) y fuentes de
24
- * filas — una URL cruda nunca es un destino válido;
25
- *
26
- * El llamante es D3: `resourceRoutes()` en `shell.routes.ts` (fail-loud al
27
- * arrancar) y el guardián de montaje del composer. Cualquier violación lanza
28
- * `SchemaCompositionError` con un mensaje legible que nombra recurso,
29
- * contenedor e hijo: nada se oculta ni se sustituye en silencio.
30
- *
31
- * El tipo de una `uiView` RAÍZ no se chequea acá: eso ya lo hace
32
- * `resourceRoutes()` con su error genérico de descriptor inexistente. Este
33
- * validador cubre lo que ese recorrido no ve: la estructura de los hijos.
34
- */
35
-
36
- /** Profundidad máxima de anidamiento de contenedores (hijos raíz = 1). */
37
- export const MAX_DEPTH = 3;
38
-
39
- /** Cantidad máxima de nodos-hijo declarados en la composición de un schema. */
40
- export const MAX_NODES = 50;
41
-
42
- /** Violación del contrato de composición, detectada antes del render. */
43
- export class SchemaCompositionError extends Error {
44
- constructor(message: string) {
45
- super(message);
46
- this.name = 'SchemaCompositionError';
47
- }
48
- }
49
-
50
- /** Estado del recorrido: cuenta de nodos y camino actual (detección de ciclos). */
51
- interface Estado {
52
- readonly esquema: ResourceSchema;
53
- nodos: number;
54
- readonly contados: Set<ViewChildNode>;
55
- readonly camino: Set<string>;
56
- }
57
-
58
- /** `config` de la vista cuando la hay (`tabs` es el único contenedor hoy). */
59
- function configDe(vista: UiViewDescriptor | ViewChildNode): unknown {
60
- return 'config' in vista ? vista.config : undefined;
61
- }
62
-
63
- /** Hijos declarados si la vista es un contenedor; `undefined` si no lo es. */
64
- function hijosDe(vista: UiViewDescriptor | ViewChildNode): ViewChildNode[] | undefined {
65
- const hijos = (configDe(vista) as { children?: unknown } | undefined)?.children;
66
- return Array.isArray(hijos) ? (hijos as ViewChildNode[]) : undefined;
67
- }
68
-
69
- /**
70
- * Valida TODA la composición de un schema. Lanza `SchemaCompositionError`
71
- * en la primera violación; no lanzar significa «apto para renderizar».
72
- */
73
- export function validateComposition(schema: ResourceSchema): void {
74
- const estado: Estado = { esquema: schema, nodos: 0, contados: new Set(), camino: new Set() };
75
- for (const [nombre, vista] of Object.entries(schema.uiViews ?? {})) {
76
- estado.camino.add(nombre);
77
- validarContenido(nombre, vista, 1, estado);
78
- estado.camino.delete(nombre);
79
- }
80
- }
81
-
82
- /**
83
- * Valida una `uiView` ya resuelta (raíz o referenciada por `ref`): sus
84
- * bindings, su fuente de filas y —si es contenedor— sus hijos.
85
- * `profundidadHijos` es la profundidad que tendrán sus hijos directos.
86
- */
87
- function validarContenido(
88
- nombre: string,
89
- vista: UiViewDescriptor,
90
- profundidadHijos: number,
91
- estado: Estado,
92
- ): void {
93
- const donde = `${estado.esquema.id}.${nombre}`;
94
- validarSelect(donde, (vista as { select?: SelectionBinding }).select);
95
- validarSource(donde, (configDe(vista) as { source?: DataSource } | undefined)?.source);
96
- const hijos = hijosDe(vista);
97
- if (!hijos) return;
98
- validarHijos(nombre, hijos, profundidadHijos, estado);
99
- }
100
-
101
- /** Valida la lista de hijos de un contenedor: identidad única entre hermanos. */
102
- function validarHijos(
103
- contenedor: string,
104
- hijos: readonly ViewChildNode[],
105
- profundidad: number,
106
- estado: Estado,
107
- ): void {
108
- const ids = new Set<string>();
109
- for (const hijo of hijos) {
110
- const id = (hijo as { id?: unknown }).id;
111
- if (typeof id !== 'string' || id === '') {
112
- throw new SchemaCompositionError(`${estado.esquema.id}.${contenedor}: hijo sin id`);
113
- }
114
- if (ids.has(id)) {
115
- throw new SchemaCompositionError(`${estado.esquema.id}.${contenedor}: id duplicado '${id}'`);
116
- }
117
- ids.add(id);
118
- validarHijo(hijo, contenedor, id, profundidad, estado);
119
- }
120
- }
121
-
122
- /** Valida un hijo: topes de nodos/profundidad, ciclo, ref y tipo inline. */
123
- function validarHijo(
124
- hijo: ViewChildNode,
125
- contenedor: string,
126
- id: string,
127
- profundidad: number,
128
- estado: Estado,
129
- ): void {
130
- const donde = `${estado.esquema.id}.${contenedor} → child '${id}'`;
131
-
132
- if (!estado.contados.has(hijo)) {
133
- estado.contados.add(hijo);
134
- estado.nodos += 1;
135
- if (estado.nodos > MAX_NODES) {
136
- throw new SchemaCompositionError(
137
- `${estado.esquema.id}: la composición supera el límite de ${MAX_NODES} nodos (observados ${estado.nodos})`,
138
- );
139
- }
140
- }
141
- if (profundidad > MAX_DEPTH) {
142
- throw new SchemaCompositionError(
143
- `${donde}: profundidad ${profundidad} supera el máximo ${MAX_DEPTH}`,
144
- );
145
- }
146
-
147
- if ('ref' in hijo) {
148
- validarRef(donde, (hijo as { ref?: unknown }).ref as string, profundidad, estado);
149
- return;
150
- }
151
-
152
- const tipo = (hijo as { type?: unknown }).type as string;
153
- if (!get('view', tipo)) {
154
- throw new SchemaCompositionError(`${donde}: tipo desconocido '${tipo}'`);
155
- }
156
- validarSelect(donde, (hijo as { select?: SelectionBinding }).select);
157
- validarSource(donde, (configDe(hijo) as { source?: DataSource } | undefined)?.source);
158
- /**
159
- * Contenedor inline: sus propios hijos también se validan. Sin esto, una
160
- * composición anidada dentro de otro `tabs` inline se renderiza sin haber
161
- * pasado por topes de profundidad/nodos ni por la detección de ciclos de
162
- * sus `ref` (D2: invalid branch NUNCA llega al render). La profundidad
163
- * CONTINUA desde este hijo — no se reinicia — y el camino de ciclo se
164
- * mantiene intacto, porque un `ref` sólo puede volver a nombres que ya
165
- * están en él.
166
- */
167
- const internos = hijosDe(hijo);
168
- if (internos !== undefined) {
169
- validarHijos(id, internos, profundidad + 1, estado);
170
- }
171
- }
172
-
173
- /**
174
- * Resuelve un hijo `ref` contra `schema.uiViews`: el destino debe existir y
175
- * no formar parte del camino actual (ciclo directo o transitivo). El
176
- * contenido del destino se valida en profundidad CONTINUANDO la del ref —
177
- * un `ref` anida de verdad (R9.9.2).
178
- */
179
- function validarRef(donde: string, target: string, profundidad: number, estado: Estado): void {
180
- if (estado.camino.has(target)) {
181
- throw new SchemaCompositionError(
182
- `${donde}: ciclo detectado — '${target}' ya está en el camino`,
183
- );
184
- }
185
- const vista = estado.esquema.uiViews?.[target];
186
- if (!vista) {
187
- throw new SchemaCompositionError(
188
- `${donde}: ref '${target}' no existe en ${estado.esquema.id}.uiViews`,
189
- );
190
- }
191
- estado.camino.add(target);
192
- validarContenido(target, vista, profundidad + 1, estado);
193
- estado.camino.delete(target);
194
- }
195
-
196
- /**
197
- * Valida el binding de selección de una `uiView` o de un hijo (R9.9.4).
198
- * Sólo `mode: 'route'` exige destino declarado; `none`/`inline` son locales.
199
- */
200
- function validarSelect(donde: string, select: SelectionBinding | undefined): void {
201
- if (select === undefined || select.mode !== 'route') return;
202
- const target = (select as { target?: unknown }).target;
203
- if (target === undefined || target === null) {
204
- throw new SchemaCompositionError(`${donde}: select mode 'route' sin target`);
205
- }
206
- if (typeof target === 'string') {
207
- throw new SchemaCompositionError(
208
- `${donde}: destino con URL cruda '${target}' — declará resource + view`,
209
- );
210
- }
211
- validarTarget(donde, target as NavigationTarget);
212
- }
213
-
214
- /**
215
- * El destino sólo puede ser un recurso + `uiView` declarados, con los params
216
- * declarados EXACTAMENTE igual que los params de la ruta del destino: ni
217
- * params ajenos a la ruta ni params de la ruta sin declarar.
218
- */
219
- function validarTarget(donde: string, target: NavigationTarget): void {
220
- const { resource, view, params } = target;
221
- if (typeof resource !== 'string' || resource === '' || typeof view !== 'string' || view === '') {
222
- throw new SchemaCompositionError(`${donde}: destino sin resource + view`);
223
- }
224
- const destino = getSchema(resource);
225
- if (!destino) {
226
- throw new SchemaCompositionError(`${donde}: destino '${resource}' no existe`);
227
- }
228
- const vista = destino.uiViews?.[view];
229
- if (!vista) {
230
- throw new SchemaCompositionError(
231
- `${donde}: destino ${resource}.${view} no tiene uiView declarada`,
232
- );
233
- }
234
- const paramsRuta = (vista.path ?? '')
235
- .split('/')
236
- .filter((segmento) => segmento.startsWith(':'))
237
- .map((segmento) => segmento.slice(1));
238
- const declarados = params ?? [];
239
- for (const param of declarados) {
240
- if (!paramsRuta.includes(param)) {
241
- throw new SchemaCompositionError(
242
- `${donde}: param '${param}' no existe en la ruta ${resource}.${view}`,
243
- );
244
- }
245
- }
246
- for (const param of paramsRuta) {
247
- if (!declarados.includes(param)) {
248
- throw new SchemaCompositionError(
249
- `${donde}: falta declarar el param '${param}' de la ruta ${resource}.${view}`,
250
- );
251
- }
252
- }
253
- }
254
-
255
- /** Valida la fuente de filas (`config.source`) declarada por una vista (R9.8). */
256
- function validarSource(donde: string, source: DataSource | undefined): void {
257
- if (source === undefined) return;
258
- if (typeof source.resource !== 'string' || source.resource === '') {
259
- throw new SchemaCompositionError(`${donde}: source sin resource`);
260
- }
261
- const origen = getSchema(source.resource);
262
- if (!origen) {
263
- throw new SchemaCompositionError(`${donde}: source '${source.resource}' no existe`);
264
- }
265
- if (source.view !== undefined && origen.views?.[source.view] === undefined) {
266
- throw new SchemaCompositionError(
267
- `${donde}: la vista '${source.view}' no existe en ${source.resource}.views`,
268
- );
269
- }
270
- }