weaver-e10-builder 1.5.10 → 1.5.12

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 (352) hide show
  1. package/README.md +212 -189
  2. package/assets/image-style-observation.schema.json +1355 -0
  3. package/assets/layout-spec.schema.json +52 -0
  4. package/dist/commands/app.d.ts.map +1 -1
  5. package/dist/commands/app.js +159 -8
  6. package/dist/commands/app.js.map +1 -1
  7. package/dist/commands/designer-setters.d.ts.map +1 -1
  8. package/dist/commands/designer-setters.js +26 -4
  9. package/dist/commands/designer-setters.js.map +1 -1
  10. package/dist/commands/form-association-manage.d.ts.map +1 -1
  11. package/dist/commands/form-association-manage.js +3 -0
  12. package/dist/commands/form-association-manage.js.map +1 -1
  13. package/dist/commands/form-button-actions-cmd.d.ts +3 -0
  14. package/dist/commands/form-button-actions-cmd.d.ts.map +1 -0
  15. package/dist/commands/form-button-actions-cmd.js +309 -0
  16. package/dist/commands/form-button-actions-cmd.js.map +1 -0
  17. package/dist/commands/form-button-permission-cmd.d.ts +3 -0
  18. package/dist/commands/form-button-permission-cmd.d.ts.map +1 -0
  19. package/dist/commands/form-button-permission-cmd.js +132 -0
  20. package/dist/commands/form-button-permission-cmd.js.map +1 -0
  21. package/dist/commands/form-button-props-cmd.d.ts +3 -0
  22. package/dist/commands/form-button-props-cmd.d.ts.map +1 -0
  23. package/dist/commands/form-button-props-cmd.js +236 -0
  24. package/dist/commands/form-button-props-cmd.js.map +1 -0
  25. package/dist/commands/form-button.d.ts.map +1 -1
  26. package/dist/commands/form-button.js +82 -55
  27. package/dist/commands/form-button.js.map +1 -1
  28. package/dist/commands/form-field-linkage.d.ts +55 -0
  29. package/dist/commands/form-field-linkage.d.ts.map +1 -1
  30. package/dist/commands/form-field-linkage.js +1026 -12
  31. package/dist/commands/form-field-linkage.js.map +1 -1
  32. package/dist/commands/form-formula-linkage.d.ts +36 -0
  33. package/dist/commands/form-formula-linkage.d.ts.map +1 -1
  34. package/dist/commands/form-formula-linkage.js +256 -65
  35. package/dist/commands/form-formula-linkage.js.map +1 -1
  36. package/dist/commands/form-layout-restore.d.ts +3 -0
  37. package/dist/commands/form-layout-restore.d.ts.map +1 -0
  38. package/dist/commands/form-layout-restore.js +217 -0
  39. package/dist/commands/form-layout-restore.js.map +1 -0
  40. package/dist/commands/form-layout.d.ts.map +1 -1
  41. package/dist/commands/form-layout.js +11 -1
  42. package/dist/commands/form-layout.js.map +1 -1
  43. package/dist/commands/form-list-permission.d.ts.map +1 -1
  44. package/dist/commands/form-list-permission.js +29 -3
  45. package/dist/commands/form-list-permission.js.map +1 -1
  46. package/dist/commands/form-list-search-group.d.ts.map +1 -1
  47. package/dist/commands/form-list-search-group.js +66 -3
  48. package/dist/commands/form-list-search-group.js.map +1 -1
  49. package/dist/commands/form-list-utils.d.ts +14 -0
  50. package/dist/commands/form-list-utils.d.ts.map +1 -1
  51. package/dist/commands/form-list-utils.js +65 -4
  52. package/dist/commands/form-list-utils.js.map +1 -1
  53. package/dist/commands/form-message.d.ts.map +1 -1
  54. package/dist/commands/form-message.js +16 -4
  55. package/dist/commands/form-message.js.map +1 -1
  56. package/dist/commands/form-obj-meta.d.ts +12 -0
  57. package/dist/commands/form-obj-meta.d.ts.map +1 -0
  58. package/dist/commands/form-obj-meta.js +116 -0
  59. package/dist/commands/form-obj-meta.js.map +1 -0
  60. package/dist/commands/form-permission.d.ts +20 -0
  61. package/dist/commands/form-permission.d.ts.map +1 -1
  62. package/dist/commands/form-permission.js +69 -11
  63. package/dist/commands/form-permission.js.map +1 -1
  64. package/dist/commands/form-validate.d.ts.map +1 -1
  65. package/dist/commands/form-validate.js +167 -35
  66. package/dist/commands/form-validate.js.map +1 -1
  67. package/dist/commands/form.d.ts.map +1 -1
  68. package/dist/commands/form.js +26 -2
  69. package/dist/commands/form.js.map +1 -1
  70. package/dist/commands/menu-permission.d.ts.map +1 -1
  71. package/dist/commands/menu-permission.js +6 -7
  72. package/dist/commands/menu-permission.js.map +1 -1
  73. package/dist/commands/menu.d.ts.map +1 -1
  74. package/dist/commands/menu.js +68 -43
  75. package/dist/commands/menu.js.map +1 -1
  76. package/dist/commands/wf-form.d.ts.map +1 -1
  77. package/dist/commands/wf-form.js +269 -47
  78. package/dist/commands/wf-form.js.map +1 -1
  79. package/dist/commands/workflow-function-management.d.ts +5 -0
  80. package/dist/commands/workflow-function-management.d.ts.map +1 -0
  81. package/dist/commands/workflow-function-management.js +91 -0
  82. package/dist/commands/workflow-function-management.js.map +1 -0
  83. package/dist/commands/workflow-node-assign-flow.d.ts.map +1 -1
  84. package/dist/commands/workflow-node-assign-flow.js +1 -0
  85. package/dist/commands/workflow-node-assign-flow.js.map +1 -1
  86. package/dist/commands/workflow-node-sign.d.ts +0 -12
  87. package/dist/commands/workflow-node-sign.d.ts.map +1 -1
  88. package/dist/commands/workflow-node-sign.js +31 -102
  89. package/dist/commands/workflow-node-sign.js.map +1 -1
  90. package/dist/commands/workflow-opinion-settings.d.ts +5 -0
  91. package/dist/commands/workflow-opinion-settings.d.ts.map +1 -0
  92. package/dist/commands/workflow-opinion-settings.js +51 -0
  93. package/dist/commands/workflow-opinion-settings.js.map +1 -0
  94. package/dist/commands/workflow-subprocess.d.ts.map +1 -1
  95. package/dist/commands/workflow-subprocess.js +370 -20
  96. package/dist/commands/workflow-subprocess.js.map +1 -1
  97. package/dist/commands/workflow.d.ts.map +1 -1
  98. package/dist/commands/workflow.js +35 -61
  99. package/dist/commands/workflow.js.map +1 -1
  100. package/dist/core/client.d.ts +2 -1
  101. package/dist/core/client.d.ts.map +1 -1
  102. package/dist/core/client.js +4 -2
  103. package/dist/core/client.js.map +1 -1
  104. package/dist/index.js +6 -0
  105. package/dist/index.js.map +1 -1
  106. package/dist/services/actionflow/calendar_mapper.d.ts.map +1 -1
  107. package/dist/services/actionflow/calendar_mapper.js +64 -18
  108. package/dist/services/actionflow/calendar_mapper.js.map +1 -1
  109. package/dist/services/actionflow/component_registry.d.ts.map +1 -1
  110. package/dist/services/actionflow/component_registry.js +6 -0
  111. package/dist/services/actionflow/component_registry.js.map +1 -1
  112. package/dist/services/actionflow/components/document_actions.d.ts.map +1 -1
  113. package/dist/services/actionflow/components/document_actions.js +113 -4
  114. package/dist/services/actionflow/components/document_actions.js.map +1 -1
  115. package/dist/services/actionflow/components/eb_get_data_by_id.d.ts.map +1 -1
  116. package/dist/services/actionflow/components/eb_get_data_by_id.js +18 -1
  117. package/dist/services/actionflow/components/eb_get_data_by_id.js.map +1 -1
  118. package/dist/services/actionflow/components/index.d.ts.map +1 -1
  119. package/dist/services/actionflow/components/index.js +2 -1
  120. package/dist/services/actionflow/components/index.js.map +1 -1
  121. package/dist/services/actionflow/components/meeting_create.d.ts.map +1 -1
  122. package/dist/services/actionflow/components/meeting_create.js +5 -1
  123. package/dist/services/actionflow/components/meeting_create.js.map +1 -1
  124. package/dist/services/actionflow/components/schedule_create.d.ts.map +1 -1
  125. package/dist/services/actionflow/components/schedule_create.js +22 -6
  126. package/dist/services/actionflow/components/schedule_create.js.map +1 -1
  127. package/dist/services/actionflow/components/workflow_actions.d.ts +1 -0
  128. package/dist/services/actionflow/components/workflow_actions.d.ts.map +1 -1
  129. package/dist/services/actionflow/components/workflow_actions.js +44 -7
  130. package/dist/services/actionflow/components/workflow_actions.js.map +1 -1
  131. package/dist/services/actionflow/document_source.d.ts +5 -0
  132. package/dist/services/actionflow/document_source.d.ts.map +1 -1
  133. package/dist/services/actionflow/document_source.js +16 -0
  134. package/dist/services/actionflow/document_source.js.map +1 -1
  135. package/dist/services/actionflow/formula_service.d.ts +7 -0
  136. package/dist/services/actionflow/formula_service.d.ts.map +1 -1
  137. package/dist/services/actionflow/formula_service.js +44 -8
  138. package/dist/services/actionflow/formula_service.js.map +1 -1
  139. package/dist/services/actionflow/preflight_service.d.ts +5 -0
  140. package/dist/services/actionflow/preflight_service.d.ts.map +1 -1
  141. package/dist/services/actionflow/preflight_service.js +127 -2
  142. package/dist/services/actionflow/preflight_service.js.map +1 -1
  143. package/dist/services/actionflow/save_workflow_draft.d.ts +7 -0
  144. package/dist/services/actionflow/save_workflow_draft.d.ts.map +1 -1
  145. package/dist/services/actionflow/save_workflow_draft.js +1 -1
  146. package/dist/services/actionflow/save_workflow_draft.js.map +1 -1
  147. package/dist/services/actionflow/workflow_compiler.d.ts.map +1 -1
  148. package/dist/services/actionflow/workflow_compiler.js +26 -0
  149. package/dist/services/actionflow/workflow_compiler.js.map +1 -1
  150. package/dist/services/app-publish.d.ts +25 -0
  151. package/dist/services/app-publish.d.ts.map +1 -1
  152. package/dist/services/app-publish.js +38 -0
  153. package/dist/services/app-publish.js.map +1 -1
  154. package/dist/services/app-range.d.ts +66 -0
  155. package/dist/services/app-range.d.ts.map +1 -0
  156. package/dist/services/app-range.js +137 -0
  157. package/dist/services/app-range.js.map +1 -0
  158. package/dist/services/form-association.d.ts +13 -0
  159. package/dist/services/form-association.d.ts.map +1 -1
  160. package/dist/services/form-association.js +42 -0
  161. package/dist/services/form-association.js.map +1 -1
  162. package/dist/services/form-button-action.d.ts +82 -0
  163. package/dist/services/form-button-action.d.ts.map +1 -1
  164. package/dist/services/form-button-action.js +194 -2
  165. package/dist/services/form-button-action.js.map +1 -1
  166. package/dist/services/form-button-condition.d.ts +45 -0
  167. package/dist/services/form-button-condition.d.ts.map +1 -0
  168. package/dist/services/form-button-condition.js +106 -0
  169. package/dist/services/form-button-condition.js.map +1 -0
  170. package/dist/services/form-button-context.d.ts +41 -0
  171. package/dist/services/form-button-context.d.ts.map +1 -0
  172. package/dist/services/form-button-context.js +54 -0
  173. package/dist/services/form-button-context.js.map +1 -0
  174. package/dist/services/form-button-logicflow.d.ts +30 -0
  175. package/dist/services/form-button-logicflow.d.ts.map +1 -0
  176. package/dist/services/form-button-logicflow.js +59 -0
  177. package/dist/services/form-button-logicflow.js.map +1 -0
  178. package/dist/services/form-button-org.d.ts +30 -0
  179. package/dist/services/form-button-org.d.ts.map +1 -0
  180. package/dist/services/form-button-org.js +80 -0
  181. package/dist/services/form-button-org.js.map +1 -0
  182. package/dist/services/form-button-permission.d.ts +65 -0
  183. package/dist/services/form-button-permission.d.ts.map +1 -0
  184. package/dist/services/form-button-permission.js +113 -0
  185. package/dist/services/form-button-permission.js.map +1 -0
  186. package/dist/services/form-button-position.d.ts +4 -18
  187. package/dist/services/form-button-position.d.ts.map +1 -1
  188. package/dist/services/form-button-position.js +4 -36
  189. package/dist/services/form-button-position.js.map +1 -1
  190. package/dist/services/form-button-props.d.ts +55 -0
  191. package/dist/services/form-button-props.d.ts.map +1 -0
  192. package/dist/services/form-button-props.js +90 -0
  193. package/dist/services/form-button-props.js.map +1 -0
  194. package/dist/services/form-button-save.d.ts +49 -0
  195. package/dist/services/form-button-save.d.ts.map +1 -0
  196. package/dist/services/form-button-save.js +54 -0
  197. package/dist/services/form-button-save.js.map +1 -0
  198. package/dist/services/form-formula-linkage.d.ts +120 -20
  199. package/dist/services/form-formula-linkage.d.ts.map +1 -1
  200. package/dist/services/form-formula-linkage.js +253 -39
  201. package/dist/services/form-formula-linkage.js.map +1 -1
  202. package/dist/services/form-layout-io.d.ts +18 -0
  203. package/dist/services/form-layout-io.d.ts.map +1 -0
  204. package/dist/services/form-layout-io.js +89 -0
  205. package/dist/services/form-layout-io.js.map +1 -0
  206. package/dist/services/form-layout-source/artifact.d.ts +8 -0
  207. package/dist/services/form-layout-source/artifact.d.ts.map +1 -0
  208. package/dist/services/form-layout-source/artifact.js +52 -0
  209. package/dist/services/form-layout-source/artifact.js.map +1 -0
  210. package/dist/services/form-layout-source/binding.d.ts +10 -0
  211. package/dist/services/form-layout-source/binding.d.ts.map +1 -0
  212. package/dist/services/form-layout-source/binding.js +43 -0
  213. package/dist/services/form-layout-source/binding.js.map +1 -0
  214. package/dist/services/form-layout-source/compile.d.ts +7 -0
  215. package/dist/services/form-layout-source/compile.d.ts.map +1 -0
  216. package/dist/services/form-layout-source/compile.js +262 -0
  217. package/dist/services/form-layout-source/compile.js.map +1 -0
  218. package/dist/services/form-layout-source/creation.d.ts +18 -0
  219. package/dist/services/form-layout-source/creation.d.ts.map +1 -0
  220. package/dist/services/form-layout-source/creation.js +42 -0
  221. package/dist/services/form-layout-source/creation.js.map +1 -0
  222. package/dist/services/form-layout-source/excel-extractor.d.ts +7 -0
  223. package/dist/services/form-layout-source/excel-extractor.d.ts.map +1 -0
  224. package/dist/services/form-layout-source/excel-extractor.js +342 -0
  225. package/dist/services/form-layout-source/excel-extractor.js.map +1 -0
  226. package/dist/services/form-layout-source/image-border.d.ts +9 -0
  227. package/dist/services/form-layout-source/image-border.d.ts.map +1 -0
  228. package/dist/services/form-layout-source/image-border.js +128 -0
  229. package/dist/services/form-layout-source/image-border.js.map +1 -0
  230. package/dist/services/form-layout-source/image-observation.d.ts +14 -0
  231. package/dist/services/form-layout-source/image-observation.d.ts.map +1 -0
  232. package/dist/services/form-layout-source/image-observation.js +90 -0
  233. package/dist/services/form-layout-source/image-observation.js.map +1 -0
  234. package/dist/services/form-layout-source/image-review.d.ts +32 -0
  235. package/dist/services/form-layout-source/image-review.d.ts.map +1 -0
  236. package/dist/services/form-layout-source/image-review.js +266 -0
  237. package/dist/services/form-layout-source/image-review.js.map +1 -0
  238. package/dist/services/form-layout-source/image-style.d.ts +16 -0
  239. package/dist/services/form-layout-source/image-style.d.ts.map +1 -0
  240. package/dist/services/form-layout-source/image-style.js +539 -0
  241. package/dist/services/form-layout-source/image-style.js.map +1 -0
  242. package/dist/services/form-layout-source/json.d.ts +3 -0
  243. package/dist/services/form-layout-source/json.d.ts.map +1 -0
  244. package/dist/services/form-layout-source/json.js +33 -0
  245. package/dist/services/form-layout-source/json.js.map +1 -0
  246. package/dist/services/form-layout-source/presentation.d.ts +23 -0
  247. package/dist/services/form-layout-source/presentation.d.ts.map +1 -0
  248. package/dist/services/form-layout-source/presentation.js +174 -0
  249. package/dist/services/form-layout-source/presentation.js.map +1 -0
  250. package/dist/services/form-layout-source/preview.d.ts +4 -0
  251. package/dist/services/form-layout-source/preview.d.ts.map +1 -0
  252. package/dist/services/form-layout-source/preview.js +49 -0
  253. package/dist/services/form-layout-source/preview.js.map +1 -0
  254. package/dist/services/form-layout-source/schema.d.ts +20 -0
  255. package/dist/services/form-layout-source/schema.d.ts.map +1 -0
  256. package/dist/services/form-layout-source/schema.js +149 -0
  257. package/dist/services/form-layout-source/schema.js.map +1 -0
  258. package/dist/services/form-layout-source/source-grid.d.ts +8 -0
  259. package/dist/services/form-layout-source/source-grid.d.ts.map +1 -0
  260. package/dist/services/form-layout-source/source-grid.js +61 -0
  261. package/dist/services/form-layout-source/source-grid.js.map +1 -0
  262. package/dist/services/form-layout-source/types.d.ts +242 -0
  263. package/dist/services/form-layout-source/types.d.ts.map +1 -0
  264. package/dist/services/form-layout-source/types.js +2 -0
  265. package/dist/services/form-layout-source/types.js.map +1 -0
  266. package/dist/services/form-layout-source/verify.d.ts +14 -0
  267. package/dist/services/form-layout-source/verify.d.ts.map +1 -0
  268. package/dist/services/form-layout-source/verify.js +226 -0
  269. package/dist/services/form-layout-source/verify.js.map +1 -0
  270. package/dist/services/form-list-search-group.d.ts +17 -2
  271. package/dist/services/form-list-search-group.d.ts.map +1 -1
  272. package/dist/services/form-list-search-group.js +29 -12
  273. package/dist/services/form-list-search-group.js.map +1 -1
  274. package/dist/services/form-list-search.d.ts.map +1 -1
  275. package/dist/services/form-list-search.js +4 -0
  276. package/dist/services/form-list-search.js.map +1 -1
  277. package/dist/services/form-list-stats.d.ts.map +1 -1
  278. package/dist/services/form-list-stats.js +9 -2
  279. package/dist/services/form-list-stats.js.map +1 -1
  280. package/dist/services/form-message.d.ts +26 -7
  281. package/dist/services/form-message.d.ts.map +1 -1
  282. package/dist/services/form-message.js +52 -5
  283. package/dist/services/form-message.js.map +1 -1
  284. package/dist/services/form-obj-meta.d.ts +72 -0
  285. package/dist/services/form-obj-meta.d.ts.map +1 -0
  286. package/dist/services/form-obj-meta.js +103 -0
  287. package/dist/services/form-obj-meta.js.map +1 -0
  288. package/dist/services/form-permission-archive.d.ts +9 -1
  289. package/dist/services/form-permission-archive.d.ts.map +1 -1
  290. package/dist/services/form-permission-archive.js +38 -22
  291. package/dist/services/form-permission-archive.js.map +1 -1
  292. package/dist/services/form-view-populate.d.ts.map +1 -1
  293. package/dist/services/form-view-populate.js +7 -0
  294. package/dist/services/form-view-populate.js.map +1 -1
  295. package/dist/services/icon-path.d.ts +70 -0
  296. package/dist/services/icon-path.d.ts.map +1 -0
  297. package/dist/services/icon-path.js +80 -0
  298. package/dist/services/icon-path.js.map +1 -0
  299. package/dist/services/matrix-condition.d.ts +161 -0
  300. package/dist/services/matrix-condition.d.ts.map +1 -0
  301. package/dist/services/matrix-condition.js +403 -0
  302. package/dist/services/matrix-condition.js.map +1 -0
  303. package/dist/services/menu-catalog.d.ts +33 -0
  304. package/dist/services/menu-catalog.d.ts.map +1 -1
  305. package/dist/services/menu-catalog.js +56 -0
  306. package/dist/services/menu-catalog.js.map +1 -1
  307. package/dist/services/permission-entity.d.ts +55 -0
  308. package/dist/services/permission-entity.d.ts.map +1 -0
  309. package/dist/services/permission-entity.js +79 -0
  310. package/dist/services/permission-entity.js.map +1 -0
  311. package/dist/services/validate-help.d.ts +25 -0
  312. package/dist/services/validate-help.d.ts.map +1 -0
  313. package/dist/services/validate-help.js +29 -0
  314. package/dist/services/validate-help.js.map +1 -0
  315. package/dist/services/workflow-assign-flow.d.ts.map +1 -1
  316. package/dist/services/workflow-assign-flow.js.map +1 -1
  317. package/dist/services/workflow-function-management.d.ts +123 -0
  318. package/dist/services/workflow-function-management.d.ts.map +1 -0
  319. package/dist/services/workflow-function-management.js +425 -0
  320. package/dist/services/workflow-function-management.js.map +1 -0
  321. package/dist/services/workflow-matrix-rule.d.ts +34 -0
  322. package/dist/services/workflow-matrix-rule.d.ts.map +1 -0
  323. package/dist/services/workflow-matrix-rule.js +94 -0
  324. package/dist/services/workflow-matrix-rule.js.map +1 -0
  325. package/dist/services/workflow-opinion-settings.d.ts +67 -0
  326. package/dist/services/workflow-opinion-settings.d.ts.map +1 -0
  327. package/dist/services/workflow-opinion-settings.js +328 -0
  328. package/dist/services/workflow-opinion-settings.js.map +1 -0
  329. package/package.json +3 -1
  330. package/skill-docs/SKILL.md +15 -6
  331. package/skill-docs/_catalog.md +4 -0
  332. package/skill-docs/actionflows/references/components/calendar/MeetingCreate.md +2 -0
  333. package/skill-docs/actionflows/references/components/document/DocumentSave.md +17 -17
  334. package/skill-docs/actionflows/references/components/workflow/ApproveCompletelyDelete.md +29 -0
  335. package/skill-docs/actionflows/references/components/workflow/ApproveDelete.md +2 -2
  336. package/skill-docs/assets/schemas/image-style-observation.schema.json +1355 -0
  337. package/skill-docs/references/common/guide-plan-template.md +3 -0
  338. package/skill-docs/references/common/ref-cli-commands.md +77 -26
  339. package/skill-docs/references/ebuilder-designer/guide-designer-components.md +9 -0
  340. package/skill-docs/references/form/guide-create-form.md +2 -0
  341. package/skill-docs/references/form/guide-field-linkage.md +140 -55
  342. package/skill-docs/references/form/guide-form-archive-permission.md +55 -2
  343. package/skill-docs/references/form/guide-form-association.md +13 -0
  344. package/skill-docs/references/form/guide-form-button.md +87 -0
  345. package/skill-docs/references/form/guide-form-layout-planning.md +6 -0
  346. package/skill-docs/references/form/guide-form-layout-source.md +366 -0
  347. package/skill-docs/references/form/guide-form-message.md +19 -2
  348. package/skill-docs/references/form/guide-form-view.md +24 -4
  349. package/skill-docs/references/form/guide-formula-linkage.md +86 -12
  350. package/skill-docs/references/workflow/guide-function-management.md +154 -0
  351. package/skill-docs/references/workflow/guide-opinion-settings.md +126 -0
  352. package/skill-docs/references/workflow/guide-workflow.md +22 -6
@@ -0,0 +1,539 @@
1
+ import { assert, clone, safeTree, stable } from './schema.js';
2
+ import { extent } from './source-grid.js';
3
+ const KEYS = ['color', 'backgroundColor', 'fontFamily', 'fontSize', 'fontUnit', 'fontWeight', 'fontStyle', 'textAlign', 'verticalAlign', 'wordWrap', 'underline', 'height', 'width', 'border', 'borderTop', 'borderBottom', 'borderLeft', 'borderRight', 'align', 'bold'];
4
+ const objectKeys = (v, keys, label) => assert(v && typeof v === 'object' && !Array.isArray(v) && Object.keys(v).every(k => keys.includes(k)), `${label} 包含未支持属性`);
5
+ function nativeFont(value) {
6
+ if (!value)
7
+ return undefined;
8
+ const match = /^(.*?)\s*(\d+(?:\.\d+)?)(px|pt)\s+(.+)$/.exec(value);
9
+ assert(match, '图片 font 需要字号单位和字体家族,例如 bold 18pt SimSun');
10
+ const tokens = match[1].trim().split(/\s+/).filter(Boolean);
11
+ assert(tokens.every(t => ['italic', 'normal', 'bold'].includes(t) || /^[1-9]00$/.test(t)), '图片 font 前缀不支持');
12
+ const weight = tokens.find(t => t === 'bold' || /^[1-9]00$/.test(t));
13
+ return normalizeObservedStyle({ fontFamily: match[4], fontSize: Number(match[2]), fontUnit: match[3], fontWeight: weight === 'bold' ? 'bold' : weight ? Number(weight) : 400, fontStyle: tokens.includes('italic') ? 'italic' : 'normal' });
14
+ }
15
+ export function imageColor(value) {
16
+ const named = { red: '#FF0000', white: '#FFFFFF', black: '#000000', blue: '#0000FF', gray: '#808080', grey: '#808080', green: '#008000' };
17
+ assert(typeof value === 'string', '图片颜色必须是字符串');
18
+ const v = value.trim().toLowerCase();
19
+ if (named[v])
20
+ return named[v];
21
+ if (/^#[0-9a-f]{3}$/.test(v))
22
+ return '#' + v.slice(1).split('').map(c => c + c).join('').toUpperCase();
23
+ if (/^#[0-9a-f]{6}$/.test(v))
24
+ return v.toUpperCase();
25
+ const rgb = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/.exec(v);
26
+ assert(rgb && rgb.slice(1).every(n => Number(n) <= 255), `图片颜色无法规范化 ${value}`);
27
+ return '#' + rgb.slice(1).map(n => Number(n).toString(16).padStart(2, '0')).join('').toUpperCase();
28
+ }
29
+ export function normalizeObservedStyle(input) {
30
+ safeTree(input);
31
+ objectKeys(input, KEYS, '图片样式');
32
+ const s = clone(input);
33
+ if (s.align !== undefined) {
34
+ assert(s.textAlign === undefined || s.textAlign === s.align, 'align 与 textAlign 冲突');
35
+ s.textAlign = s.align;
36
+ delete s.align;
37
+ }
38
+ if (s.bold !== undefined) {
39
+ assert(typeof s.bold === 'boolean', 'bold 必须是布尔值');
40
+ const weight = s.bold ? 700 : 400;
41
+ assert(s.fontWeight === undefined || s.fontWeight === weight || s.fontWeight === (s.bold ? 'bold' : 'normal'), 'bold 与 fontWeight 冲突');
42
+ s.fontWeight = weight;
43
+ delete s.bold;
44
+ }
45
+ for (const key of ['color', 'backgroundColor'])
46
+ if (s[key] !== undefined)
47
+ s[key] = imageColor(s[key]);
48
+ if (s.fontFamily !== undefined)
49
+ assert(typeof s.fontFamily === 'string' && s.fontFamily.length > 0 && s.fontFamily.length <= 100 && !/[;{}<>\r\n()]|url|expression/i.test(s.fontFamily), '字体名称无效');
50
+ if (s.fontSize !== undefined)
51
+ assert(Number.isFinite(s.fontSize) && s.fontSize >= 1 && s.fontSize <= (s.fontUnit === 'pt' ? 150 : 200), '字号无效');
52
+ assert(s.fontUnit === undefined || ['px', 'pt'].includes(s.fontUnit) && s.fontSize !== undefined, 'fontUnit 需要字号及 px/pt 单位');
53
+ if (s.fontWeight !== undefined)
54
+ assert(['normal', 'bold'].includes(s.fontWeight) || Number.isInteger(s.fontWeight) && s.fontWeight >= 100 && s.fontWeight <= 900 && s.fontWeight % 100 === 0, '字体粗细无效');
55
+ for (const [key, allowed] of [['fontStyle', ['normal', 'italic']], ['textAlign', ['left', 'center', 'right']], ['verticalAlign', ['top', 'middle', 'bottom']]])
56
+ assert(s[key] === undefined || allowed.includes(s[key]), `${key} 无效`);
57
+ for (const key of ['wordWrap', 'underline'])
58
+ assert(s[key] === undefined || typeof s[key] === 'boolean', `${key} 必须是布尔值`);
59
+ for (const key of ['height', 'width'])
60
+ if (s[key] !== undefined)
61
+ assert(Number.isFinite(s[key]) && s[key] > 0 && s[key] <= 2000, `${key} 无效`);
62
+ for (const key of ['border', 'borderTop', 'borderBottom', 'borderLeft', 'borderRight'])
63
+ if (s[key] !== undefined) {
64
+ const b = s[key];
65
+ objectKeys(b, ['color', 'width', 'line'], '图片边框');
66
+ b.color = imageColor(b.color);
67
+ assert([1, 2, 3].includes(b.width) && ['solid', 'dashed', 'dotted', 'double'].includes(b.line), '边框宽度或线型无效');
68
+ assert(b.line === 'solid' || b.width <= 2, '非实线边框最多支持宽度 2,不能静默降为细线');
69
+ }
70
+ return s;
71
+ }
72
+ function validateImageGeometry(geometry, source) {
73
+ objectKeys(geometry, ['imageWidth', 'imageHeight', 'sheets'], '图片几何证据');
74
+ assert([geometry.imageWidth, geometry.imageHeight].every(n => Number.isInteger(n) && n > 0 && n <= 100000), '图片像素尺寸无效');
75
+ assert(Array.isArray(geometry.sheets) && geometry.sheets.length > 0 && geometry.sheets.length <= source.sheets.length, '图片几何 Sheet 数量无效');
76
+ const names = new Set();
77
+ for (const grid of geometry.sheets) {
78
+ objectKeys(grid, ['sheet', 'xLines', 'yLines', 'regions'], '图片几何网格');
79
+ const sheet = source.sheets.find(s => s.name === grid.sheet);
80
+ assert(sheet && !names.has(grid.sheet), '图片几何 Sheet 缺失或重复');
81
+ names.add(grid.sheet);
82
+ for (const [lines, count, limit] of [[grid.xLines, sheet.columnCount, geometry.imageWidth], [grid.yLines, sheet.rowCount, geometry.imageHeight]]) {
83
+ assert(Array.isArray(lines) && lines.length === count + 1 && lines.every((n, i) => Number.isFinite(n) && n >= 0 && n <= limit && (!i || n > lines[i - 1] && n - lines[i - 1] <= 10000)), '图片边界坐标必须严格递增、匹配行列数且位于原图内');
84
+ }
85
+ assert(sheet.rowCount * sheet.columnCount <= 100000 && Array.isArray(grid.regions) && grid.regions.length <= 100000, '图片几何区域数量超限');
86
+ const occupied = new Set();
87
+ for (const region of grid.regions) {
88
+ objectKeys(region, ['row', 'col', 'rowCount', 'colCount', 'style'], '图片可见区域');
89
+ assert([region.row, region.col, region.rowCount, region.colCount].every(Number.isInteger) && region.row >= 0 && region.col >= 0 && region.rowCount > 0 && region.colCount > 0 && region.row + region.rowCount <= sheet.rowCount && region.col + region.colCount <= sheet.columnCount, '图片可见区域越界');
90
+ if (region.style) {
91
+ const style = normalizeObservedStyle(region.style);
92
+ assert(style.width === undefined && style.height === undefined, '图片区域尺寸由像素边界决定');
93
+ }
94
+ for (let r = region.row; r < region.row + region.rowCount; r++)
95
+ for (let c = region.col; c < region.col + region.colCount; c++) {
96
+ const key = `${r},${c}`;
97
+ assert(!occupied.has(key), '图片可见区域重叠');
98
+ occupied.add(key);
99
+ }
100
+ }
101
+ assert(occupied.size === sheet.rowCount * sheet.columnCount, '图片区域分割不完整:空白区域也必须描述,不能遗漏合并和值区域');
102
+ }
103
+ }
104
+ /** 像素边界是几何来源,不从字段数或默认两字段模板推定网格。 */
105
+ export function geometrySheet(source, selected, mergedAnchorBorders = false, preserveBorders = false) {
106
+ const sheet = clone(selected), geometry = source.imageStyles?.geometry;
107
+ if (!geometry)
108
+ return sheet;
109
+ validateImageGeometry(geometry, source);
110
+ const grid = geometry.sheets.find(s => s.sheet === sheet.name);
111
+ if (!grid)
112
+ return sheet;
113
+ assert(sheet.rows.every(r => r.visible) && sheet.columns.every(c => c.visible), '图片像素网格不接受隐藏行列');
114
+ sheet.columns = grid.xLines.slice(1).map((x, i) => ({ size: x - grid.xLines[i], visible: true }));
115
+ sheet.rows = grid.yLines.slice(1).map((y, i) => ({ size: y - grid.yLines[i], visible: true }));
116
+ sheet.spans = grid.regions.filter(r => r.rowCount > 1 || r.colCount > 1).map(({ row, col, rowCount, colCount }) => ({ row, col, rowCount, colCount }));
117
+ const cells = new Map(sheet.cells.map(c => [`${Number(c.row)},${Number(c.col)}`, c]));
118
+ const get = (r, c) => { const key = `${r},${c}`; if (!cells.has(key)) {
119
+ const cell = { row: String(r), col: String(c), style: {} };
120
+ sheet.cells.push(cell);
121
+ cells.set(key, cell);
122
+ } return cells.get(key); };
123
+ for (const region of grid.regions) {
124
+ const native = observedNative(region.style || {}, get(region.row, region.col).style || {});
125
+ if (preserveBorders) {
126
+ const anchor = get(region.row, region.col), anchorStyle = clone(anchor.style || {});
127
+ const perimeter = [];
128
+ for (let r = region.row; r < region.row + region.rowCount; r++)
129
+ for (let c = region.col; c < region.col + region.colCount; c++) {
130
+ const cell = get(r, c);
131
+ assert(cell === anchor || (!cell.formula && (cell.value === undefined || cell.value === '')), '图片合并区域覆盖了非锚点文字或公式,必须修正观察和映射');
132
+ for (const [key, edge] of [['borderTop', r === region.row], ['borderBottom', r === region.row + region.rowCount - 1], ['borderLeft', c === region.col], ['borderRight', c === region.col + region.colCount - 1]]) {
133
+ const border = native[key] || cell.style?.[key] || (key === 'borderRight' || key === 'borderBottom' ? anchorStyle[key] : undefined);
134
+ if (edge && border)
135
+ perimeter.push({ row: r, col: c, key, border: clone(border) });
136
+ }
137
+ }
138
+ for (let r = region.row; r < region.row + region.rowCount; r++)
139
+ for (let c = region.col; c < region.col + region.colCount; c++) {
140
+ const cell = get(r, c);
141
+ cell.style ||= {};
142
+ for (const key of ['borderTop', 'borderBottom', 'borderLeft', 'borderRight'])
143
+ delete cell.style[key];
144
+ }
145
+ const { borderTop, borderBottom, borderLeft, borderRight, ...text } = native;
146
+ Object.assign(anchor.style, text);
147
+ for (const edge of perimeter)
148
+ get(edge.row, edge.col).style[edge.key] = edge.border;
149
+ if (mergedAnchorBorders)
150
+ for (const [key, count] of [['borderBottom', region.colCount], ['borderRight', region.rowCount]]) {
151
+ const edges = perimeter.filter(e => e.key === key);
152
+ if (edges.length === count && edges.every(e => stable(e.border) === stable(edges[0].border)))
153
+ anchor.style[key] = clone(edges[0].border);
154
+ }
155
+ continue;
156
+ }
157
+ for (let r = region.row; r < region.row + region.rowCount; r++)
158
+ for (let c = region.col; c < region.col + region.colCount; c++) {
159
+ const cell = get(r, c);
160
+ cell.style ||= {};
161
+ const anchor = r === region.row && c === region.col;
162
+ assert(anchor || (!cell.formula && (cell.value === undefined || cell.value === '')), '图片合并区域覆盖了非锚点文字或公式,必须修正观察和映射');
163
+ for (const key of ['borderTop', 'borderBottom', 'borderLeft', 'borderRight'])
164
+ delete cell.style[key];
165
+ if (anchor) {
166
+ const { borderTop, borderBottom, borderLeft, borderRight, ...text } = native;
167
+ Object.assign(cell.style, text);
168
+ if (mergedAnchorBorders && region.rowCount > 1 && borderBottom)
169
+ cell.style.borderBottom = clone(borderBottom);
170
+ if (mergedAnchorBorders && region.colCount > 1 && borderRight)
171
+ cell.style.borderRight = clone(borderRight);
172
+ }
173
+ for (const [key, edge] of [['borderTop', r === region.row], ['borderBottom', r === region.row + region.rowCount - 1], ['borderLeft', c === region.col], ['borderRight', c === region.col + region.colCount - 1]])
174
+ if (edge && native[key])
175
+ cell.style[key] = clone(native[key]);
176
+ }
177
+ }
178
+ return sheet;
179
+ }
180
+ export function validateImageStyles(profile, source) {
181
+ safeTree(profile);
182
+ objectKeys(profile, ['schemaVersion', 'componentStyles', 'geometry', 'page', 'cells', 'fields', 'issues', 'notes', 'tableBorders'], '图片样式观察');
183
+ assert(source.sourceType === 'image' && profile.schemaVersion === 'e10.image-styles/v1', '样式观察只用于图片,版本必须为 e10.image-styles/v1');
184
+ if (profile.geometry)
185
+ validateImageGeometry(profile.geometry, source);
186
+ assert(profile.tableBorders === undefined || Array.isArray(profile.tableBorders) && profile.tableBorders.length <= 1000, '表格外框观察数量超限');
187
+ for (const table of profile.tableBorders || []) {
188
+ objectKeys(table, ['sheet', 'row', 'col', 'rowCount', 'colCount', 'top', 'right', 'bottom', 'left'], '表格外框观察');
189
+ const sheet = source.sheets.find(s => s.name === table.sheet);
190
+ assert(sheet && [table.row, table.col, table.rowCount, table.colCount].every(Number.isInteger) && table.row >= 0 && table.col >= 0 && table.rowCount > 0 && table.colCount > 0 && table.row + table.rowCount <= sheet.rowCount && table.col + table.colCount <= sheet.columnCount, '表格外框必须明确正文范围且位于源网格内');
191
+ for (const side of ['top', 'right', 'bottom', 'left']) {
192
+ assert(table[side] !== undefined, '表格外框必须逐侧记录 top/right/bottom/left,未知用 unknown,无边框用 none');
193
+ if (table[side] !== 'none' && table[side] !== 'unknown')
194
+ normalizeObservedStyle({ border: table[side] });
195
+ }
196
+ }
197
+ assert(profile.componentStyles === undefined || ['merge', 'replace', 'workbookOnly'].includes(profile.componentStyles), '组件样式策略无效');
198
+ assert(Array.isArray(profile.issues) && profile.issues.length <= 1000 && profile.issues.every(s => typeof s === 'string' && s.length > 0), '图片样式 issues 无效');
199
+ assert(profile.notes === undefined || Array.isArray(profile.notes) && profile.notes.length <= 1000 && profile.notes.every(s => typeof s === 'string' && s.length > 0), '图片样式 notes 无效');
200
+ if (profile.page) {
201
+ objectKeys(profile.page, ['backgroundColor'], '页面样式');
202
+ imageColor(profile.page.backgroundColor);
203
+ }
204
+ assert(profile.cells === undefined || Array.isArray(profile.cells) && profile.cells.length <= 100000, '图片单元格样式数量超限');
205
+ const positions = new Set();
206
+ for (const c of profile.cells || []) {
207
+ objectKeys(c, ['sheet', 'row', 'col', 'style'], '图片单元格样式');
208
+ const sheet = source.sheets.find(s => s.name === c.sheet);
209
+ assert(sheet && Number.isInteger(c.row) && Number.isInteger(c.col) && c.row >= 0 && c.row < sheet.rowCount && c.col >= 0 && c.col < sheet.columnCount, '图片样式位置超出网格');
210
+ extent(sheet, { row: c.row, col: c.col });
211
+ const key = `${c.sheet}:${c.row},${c.col}`;
212
+ assert(!positions.has(key), '重复图片样式位置');
213
+ positions.add(key);
214
+ const style = normalizeObservedStyle(c.style);
215
+ assert(style.height === undefined && style.width === undefined, '网格高度和宽度应通过 rows/columns 描述');
216
+ }
217
+ assert(profile.fields === undefined || Array.isArray(profile.fields) && profile.fields.length <= 1000, '图片字段样式数量超限');
218
+ for (const f of profile.fields || []) {
219
+ objectKeys(f, ['fieldId', 'fieldName', 'subFormId', 'displayTitle', 'inputTarget', 'title', 'content', 'input', 'textArea'], '图片字段样式');
220
+ assert(typeof f.fieldId === 'string' && /^[1-9]\d*$/.test(f.fieldId) || typeof f.fieldName === 'string' && f.fieldName.length > 0, '图片字段样式需要精确字段身份');
221
+ assert(f.subFormId === undefined || typeof f.subFormId === 'string' && /^[1-9]\d*$/.test(f.subFormId), '图片字段样式明细身份无效');
222
+ assert(f.title || f.content || f.input || f.textArea || f.displayTitle, '图片字段样式不能为空');
223
+ if (f.displayTitle !== undefined)
224
+ assert(typeof f.fieldId === 'string' && typeof f.displayTitle === 'string' && f.displayTitle.trim() === f.displayTitle && f.displayTitle.length > 0 && f.displayTitle.length <= 200 && !/[<>\r\n]/.test(f.displayTitle), '展示标题必须绑定真实 fieldId,且为纯文本');
225
+ assert(f.inputTarget === undefined || !!f.input && ['component', 'cell'].includes(f.inputTarget), 'inputTarget 必须有 input 样式且为 component/cell');
226
+ if (f.inputTarget === 'cell')
227
+ assert(f.input.height === undefined && f.input.width === undefined, '单元格投影不接受输入框宽高;网格尺寸用 geometry 或 rows/columns');
228
+ assert(profile.componentStyles !== 'workbookOnly' || !f.input || f.inputTarget === 'cell', 'workbookOnly 下 input 必须显式选择 cell;不能静默丢弃控件样式');
229
+ if (f.textArea) {
230
+ objectKeys(f.textArea, ['rows', 'fitCell', 'autoHeight'], '多行文本展示');
231
+ assert(Number.isInteger(f.textArea.rows) && f.textArea.rows > 0 && f.textArea.rows <= 50, '多行文本 rows 必须为 1~50');
232
+ for (const key of ['fitCell', 'autoHeight'])
233
+ assert(f.textArea[key] === undefined || typeof f.textArea[key] === 'boolean', `多行文本 ${key} 必须为布尔值`);
234
+ }
235
+ for (const style of [f.title, f.content, f.input])
236
+ if (style)
237
+ normalizeObservedStyle(style);
238
+ for (const style of [f.title, f.content])
239
+ if (style)
240
+ assert(style.height === undefined && style.width === undefined, '标题/内容区域宽高使用 rows/columns;输入框尺寸使用 input');
241
+ if (f.input)
242
+ assert(!Object.keys(f.input).some(k => ['color', 'fontFamily', 'fontSize', 'fontUnit', 'fontWeight', 'fontStyle', 'textAlign', 'align', 'bold', 'verticalAlign', 'wordWrap', 'underline', 'borderTop', 'borderBottom', 'borderLeft', 'borderRight'].includes(k)), 'input 仅描述文本框外观和统一 border;文字样式用 content,分边边框用单元格样式');
243
+ }
244
+ }
245
+ export function observedCss(input) {
246
+ const s = normalizeObservedStyle(input), css = {};
247
+ for (const [from, to] of [['color', 'color'], ['backgroundColor', 'background-color'], ['fontFamily', 'font-family'], ['fontStyle', 'font-style'], ['textAlign', 'text-align']])
248
+ if (s[from] !== undefined)
249
+ css[to] = s[from];
250
+ if (s.fontSize !== undefined)
251
+ css['font-size'] = `${Number((s.fontSize * (s.fontUnit === 'pt' ? 96 / 72 : 1)).toFixed(1))}px`;
252
+ if (s.fontWeight !== undefined)
253
+ css['font-weight'] = String(s.fontWeight === 'bold' ? 700 : s.fontWeight === 'normal' ? 400 : s.fontWeight);
254
+ for (const key of ['height', 'width'])
255
+ if (s[key] !== undefined)
256
+ css[key] = `${s[key]}px`;
257
+ if (s.border)
258
+ css.border = `${s.border.width}px ${s.border.line} ${s.border.color}`;
259
+ // 网格对齐/换行由 SpreadJS 承载;不向原生组件传未登记的 CSS 属性。
260
+ return css;
261
+ }
262
+ export function observedNative(input, existing = {}) {
263
+ const s = normalizeObservedStyle(input), native = {};
264
+ if (s.color !== undefined)
265
+ native.foreColor = s.color;
266
+ if (s.backgroundColor !== undefined)
267
+ native.backColor = s.backgroundColor;
268
+ const oldFont = nativeFont(existing.font);
269
+ const hasFont = [s.fontSize, s.fontFamily, s.fontWeight, s.fontStyle].some(v => v !== undefined);
270
+ const size = s.fontSize !== undefined ? Number((s.fontSize * (s.fontUnit === 'pt' ? 96 / 72 : 1)).toFixed(1)) : oldFont ? Number((oldFont.fontSize * (oldFont.fontUnit === 'pt' ? 96 / 72 : 1)).toFixed(1)) : undefined;
271
+ if (hasFont && size !== undefined) {
272
+ const weight = s.fontWeight ?? oldFont?.fontWeight ?? 400, fontStyle = s.fontStyle ?? oldFont?.fontStyle;
273
+ native.font = `${fontStyle === 'italic' ? 'italic ' : ''}${weight === 'bold' ? 700 : weight === 'normal' ? 400 : weight} ${size}px ${s.fontFamily || oldFont?.fontFamily || 'sans-serif'}`;
274
+ }
275
+ if (s.textAlign !== undefined)
276
+ native.hAlign = ['left', 'center', 'right'].indexOf(s.textAlign);
277
+ if (s.verticalAlign !== undefined)
278
+ native.vAlign = ['top', 'middle', 'bottom'].indexOf(s.verticalAlign);
279
+ if (s.wordWrap !== undefined)
280
+ native.wordWrap = s.wordWrap;
281
+ if (s.underline !== undefined)
282
+ native.textDecoration = s.underline ? 1 : 0;
283
+ for (const key of ['borderTop', 'borderBottom', 'borderLeft', 'borderRight']) {
284
+ const b = s[key] || s.border;
285
+ if (!b)
286
+ continue;
287
+ native[key] = { color: b.color, style: b.line === 'solid' ? ({ 1: 1, 2: 2, 3: 5 }[b.width]) : b.line === 'dashed' && b.width === 2 ? 8 : ({ dashed: 3, dotted: 4, double: 6 }[b.line]) };
288
+ }
289
+ return native;
290
+ }
291
+ /** 图像单元格键别名规范化,仅在 extract 图片入口使用,Excel 与旧产物不变。 */
292
+ export function normalizeImageCells(source) {
293
+ const copy = clone(source);
294
+ safeTree(copy);
295
+ copy.imageStyles ??= { schemaVersion: 'e10.image-styles/v1', issues: [] };
296
+ const initialRules = copy.imageStyles.cells || (copy.imageStyles.cells = []);
297
+ assert(Array.isArray(initialRules), '图片单元格样式必须为数组');
298
+ const ruleIndex = new Map(initialRules.map(r => [`${r.sheet}:${r.row},${r.col}`, r]));
299
+ for (const sheet of copy.sheets || [])
300
+ for (const cell of sheet.cells || []) {
301
+ const style = cell.style || {}, semantic = {};
302
+ for (const key of KEYS)
303
+ if (style[key] !== undefined && !['wordWrap', 'borderTop', 'borderBottom', 'borderLeft', 'borderRight', 'underline'].includes(key)) {
304
+ semantic[key] = style[key];
305
+ delete style[key];
306
+ }
307
+ if (semantic.bold !== undefined || semantic.fontWeight !== undefined || semantic.fontStyle !== undefined || semantic.fontFamily !== undefined) {
308
+ const match = nativeFont(style.font);
309
+ semantic.fontSize ??= match?.fontSize;
310
+ semantic.fontFamily ??= match?.fontFamily;
311
+ if (semantic.fontSize !== undefined)
312
+ semantic.fontUnit ??= match?.fontUnit;
313
+ semantic.fontStyle ??= match?.fontStyle;
314
+ }
315
+ assert(semantic.height === undefined && semantic.width === undefined, '单元格宽高应通过 rows/columns 描述');
316
+ if (Object.keys(semantic).length) {
317
+ Object.assign(style, observedNative(semantic, style));
318
+ const rules = initialRules, key = `${sheet.name}:${Number(cell.row)},${Number(cell.col)}`;
319
+ const hit = ruleIndex.get(key);
320
+ if (hit)
321
+ hit.style = { ...semantic, ...hit.style };
322
+ else {
323
+ const added = { sheet: sheet.name, row: Number(cell.row), col: Number(cell.col), style: semantic };
324
+ rules.push(added);
325
+ ruleIndex.set(key, added);
326
+ }
327
+ }
328
+ for (const key of ['foreColor', 'backColor'])
329
+ if (style[key] !== undefined)
330
+ style[key] = imageColor(style[key]);
331
+ cell.style = style;
332
+ }
333
+ return copy;
334
+ }
335
+ export function prepareImageStyleSheet(source, selected, mergedAnchorBorders = false, preserveBorders = false) {
336
+ const sheet = geometrySheet(source, selected, mergedAnchorBorders, preserveBorders);
337
+ const cellIndex = new Map(sheet.cells.map(c => [`${Number(c.row)},${Number(c.col)}`, c]));
338
+ if (source.imageStyles)
339
+ for (const cell of sheet.cells) {
340
+ for (const key of ['foreColor', 'backColor'])
341
+ if (cell.style?.[key] !== undefined)
342
+ cell.style[key] = imageColor(cell.style[key]);
343
+ if (cell.style?.font)
344
+ cell.style.font = observedNative(nativeFont(cell.style.font)).font;
345
+ }
346
+ for (const rule of source.imageStyles?.cells || []) {
347
+ assert(rule.sheet === selected.name, '图片样式包含未选择的 Sheet,需要分别编译');
348
+ const key = `${rule.row},${rule.col}`;
349
+ const cell = cellIndex.get(key) || { row: String(rule.row), col: String(rule.col), style: {} };
350
+ cell.style = { ...(cell.style || {}), ...observedNative(rule.style, cell.style) };
351
+ if (!cellIndex.has(key)) {
352
+ sheet.cells.push(cell);
353
+ cellIndex.set(key, cell);
354
+ }
355
+ }
356
+ return sheet;
357
+ }
358
+ function nativeTextCss(style, effectiveText = false) {
359
+ const css = {};
360
+ if (style.foreColor !== undefined)
361
+ css.color = imageColor(style.foreColor);
362
+ if (effectiveText && style.backColor !== undefined)
363
+ css['background-color'] = imageColor(style.backColor);
364
+ const font = nativeFont(style.font);
365
+ if (font)
366
+ Object.assign(css, observedCss(font));
367
+ if (style.hAlign !== undefined && style.hAlign <= 2)
368
+ css['text-align'] = ['left', 'center', 'right'][style.hAlign];
369
+ if (effectiveText && style.vAlign !== undefined && style.vAlign <= 2)
370
+ css['align-items'] = ['flex-start', 'center', 'flex-end'][style.vAlign];
371
+ return css;
372
+ }
373
+ export function projectImageField(source, binding, title, content, projection, used, sheetName, effectiveDisplay = false, effectiveText = false) {
374
+ if (!source.imageStyles)
375
+ return;
376
+ const f = binding.field, sub = String(f.subFormId || '');
377
+ const rules = (source.imageStyles.fields || []).filter(r => (r.fieldId ? r.fieldId === f.fieldId : r.fieldName === String(f.title || f.fieldName)) && (r.subFormId ? r.subFormId === sub : ['', '0', '-1'].includes(sub)));
378
+ assert(rules.length <= 1, `重复图片字段样式 ${f.fieldId}`);
379
+ const rule = rules[0];
380
+ if (rule) {
381
+ if (rule.fieldName)
382
+ assert(rule.fieldName === String(f.title || f.fieldName), '图片样式字段名与 ID 不一致');
383
+ used.add(rule);
384
+ }
385
+ if (rule?.displayTitle !== undefined) {
386
+ assert(binding.value.config, '字段缺少原生展示配置');
387
+ assert(binding.value.config.displayName === undefined || binding.value.config.displayName && typeof binding.value.config.displayName === 'object' && !Array.isArray(binding.value.config.displayName), '原生展示标题形状无效');
388
+ const properties = { enableDisplayName: true, displayName: { ...(binding.value.config.displayName || {}), nameAlias: rule.displayTitle } };
389
+ Object.assign(binding.value.config, properties);
390
+ projection.entries.push({ layer: 'componentConfig', componentId: String(binding.value.id), source: `field:${f.fieldId}.displayTitle`, properties: clone(properties) });
391
+ }
392
+ if (rule?.textArea) {
393
+ assert(binding.value.type === 'TextArea' && binding.value.config?.richEditor !== true, 'textArea 展示只支持普通 TextArea,不转换字段或富文本');
394
+ const properties = effectiveDisplay && rule.textArea.fitCell === true ? {} : { height: rule.textArea.rows };
395
+ if (effectiveDisplay && rule.textArea.fitCell === true)
396
+ (projection.notes ||= []).push(`字段 ${f.fieldId} 使用 fullHeight 撑满单元格;rows=${rule.textArea.rows} 不作为独立显示高度写入`);
397
+ if (rule.textArea.fitCell !== undefined)
398
+ properties.fullHeight = rule.textArea.fitCell;
399
+ if (rule.textArea.autoHeight !== undefined)
400
+ properties.disableAutoHeight = !rule.textArea.autoHeight;
401
+ Object.assign(binding.value.config, properties);
402
+ projection.entries.push({ layer: 'componentConfig', componentId: String(binding.value.id), source: `field:${f.fieldId}.textArea`, properties });
403
+ }
404
+ for (const [cell, style] of [[title, rule?.title], [content, rule?.content]])
405
+ if (style)
406
+ cell.style = { ...(cell.style || {}), ...observedNative(style, cell.style) };
407
+ if (rule?.input && rule.inputTarget === 'cell')
408
+ content.style = { ...(content.style || {}), ...observedNative(rule.input, content.style) };
409
+ if (source.imageStyles.componentStyles === 'replace' || source.imageStyles.componentStyles === 'workbookOnly') {
410
+ delete binding.title.config.styles;
411
+ delete binding.value.config.styles;
412
+ }
413
+ if (source.imageStyles.componentStyles === 'workbookOnly')
414
+ return;
415
+ const cellCss = (cell) => { const r = source.imageStyles?.cells?.find(r => r.row === Number(cell.row) && r.col === Number(cell.col)); return r ? observedCss(r.style) : {}; };
416
+ const originalCss = (cell) => {
417
+ const candidates = source.sheets.filter(s => s.name === sheetName).flatMap(s => s.cells).filter(c => Number(c.row) === Number(cell.row) && Number(c.col) === Number(cell.col));
418
+ return candidates.length === 1 ? nativeTextCss(candidates[0].style || {}) : {};
419
+ };
420
+ // CSS 只投影实际观察属性;SpreadJS 字体缺省值不能冒充图片已识别的字体属性。
421
+ const groups = { title: { ...originalCss(title), ...cellCss(title), ...(rule?.title ? observedCss(rule.title) : {}) }, content: { ...originalCss(content), ...cellCss(content), ...(rule?.content ? observedCss(rule.content) : {}) } };
422
+ if (effectiveText) {
423
+ Object.assign(groups.title, nativeTextCss(title.style || {}, true));
424
+ Object.assign(groups.content, nativeTextCss(content.style || {}, true));
425
+ }
426
+ if (rule?.input && rule.inputTarget !== 'cell')
427
+ groups.inputStyle = observedCss(rule.input);
428
+ for (const key of Object.keys(groups))
429
+ if (!Object.keys(groups[key]).length)
430
+ delete groups[key];
431
+ if (!Object.keys(groups).length)
432
+ return;
433
+ const comp = binding.value, categories = Array.isArray(comp.applyStyle) ? comp.applyStyle.map(String) : String(comp.applyStyle || '').split(',').filter(Boolean);
434
+ if (categories.length !== 1 || !comp.styleCategoryCompKey || !comp.config) {
435
+ projection.issues.push(`字段 ${f.fieldId} 缺少唯一原生样式分类,组件样式未投影`);
436
+ return;
437
+ }
438
+ const auditedCategories = ['InputStyleConfig', 'TextAreaStyleConfig', 'UploadStyleConfig', 'OptionStyleConfig', 'InputOptionStyleConfig', 'ImageOptionStyleConfig', 'DateStyleConfig', 'DateInputStyleConfig', 'RelateStyleConfig', 'OtherStyleConfig1', 'OtherStyleConfig2', 'BaseFieldStyleConfig'];
439
+ if (!auditedCategories.includes(comp.styleCategoryCompKey) || comp.styleCategoryPackage && comp.styleCategoryPackage !== '@weapp/formbuilder') {
440
+ projection.issues.push(`字段 ${f.fieldId} 的样式分类 ${comp.styleCategoryCompKey} 尚未核对原生渲染契约`);
441
+ return;
442
+ }
443
+ if (groups.inputStyle && !['InputStyleConfig', 'DateInputStyleConfig', 'TextAreaStyleConfig', 'InputOptionStyleConfig'].includes(comp.styleCategoryCompKey)) {
444
+ projection.issues.push(`字段 ${f.fieldId} 的原生分类不支持 inputStyle`);
445
+ delete groups.inputStyle;
446
+ }
447
+ if (groups.inputStyle?.height && comp.styleCategoryCompKey === 'TextAreaStyleConfig') {
448
+ projection.issues.push(`字段 ${f.fieldId} 的 TextArea 高度需专门原生契约,未写 inputStyle.height`);
449
+ delete groups.inputStyle.height;
450
+ }
451
+ assert(comp.config.styles === undefined || Array.isArray(comp.config.styles), '原生组件 styles 形状无效');
452
+ const styles = comp.config.styles || (comp.config.styles = []), category = categories[0];
453
+ const matches = styles.filter((s) => String(s.category) === category);
454
+ assert(matches.length <= 1, '原生样式分类重复');
455
+ const row = matches[0] || { category, useCustom: true, customStyle: {} };
456
+ row.useCustom = true;
457
+ row.customStyle ||= {};
458
+ if (Array.isArray(comp.applyStyle))
459
+ row.category = comp.applyStyle[0];
460
+ for (const [group, properties] of Object.entries(groups)) {
461
+ row.customStyle[group] = { ...(row.customStyle[group] || {}), ...properties };
462
+ projection.entries.push({ layer: 'component', componentId: String(comp.id), category, group, source: `field:${f.fieldId}.${group}`, properties: clone(properties) });
463
+ }
464
+ if (!matches.length)
465
+ styles.push(row);
466
+ }
467
+ export function projectImagePage(source, layout, projection) {
468
+ if (!source.imageStyles?.page)
469
+ return;
470
+ const parse = (v, label) => {
471
+ const value = typeof v === 'string' ? (v.trim() ? JSON.parse(v) : {}) : clone(v || {});
472
+ assert(value && typeof value === 'object' && !Array.isArray(value), `${label} 必须为 JSON 对象`);
473
+ safeTree(value);
474
+ return value;
475
+ };
476
+ const style = parse(layout.formStyle, 'formStyle'), config = parse(style.styleConfig, 'styleConfig');
477
+ config.formLayout ||= {};
478
+ config.formLayout.background ||= {};
479
+ assert(typeof config.formLayout === 'object' && !Array.isArray(config.formLayout) && typeof config.formLayout.background === 'object' && !Array.isArray(config.formLayout.background), 'formLayout/background 必须为 JSON 对象');
480
+ const properties = { 'background-color': imageColor(source.imageStyles.page.backgroundColor) };
481
+ Object.assign(config.formLayout.background, properties);
482
+ // 原生 FormStyle.styleConfig 是 Java String;内部修改用对象,保存必须编码回 JSON 字符串。
483
+ style.styleConfig = JSON.stringify(config);
484
+ layout.formStyle = style;
485
+ projection.entries.push({ layer: 'page', source: 'page.backgroundColor', group: 'background', properties });
486
+ }
487
+ export function canonicalImageFormStyle(value) {
488
+ if (value === undefined)
489
+ return undefined;
490
+ const style = typeof value === 'string' ? JSON.parse(value) : clone(value);
491
+ if (style && typeof style.styleConfig === 'string')
492
+ style.styleConfig = JSON.parse(style.styleConfig);
493
+ safeTree(style);
494
+ return style;
495
+ }
496
+ export function imageStyleReport(projection, pages, formStyle) {
497
+ const scope = { verificationScope: 'OBSERVATION_TO_NATIVE_READBACK', sourceImageCompared: false };
498
+ if (!projection)
499
+ return { ...scope, projectionVerified: false, status: 'NOT_OBSERVED', comparedProperties: 0, matchedProperties: 0, differences: [], issues: [] };
500
+ let comparedProperties = 0, matchedProperties = 0;
501
+ const differences = [];
502
+ const parse = (v) => { try {
503
+ return typeof v === 'string' ? JSON.parse(v) : v || {};
504
+ }
505
+ catch {
506
+ return {};
507
+ } };
508
+ const comps = [];
509
+ const flatten = (list) => { for (const c of list) {
510
+ comps.push(c);
511
+ flatten(c.children || []);
512
+ flatten(c.config?.children || []);
513
+ } };
514
+ pages?.forEach(p => flatten(p.comps || []));
515
+ for (const entry of projection.entries) {
516
+ let actual = {};
517
+ if (pages) {
518
+ if (entry.layer === 'page')
519
+ actual = parse(parse(formStyle).styleConfig).formLayout?.[entry.group] || {};
520
+ else if (entry.layer === 'componentConfig')
521
+ actual = comps.find(c => String(c.id) === entry.componentId)?.config || {};
522
+ else if (entry.layer === 'component')
523
+ actual = comps.find(c => String(c.id) === entry.componentId)?.config?.styles?.find((s) => String(s.category) === entry.category)?.customStyle?.[entry.group] || {};
524
+ else
525
+ actual = pages.flatMap(p => p.config?.workbook?.[entry.sheet]?.cells || []).find(c => Number(c.row) === entry.row && Number(c.col) === entry.col)?.style || {};
526
+ }
527
+ for (const [property, expected] of Object.entries(entry.properties)) {
528
+ comparedProperties++;
529
+ if (!pages)
530
+ continue;
531
+ if (stable(expected) === stable(actual[property]))
532
+ matchedProperties++;
533
+ else if (differences.length < 100)
534
+ differences.push({ source: entry.source, layer: entry.layer, property, expected, actual: actual[property] ?? null });
535
+ }
536
+ }
537
+ return { ...scope, projectionVerified: !!pages && !projection.issues.length && !differences.length && comparedProperties > 0, status: projection.issues.length ? 'INCOMPLETE' : !pages ? 'COMPILED' : differences.length ? 'MISMATCH' : comparedProperties > 0 ? 'VERIFIED' : 'INCOMPLETE', comparedProperties, matchedProperties, differences, issues: clone(projection.issues), ...(projection.notes ? { notes: clone(projection.notes) } : {}) };
538
+ }
539
+ //# sourceMappingURL=image-style.js.map