@graphty/graph-io 0.3.42 → 0.3.44

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 (674) hide show
  1. package/dist/chunks/approximations-3Q4TsdTh.js +40 -0
  2. package/dist/chunks/approximations-3Q4TsdTh.js.map +1 -0
  3. package/dist/chunks/block-JQiwViEt.js +2777 -0
  4. package/dist/chunks/block-JQiwViEt.js.map +1 -0
  5. package/dist/chunks/{choose-DvpbdRuz.js → choose-BemygfH8.js} +3 -2
  6. package/dist/chunks/{choose-DvpbdRuz.js.map → choose-BemygfH8.js.map} +1 -1
  7. package/dist/chunks/{constants-fT3E8JYY.js → constants-BFUR_CtU.js} +6 -2
  8. package/dist/chunks/constants-BFUR_CtU.js.map +1 -0
  9. package/dist/chunks/convert-BcQ8_jMo.js +59 -0
  10. package/dist/chunks/convert-BcQ8_jMo.js.map +1 -0
  11. package/dist/chunks/emit-DCwFLts5.js +3456 -0
  12. package/dist/chunks/emit-DCwFLts5.js.map +1 -0
  13. package/dist/chunks/{escape-B62ZGM_a.js → escape-B1rMftd9.js} +43 -20
  14. package/dist/chunks/escape-B1rMftd9.js.map +1 -0
  15. package/dist/chunks/{export-rKLeGQMo.js → export-D7IGzTG4.js} +196 -792
  16. package/dist/chunks/export-D7IGzTG4.js.map +1 -0
  17. package/dist/chunks/{exporter-BWwEuOPT.js → exporter-BtnqYuuj.js} +22 -12
  18. package/dist/chunks/exporter-BtnqYuuj.js.map +1 -0
  19. package/dist/chunks/{exporter-yLxKBvLE.js → exporter-ChPyhBOv.js} +4 -3
  20. package/dist/chunks/{exporter-yLxKBvLE.js.map → exporter-ChPyhBOv.js.map} +1 -1
  21. package/dist/chunks/{exporter-8hLNemFk.js → exporter-KEPxYUXD.js} +133 -74
  22. package/dist/chunks/exporter-KEPxYUXD.js.map +1 -0
  23. package/dist/chunks/{exporter-CpRyHZ3H.js → exporter-quPUCBiC.js} +1807 -288
  24. package/dist/chunks/exporter-quPUCBiC.js.map +1 -0
  25. package/dist/chunks/format-GDmO6m6Q.js +676 -0
  26. package/dist/chunks/format-GDmO6m6Q.js.map +1 -0
  27. package/dist/chunks/generic-BL06jrJf.js +1347 -0
  28. package/dist/chunks/generic-BL06jrJf.js.map +1 -0
  29. package/dist/chunks/{importer-WrGRZb0N.js → importer-B7r2owVf.js} +449 -102
  30. package/dist/chunks/importer-B7r2owVf.js.map +1 -0
  31. package/dist/chunks/{importer-Ht7LNg8L.js → importer-BFmOP96W.js} +116 -296
  32. package/dist/chunks/importer-BFmOP96W.js.map +1 -0
  33. package/dist/chunks/{importer-BbNb7eNg.js → importer-C2nzGhdV.js} +1390 -129
  34. package/dist/chunks/importer-C2nzGhdV.js.map +1 -0
  35. package/dist/chunks/{importer-Dz7tI8Sa.js → importer-CbX2_rNF.js} +617 -115
  36. package/dist/chunks/importer-CbX2_rNF.js.map +1 -0
  37. package/dist/chunks/{importer-D794XUTe.js → importer-CdzeN6X4.js} +31 -8
  38. package/dist/chunks/importer-CdzeN6X4.js.map +1 -0
  39. package/dist/chunks/{importer-xZ-3suY1.js → importer-ChKNC_GN.js} +791 -135
  40. package/dist/chunks/importer-ChKNC_GN.js.map +1 -0
  41. package/dist/chunks/{importer-C98dpSH4.js → importer-dwoYpSqb.js} +141 -82
  42. package/dist/chunks/importer-dwoYpSqb.js.map +1 -0
  43. package/dist/chunks/index-B9fdNpTA.js +4310 -0
  44. package/dist/chunks/index-B9fdNpTA.js.map +1 -0
  45. package/dist/chunks/{json-elements-DKSqpNW1.js → json-elements-C4FwgnH5.js} +123 -32
  46. package/dist/chunks/json-elements-C4FwgnH5.js.map +1 -0
  47. package/dist/chunks/lexicon-B-knUi-l.js +508 -0
  48. package/dist/chunks/lexicon-B-knUi-l.js.map +1 -0
  49. package/dist/chunks/{ontology-export-CtRXjg_i.js → ontology-export-BSpbY5FL.js} +3 -2
  50. package/dist/chunks/{ontology-export-CtRXjg_i.js.map → ontology-export-BSpbY5FL.js.map} +1 -1
  51. package/dist/chunks/{records-Cu4bxYOm.js → records-Nwz_rbNt.js} +2 -2
  52. package/dist/chunks/{records-Cu4bxYOm.js.map → records-Nwz_rbNt.js.map} +1 -1
  53. package/dist/chunks/styles-Brt9JMfs.js +690 -0
  54. package/dist/chunks/styles-Brt9JMfs.js.map +1 -0
  55. package/dist/chunks/styles-_N-C8S-U.js +2102 -0
  56. package/dist/chunks/styles-_N-C8S-U.js.map +1 -0
  57. package/dist/chunks/styles-yed-DAfcIkf7.js +842 -0
  58. package/dist/chunks/styles-yed-DAfcIkf7.js.map +1 -0
  59. package/dist/chunks/{text-DHOJXnED.js → text-CgzMqHQb.js} +2 -2
  60. package/dist/chunks/{text-DHOJXnED.js.map → text-CgzMqHQb.js.map} +1 -1
  61. package/dist/chunks/units-XMZFIFe1.js +19 -0
  62. package/dist/chunks/units-XMZFIFe1.js.map +1 -0
  63. package/dist/csv.js +5 -4
  64. package/dist/csv.js.map +1 -1
  65. package/dist/cx.js +1 -1
  66. package/dist/cx2.js +2 -2
  67. package/dist/cys.js +1 -1
  68. package/dist/dot.js +5 -2
  69. package/dist/dot.js.map +1 -1
  70. package/dist/gexf.js +295 -414
  71. package/dist/gexf.js.map +1 -1
  72. package/dist/gml.js +8 -3031
  73. package/dist/gml.js.map +1 -1
  74. package/dist/graph-io.js +354 -240
  75. package/dist/graph-io.js.map +1 -1
  76. package/dist/graphml.js +4 -2
  77. package/dist/graphml.js.map +1 -1
  78. package/dist/json.js +1 -1
  79. package/dist/neo4j.js +4 -3
  80. package/dist/neo4j.js.map +1 -1
  81. package/dist/obo.js +1 -1
  82. package/dist/pajek.js +4 -2
  83. package/dist/positions.d.ts +1 -0
  84. package/dist/positions.js +427 -0
  85. package/dist/positions.js.map +1 -0
  86. package/dist/src/common/codes.d.ts +6 -0
  87. package/dist/src/common/codes.d.ts.map +1 -1
  88. package/dist/src/common/codes.js +6 -0
  89. package/dist/src/common/codes.js.map +1 -1
  90. package/dist/src/common/escape.d.ts.map +1 -1
  91. package/dist/src/common/escape.js +4 -2
  92. package/dist/src/common/escape.js.map +1 -1
  93. package/dist/src/common/export.d.ts +10 -0
  94. package/dist/src/common/export.d.ts.map +1 -1
  95. package/dist/src/common/export.js +123 -100
  96. package/dist/src/common/export.js.map +1 -1
  97. package/dist/src/common/input.d.ts.map +1 -1
  98. package/dist/src/common/input.js +8 -1
  99. package/dist/src/common/input.js.map +1 -1
  100. package/dist/src/common/json-elements.d.ts +12 -9
  101. package/dist/src/common/json-elements.d.ts.map +1 -1
  102. package/dist/src/common/json-elements.js +160 -37
  103. package/dist/src/common/json-elements.js.map +1 -1
  104. package/dist/src/common/notes.d.ts +42 -0
  105. package/dist/src/common/notes.d.ts.map +1 -0
  106. package/dist/src/common/notes.js +72 -0
  107. package/dist/src/common/notes.js.map +1 -0
  108. package/dist/src/common/report.d.ts +18 -0
  109. package/dist/src/common/report.d.ts.map +1 -1
  110. package/dist/src/common/report.js +36 -1
  111. package/dist/src/common/report.js.map +1 -1
  112. package/dist/src/common/units.d.ts +24 -0
  113. package/dist/src/common/units.d.ts.map +1 -0
  114. package/dist/src/common/units.js +26 -0
  115. package/dist/src/common/units.js.map +1 -0
  116. package/dist/src/common/xml.d.ts +18 -0
  117. package/dist/src/common/xml.d.ts.map +1 -1
  118. package/dist/src/common/xml.js +42 -5
  119. package/dist/src/common/xml.js.map +1 -1
  120. package/dist/src/formats/cx/exporter.d.ts +6 -0
  121. package/dist/src/formats/cx/exporter.d.ts.map +1 -1
  122. package/dist/src/formats/cx/exporter.js +71 -8
  123. package/dist/src/formats/cx/exporter.js.map +1 -1
  124. package/dist/src/formats/cx/importer.d.ts +5 -2
  125. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  126. package/dist/src/formats/cx/importer.js +102 -72
  127. package/dist/src/formats/cx/importer.js.map +1 -1
  128. package/dist/src/formats/cx/styles.d.ts +102 -0
  129. package/dist/src/formats/cx/styles.d.ts.map +1 -0
  130. package/dist/src/formats/cx/styles.js +225 -0
  131. package/dist/src/formats/cx/styles.js.map +1 -0
  132. package/dist/src/formats/cx2/exporter.d.ts +5 -0
  133. package/dist/src/formats/cx2/exporter.d.ts.map +1 -1
  134. package/dist/src/formats/cx2/exporter.js +181 -71
  135. package/dist/src/formats/cx2/exporter.js.map +1 -1
  136. package/dist/src/formats/cx2/importer.d.ts +4 -1
  137. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  138. package/dist/src/formats/cx2/importer.js +19 -1
  139. package/dist/src/formats/cx2/importer.js.map +1 -1
  140. package/dist/src/formats/cx2/styles.d.ts +18 -0
  141. package/dist/src/formats/cx2/styles.d.ts.map +1 -0
  142. package/dist/src/formats/cx2/styles.js +24 -0
  143. package/dist/src/formats/cx2/styles.js.map +1 -0
  144. package/dist/src/formats/cys/constants.d.ts +2 -0
  145. package/dist/src/formats/cys/constants.d.ts.map +1 -1
  146. package/dist/src/formats/cys/constants.js +2 -0
  147. package/dist/src/formats/cys/constants.js.map +1 -1
  148. package/dist/src/formats/cys/exporter.d.ts +6 -2
  149. package/dist/src/formats/cys/exporter.d.ts.map +1 -1
  150. package/dist/src/formats/cys/exporter.js +215 -53
  151. package/dist/src/formats/cys/exporter.js.map +1 -1
  152. package/dist/src/formats/cys/importer.d.ts +2 -1
  153. package/dist/src/formats/cys/importer.d.ts.map +1 -1
  154. package/dist/src/formats/cys/importer.js +119 -6
  155. package/dist/src/formats/cys/importer.js.map +1 -1
  156. package/dist/src/formats/cys/session.d.ts +2 -0
  157. package/dist/src/formats/cys/session.d.ts.map +1 -1
  158. package/dist/src/formats/cys/session.js +5 -0
  159. package/dist/src/formats/cys/session.js.map +1 -1
  160. package/dist/src/formats/cys/styles.d.ts +38 -0
  161. package/dist/src/formats/cys/styles.d.ts.map +1 -0
  162. package/dist/src/formats/cys/styles.js +213 -0
  163. package/dist/src/formats/cys/styles.js.map +1 -0
  164. package/dist/src/formats/cys/tables.d.ts +8 -3
  165. package/dist/src/formats/cys/tables.d.ts.map +1 -1
  166. package/dist/src/formats/cys/tables.js +88 -34
  167. package/dist/src/formats/cys/tables.js.map +1 -1
  168. package/dist/src/formats/dot/exporter.d.ts +2 -0
  169. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  170. package/dist/src/formats/dot/exporter.js +195 -81
  171. package/dist/src/formats/dot/exporter.js.map +1 -1
  172. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  173. package/dist/src/formats/dot/importer.js +100 -20
  174. package/dist/src/formats/dot/importer.js.map +1 -1
  175. package/dist/src/formats/dot/index.d.ts +1 -0
  176. package/dist/src/formats/dot/index.d.ts.map +1 -1
  177. package/dist/src/formats/dot/index.js +1 -0
  178. package/dist/src/formats/dot/index.js.map +1 -1
  179. package/dist/src/formats/dot/positions.d.ts +14 -0
  180. package/dist/src/formats/dot/positions.d.ts.map +1 -0
  181. package/dist/src/formats/dot/positions.js +70 -0
  182. package/dist/src/formats/dot/positions.js.map +1 -0
  183. package/dist/src/formats/dot/styles.d.ts +82 -0
  184. package/dist/src/formats/dot/styles.d.ts.map +1 -0
  185. package/dist/src/formats/dot/styles.js +1484 -0
  186. package/dist/src/formats/dot/styles.js.map +1 -0
  187. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  188. package/dist/src/formats/gexf/exporter.js +23 -7
  189. package/dist/src/formats/gexf/exporter.js.map +1 -1
  190. package/dist/src/formats/gexf/importer.d.ts +8 -1
  191. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  192. package/dist/src/formats/gexf/importer.js +251 -131
  193. package/dist/src/formats/gexf/importer.js.map +1 -1
  194. package/dist/src/formats/gexf/index.d.ts +8 -0
  195. package/dist/src/formats/gexf/index.d.ts.map +1 -1
  196. package/dist/src/formats/gexf/index.js +10 -2
  197. package/dist/src/formats/gexf/index.js.map +1 -1
  198. package/dist/src/formats/gexf/schema.d.ts +5 -0
  199. package/dist/src/formats/gexf/schema.d.ts.map +1 -1
  200. package/dist/src/formats/gexf/schema.js +5 -0
  201. package/dist/src/formats/gexf/schema.js.map +1 -1
  202. package/dist/src/formats/gexf/styles.d.ts +74 -0
  203. package/dist/src/formats/gexf/styles.d.ts.map +1 -0
  204. package/dist/src/formats/gexf/styles.js +604 -0
  205. package/dist/src/formats/gexf/styles.js.map +1 -0
  206. package/dist/src/formats/gml/exporter.d.ts +1 -5
  207. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  208. package/dist/src/formats/gml/exporter.js +19 -8
  209. package/dist/src/formats/gml/exporter.js.map +1 -1
  210. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  211. package/dist/src/formats/gml/importer.js +4 -0
  212. package/dist/src/formats/gml/importer.js.map +1 -1
  213. package/dist/src/formats/gml/index.d.ts +2 -1
  214. package/dist/src/formats/gml/index.d.ts.map +1 -1
  215. package/dist/src/formats/gml/index.js +2 -1
  216. package/dist/src/formats/gml/index.js.map +1 -1
  217. package/dist/src/formats/gml/positions.d.ts +14 -0
  218. package/dist/src/formats/gml/positions.d.ts.map +1 -0
  219. package/dist/src/formats/gml/positions.js +46 -0
  220. package/dist/src/formats/gml/positions.js.map +1 -0
  221. package/dist/src/formats/gml/styles.d.ts +59 -0
  222. package/dist/src/formats/gml/styles.d.ts.map +1 -0
  223. package/dist/src/formats/gml/styles.js +1056 -0
  224. package/dist/src/formats/gml/styles.js.map +1 -0
  225. package/dist/src/formats/gml/syntax.d.ts +11 -0
  226. package/dist/src/formats/gml/syntax.d.ts.map +1 -1
  227. package/dist/src/formats/gml/syntax.js +151 -62
  228. package/dist/src/formats/gml/syntax.js.map +1 -1
  229. package/dist/src/formats/graphml/constants.d.ts +4 -0
  230. package/dist/src/formats/graphml/constants.d.ts.map +1 -1
  231. package/dist/src/formats/graphml/constants.js +5 -1
  232. package/dist/src/formats/graphml/constants.js.map +1 -1
  233. package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
  234. package/dist/src/formats/graphml/exporter.js +133 -65
  235. package/dist/src/formats/graphml/exporter.js.map +1 -1
  236. package/dist/src/formats/graphml/importer.d.ts +4 -1
  237. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  238. package/dist/src/formats/graphml/importer.js +100 -44
  239. package/dist/src/formats/graphml/importer.js.map +1 -1
  240. package/dist/src/formats/graphml/index.d.ts +1 -0
  241. package/dist/src/formats/graphml/index.d.ts.map +1 -1
  242. package/dist/src/formats/graphml/index.js +1 -0
  243. package/dist/src/formats/graphml/index.js.map +1 -1
  244. package/dist/src/formats/graphml/styles-plain.d.ts +19 -0
  245. package/dist/src/formats/graphml/styles-plain.d.ts.map +1 -0
  246. package/dist/src/formats/graphml/styles-plain.js +187 -0
  247. package/dist/src/formats/graphml/styles-plain.js.map +1 -0
  248. package/dist/src/formats/graphml/styles-yed.d.ts +179 -0
  249. package/dist/src/formats/graphml/styles-yed.d.ts.map +1 -0
  250. package/dist/src/formats/graphml/styles-yed.js +1086 -0
  251. package/dist/src/formats/graphml/styles-yed.js.map +1 -0
  252. package/dist/src/formats/graphml/styles-yfiles3.d.ts +19 -0
  253. package/dist/src/formats/graphml/styles-yfiles3.d.ts.map +1 -0
  254. package/dist/src/formats/graphml/styles-yfiles3.js +508 -0
  255. package/dist/src/formats/graphml/styles-yfiles3.js.map +1 -0
  256. package/dist/src/formats/graphml/tree.d.ts.map +1 -1
  257. package/dist/src/formats/graphml/tree.js +34 -19
  258. package/dist/src/formats/graphml/tree.js.map +1 -1
  259. package/dist/src/formats/graphml/yfiles.d.ts +16 -2
  260. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  261. package/dist/src/formats/graphml/yfiles.js +83 -12
  262. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  263. package/dist/src/formats/json/exporter.d.ts +5 -0
  264. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  265. package/dist/src/formats/json/exporter.js +68 -25
  266. package/dist/src/formats/json/exporter.js.map +1 -1
  267. package/dist/src/formats/json/importer.d.ts +22 -3
  268. package/dist/src/formats/json/importer.d.ts.map +1 -1
  269. package/dist/src/formats/json/importer.js +441 -265
  270. package/dist/src/formats/json/importer.js.map +1 -1
  271. package/dist/src/formats/json/positions.d.ts +16 -0
  272. package/dist/src/formats/json/positions.d.ts.map +1 -0
  273. package/dist/src/formats/json/positions.js +44 -0
  274. package/dist/src/formats/json/positions.js.map +1 -0
  275. package/dist/src/formats/json/styles.d.ts +102 -0
  276. package/dist/src/formats/json/styles.d.ts.map +1 -0
  277. package/dist/src/formats/json/styles.js +1753 -0
  278. package/dist/src/formats/json/styles.js.map +1 -0
  279. package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
  280. package/dist/src/formats/neo4j/exporter.js +2 -1
  281. package/dist/src/formats/neo4j/exporter.js.map +1 -1
  282. package/dist/src/formats/pajek/exporter.d.ts +2 -0
  283. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  284. package/dist/src/formats/pajek/exporter.js +142 -76
  285. package/dist/src/formats/pajek/exporter.js.map +1 -1
  286. package/dist/src/formats/pajek/importer.d.ts +4 -0
  287. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  288. package/dist/src/formats/pajek/importer.js +60 -6
  289. package/dist/src/formats/pajek/importer.js.map +1 -1
  290. package/dist/src/formats/pajek/index.d.ts +2 -0
  291. package/dist/src/formats/pajek/index.d.ts.map +1 -1
  292. package/dist/src/formats/pajek/index.js +2 -0
  293. package/dist/src/formats/pajek/index.js.map +1 -1
  294. package/dist/src/formats/pajek/styles.d.ts +50 -0
  295. package/dist/src/formats/pajek/styles.d.ts.map +1 -0
  296. package/dist/src/formats/pajek/styles.js +569 -0
  297. package/dist/src/formats/pajek/styles.js.map +1 -0
  298. package/dist/src/formats/pajek/syntax.d.ts +6 -0
  299. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  300. package/dist/src/formats/pajek/syntax.js +6 -0
  301. package/dist/src/formats/pajek/syntax.js.map +1 -1
  302. package/dist/src/formats/xgmml/columns.d.ts.map +1 -1
  303. package/dist/src/formats/xgmml/columns.js +34 -9
  304. package/dist/src/formats/xgmml/columns.js.map +1 -1
  305. package/dist/src/formats/xgmml/constants.d.ts +2 -0
  306. package/dist/src/formats/xgmml/constants.d.ts.map +1 -1
  307. package/dist/src/formats/xgmml/constants.js +3 -1
  308. package/dist/src/formats/xgmml/constants.js.map +1 -1
  309. package/dist/src/formats/xgmml/document.d.ts +12 -8
  310. package/dist/src/formats/xgmml/document.d.ts.map +1 -1
  311. package/dist/src/formats/xgmml/document.js +56 -13
  312. package/dist/src/formats/xgmml/document.js.map +1 -1
  313. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  314. package/dist/src/formats/xgmml/emit.js +12 -6
  315. package/dist/src/formats/xgmml/emit.js.map +1 -1
  316. package/dist/src/formats/xgmml/exporter.d.ts +3 -1
  317. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
  318. package/dist/src/formats/xgmml/exporter.js +22 -9
  319. package/dist/src/formats/xgmml/exporter.js.map +1 -1
  320. package/dist/src/formats/xgmml/importer.d.ts +2 -1
  321. package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
  322. package/dist/src/formats/xgmml/importer.js +31 -24
  323. package/dist/src/formats/xgmml/importer.js.map +1 -1
  324. package/dist/src/formats/xgmml/styles.d.ts +104 -0
  325. package/dist/src/formats/xgmml/styles.d.ts.map +1 -0
  326. package/dist/src/formats/xgmml/styles.js +310 -0
  327. package/dist/src/formats/xgmml/styles.js.map +1 -0
  328. package/dist/src/index.d.ts +9 -7
  329. package/dist/src/index.d.ts.map +1 -1
  330. package/dist/src/index.js +7 -7
  331. package/dist/src/index.js.map +1 -1
  332. package/dist/src/positions/codes.d.ts +31 -0
  333. package/dist/src/positions/codes.d.ts.map +1 -0
  334. package/dist/src/positions/codes.js +26 -0
  335. package/dist/src/positions/codes.js.map +1 -0
  336. package/dist/src/positions/convert.d.ts +58 -0
  337. package/dist/src/positions/convert.d.ts.map +1 -0
  338. package/dist/src/positions/convert.js +107 -0
  339. package/dist/src/positions/convert.js.map +1 -0
  340. package/dist/src/positions/extract.d.ts +27 -0
  341. package/dist/src/positions/extract.d.ts.map +1 -0
  342. package/dist/src/positions/extract.js +526 -0
  343. package/dist/src/positions/extract.js.map +1 -0
  344. package/dist/src/positions/index.d.ts +10 -0
  345. package/dist/src/positions/index.d.ts.map +1 -0
  346. package/dist/src/positions/index.js +9 -0
  347. package/dist/src/positions/index.js.map +1 -0
  348. package/dist/src/positions/types.d.ts +208 -0
  349. package/dist/src/positions/types.d.ts.map +1 -0
  350. package/dist/src/positions/types.js +10 -0
  351. package/dist/src/positions/types.js.map +1 -0
  352. package/dist/src/registry.d.ts +30 -0
  353. package/dist/src/registry.d.ts.map +1 -1
  354. package/dist/src/registry.js +130 -9
  355. package/dist/src/registry.js.map +1 -1
  356. package/dist/src/styles/annotations.d.ts +132 -0
  357. package/dist/src/styles/annotations.d.ts.map +1 -0
  358. package/dist/src/styles/annotations.js +320 -0
  359. package/dist/src/styles/annotations.js.map +1 -0
  360. package/dist/src/styles/budget.d.ts +45 -0
  361. package/dist/src/styles/budget.d.ts.map +1 -0
  362. package/dist/src/styles/budget.js +58 -0
  363. package/dist/src/styles/budget.js.map +1 -0
  364. package/dist/src/styles/canon/bends.d.ts +32 -0
  365. package/dist/src/styles/canon/bends.d.ts.map +1 -0
  366. package/dist/src/styles/canon/bends.js +74 -0
  367. package/dist/src/styles/canon/bends.js.map +1 -0
  368. package/dist/src/styles/canon/color-tables.d.ts +22 -0
  369. package/dist/src/styles/canon/color-tables.d.ts.map +1 -0
  370. package/dist/src/styles/canon/color-tables.js +369 -0
  371. package/dist/src/styles/canon/color-tables.js.map +1 -0
  372. package/dist/src/styles/canon/color.d.ts +66 -0
  373. package/dist/src/styles/canon/color.d.ts.map +1 -0
  374. package/dist/src/styles/canon/color.js +548 -0
  375. package/dist/src/styles/canon/color.js.map +1 -0
  376. package/dist/src/styles/canon/enums.d.ts +25 -0
  377. package/dist/src/styles/canon/enums.d.ts.map +1 -0
  378. package/dist/src/styles/canon/enums.js +187 -0
  379. package/dist/src/styles/canon/enums.js.map +1 -0
  380. package/dist/src/styles/canon/graphviz.d.ts +48 -0
  381. package/dist/src/styles/canon/graphviz.d.ts.map +1 -0
  382. package/dist/src/styles/canon/graphviz.js +160 -0
  383. package/dist/src/styles/canon/graphviz.js.map +1 -0
  384. package/dist/src/styles/canon/index.d.ts +13 -0
  385. package/dist/src/styles/canon/index.d.ts.map +1 -0
  386. package/dist/src/styles/canon/index.js +13 -0
  387. package/dist/src/styles/canon/index.js.map +1 -0
  388. package/dist/src/styles/canon/number.d.ts +59 -0
  389. package/dist/src/styles/canon/number.d.ts.map +1 -0
  390. package/dist/src/styles/canon/number.js +142 -0
  391. package/dist/src/styles/canon/number.js.map +1 -0
  392. package/dist/src/styles/canon/site.d.ts +51 -0
  393. package/dist/src/styles/canon/site.d.ts.map +1 -0
  394. package/dist/src/styles/canon/site.js +63 -0
  395. package/dist/src/styles/canon/site.js.map +1 -0
  396. package/dist/src/styles/canon/text.d.ts +61 -0
  397. package/dist/src/styles/canon/text.d.ts.map +1 -0
  398. package/dist/src/styles/canon/text.js +199 -0
  399. package/dist/src/styles/canon/text.js.map +1 -0
  400. package/dist/src/styles/codes.d.ts +95 -0
  401. package/dist/src/styles/codes.d.ts.map +1 -0
  402. package/dist/src/styles/codes.js +97 -0
  403. package/dist/src/styles/codes.js.map +1 -0
  404. package/dist/src/styles/cyjs/cascade.d.ts +134 -0
  405. package/dist/src/styles/cyjs/cascade.d.ts.map +1 -0
  406. package/dist/src/styles/cyjs/cascade.js +2252 -0
  407. package/dist/src/styles/cyjs/cascade.js.map +1 -0
  408. package/dist/src/styles/cyjs/defaults-table.d.ts +25 -0
  409. package/dist/src/styles/cyjs/defaults-table.d.ts.map +1 -0
  410. package/dist/src/styles/cyjs/defaults-table.js +76 -0
  411. package/dist/src/styles/cyjs/defaults-table.js.map +1 -0
  412. package/dist/src/styles/cyjs/emit.d.ts +82 -0
  413. package/dist/src/styles/cyjs/emit.d.ts.map +1 -0
  414. package/dist/src/styles/cyjs/emit.js +790 -0
  415. package/dist/src/styles/cyjs/emit.js.map +1 -0
  416. package/dist/src/styles/cyjs/index.d.ts +13 -0
  417. package/dist/src/styles/cyjs/index.d.ts.map +1 -0
  418. package/dist/src/styles/cyjs/index.js +13 -0
  419. package/dist/src/styles/cyjs/index.js.map +1 -0
  420. package/dist/src/styles/cyjs/live.d.ts +46 -0
  421. package/dist/src/styles/cyjs/live.d.ts.map +1 -0
  422. package/dist/src/styles/cyjs/live.js +108 -0
  423. package/dist/src/styles/cyjs/live.js.map +1 -0
  424. package/dist/src/styles/cyjs/mappers.d.ts +147 -0
  425. package/dist/src/styles/cyjs/mappers.d.ts.map +1 -0
  426. package/dist/src/styles/cyjs/mappers.js +744 -0
  427. package/dist/src/styles/cyjs/mappers.js.map +1 -0
  428. package/dist/src/styles/cyjs/selector.d.ts +113 -0
  429. package/dist/src/styles/cyjs/selector.d.ts.map +1 -0
  430. package/dist/src/styles/cyjs/selector.js +611 -0
  431. package/dist/src/styles/cyjs/selector.js.map +1 -0
  432. package/dist/src/styles/cyjs/stylesheet-text.d.ts +37 -0
  433. package/dist/src/styles/cyjs/stylesheet-text.d.ts.map +1 -0
  434. package/dist/src/styles/cyjs/stylesheet-text.js +181 -0
  435. package/dist/src/styles/cyjs/stylesheet-text.js.map +1 -0
  436. package/dist/src/styles/cytoscape/emit.d.ts +125 -0
  437. package/dist/src/styles/cytoscape/emit.d.ts.map +1 -0
  438. package/dist/src/styles/cytoscape/emit.js +1025 -0
  439. package/dist/src/styles/cytoscape/emit.js.map +1 -0
  440. package/dist/src/styles/cytoscape/index.d.ts +10 -0
  441. package/dist/src/styles/cytoscape/index.d.ts.map +1 -0
  442. package/dist/src/styles/cytoscape/index.js +10 -0
  443. package/dist/src/styles/cytoscape/index.js.map +1 -0
  444. package/dist/src/styles/cytoscape/lexicon.d.ts +49 -0
  445. package/dist/src/styles/cytoscape/lexicon.d.ts.map +1 -0
  446. package/dist/src/styles/cytoscape/lexicon.js +603 -0
  447. package/dist/src/styles/cytoscape/lexicon.js.map +1 -0
  448. package/dist/src/styles/cytoscape/mappings.d.ts +171 -0
  449. package/dist/src/styles/cytoscape/mappings.d.ts.map +1 -0
  450. package/dist/src/styles/cytoscape/mappings.js +460 -0
  451. package/dist/src/styles/cytoscape/mappings.js.map +1 -0
  452. package/dist/src/styles/cytoscape/resolve.d.ts +137 -0
  453. package/dist/src/styles/cytoscape/resolve.d.ts.map +1 -0
  454. package/dist/src/styles/cytoscape/resolve.js +381 -0
  455. package/dist/src/styles/cytoscape/resolve.js.map +1 -0
  456. package/dist/src/styles/cytoscape/translate.d.ts +50 -0
  457. package/dist/src/styles/cytoscape/translate.d.ts.map +1 -0
  458. package/dist/src/styles/cytoscape/translate.js +156 -0
  459. package/dist/src/styles/cytoscape/translate.js.map +1 -0
  460. package/dist/src/styles/defaults.d.ts +90 -0
  461. package/dist/src/styles/defaults.d.ts.map +1 -0
  462. package/dist/src/styles/defaults.js +414 -0
  463. package/dist/src/styles/defaults.js.map +1 -0
  464. package/dist/src/styles/index.d.ts +15 -0
  465. package/dist/src/styles/index.d.ts.map +1 -0
  466. package/dist/src/styles/index.js +14 -0
  467. package/dist/src/styles/index.js.map +1 -0
  468. package/dist/src/styles/internal.d.ts +17 -0
  469. package/dist/src/styles/internal.d.ts.map +1 -0
  470. package/dist/src/styles/internal.js +16 -0
  471. package/dist/src/styles/internal.js.map +1 -0
  472. package/dist/src/styles/io/approximations.d.ts +24 -0
  473. package/dist/src/styles/io/approximations.d.ts.map +1 -0
  474. package/dist/src/styles/io/approximations.js +51 -0
  475. package/dist/src/styles/io/approximations.js.map +1 -0
  476. package/dist/src/styles/io/block.d.ts +166 -0
  477. package/dist/src/styles/io/block.d.ts.map +1 -0
  478. package/dist/src/styles/io/block.js +930 -0
  479. package/dist/src/styles/io/block.js.map +1 -0
  480. package/dist/src/styles/io/generic.d.ts +88 -0
  481. package/dist/src/styles/io/generic.d.ts.map +1 -0
  482. package/dist/src/styles/io/generic.js +516 -0
  483. package/dist/src/styles/io/generic.js.map +1 -0
  484. package/dist/src/styles/io/index.d.ts +8 -0
  485. package/dist/src/styles/io/index.d.ts.map +1 -0
  486. package/dist/src/styles/io/index.js +7 -0
  487. package/dist/src/styles/io/index.js.map +1 -0
  488. package/dist/src/styles/io/writer.d.ts +80 -0
  489. package/dist/src/styles/io/writer.d.ts.map +1 -0
  490. package/dist/src/styles/io/writer.js +596 -0
  491. package/dist/src/styles/io/writer.js.map +1 -0
  492. package/dist/src/styles/notes.d.ts +47 -0
  493. package/dist/src/styles/notes.d.ts.map +1 -0
  494. package/dist/src/styles/notes.js +140 -0
  495. package/dist/src/styles/notes.js.map +1 -0
  496. package/dist/src/styles/plan/classes.d.ts +31 -0
  497. package/dist/src/styles/plan/classes.d.ts.map +1 -0
  498. package/dist/src/styles/plan/classes.js +139 -0
  499. package/dist/src/styles/plan/classes.js.map +1 -0
  500. package/dist/src/styles/plan/continuous.d.ts +32 -0
  501. package/dist/src/styles/plan/continuous.d.ts.map +1 -0
  502. package/dist/src/styles/plan/continuous.js +165 -0
  503. package/dist/src/styles/plan/continuous.js.map +1 -0
  504. package/dist/src/styles/plan/discrete.d.ts +39 -0
  505. package/dist/src/styles/plan/discrete.d.ts.map +1 -0
  506. package/dist/src/styles/plan/discrete.js +127 -0
  507. package/dist/src/styles/plan/discrete.js.map +1 -0
  508. package/dist/src/styles/plan/families.d.ts +31 -0
  509. package/dist/src/styles/plan/families.d.ts.map +1 -0
  510. package/dist/src/styles/plan/families.js +95 -0
  511. package/dist/src/styles/plan/families.js.map +1 -0
  512. package/dist/src/styles/plan/features.d.ts +58 -0
  513. package/dist/src/styles/plan/features.d.ts.map +1 -0
  514. package/dist/src/styles/plan/features.js +185 -0
  515. package/dist/src/styles/plan/features.js.map +1 -0
  516. package/dist/src/styles/plan/index.d.ts +7 -0
  517. package/dist/src/styles/plan/index.d.ts.map +1 -0
  518. package/dist/src/styles/plan/index.js +7 -0
  519. package/dist/src/styles/plan/index.js.map +1 -0
  520. package/dist/src/styles/plan/plan.d.ts +71 -0
  521. package/dist/src/styles/plan/plan.d.ts.map +1 -0
  522. package/dist/src/styles/plan/plan.js +893 -0
  523. package/dist/src/styles/plan/plan.js.map +1 -0
  524. package/dist/src/styles/plan/resolve.d.ts +137 -0
  525. package/dist/src/styles/plan/resolve.d.ts.map +1 -0
  526. package/dist/src/styles/plan/resolve.js +587 -0
  527. package/dist/src/styles/plan/resolve.js.map +1 -0
  528. package/dist/src/styles/types.d.ts +702 -0
  529. package/dist/src/styles/types.d.ts.map +1 -0
  530. package/dist/src/styles/types.js +10 -0
  531. package/dist/src/styles/types.js.map +1 -0
  532. package/dist/src/styles/vocabulary.d.ts +41 -0
  533. package/dist/src/styles/vocabulary.d.ts.map +1 -0
  534. package/dist/src/styles/vocabulary.js +140 -0
  535. package/dist/src/styles/vocabulary.js.map +1 -0
  536. package/dist/src/types.d.ts +64 -1
  537. package/dist/src/types.d.ts.map +1 -1
  538. package/dist/src/types.js.map +1 -1
  539. package/dist/styles.d.ts +1 -0
  540. package/dist/styles.js +322 -0
  541. package/dist/styles.js.map +1 -0
  542. package/dist/xgmml.js +5 -4
  543. package/dist/xgmml.js.map +1 -1
  544. package/package.json +13 -2
  545. package/src/common/codes.ts +7 -0
  546. package/src/common/escape.ts +5 -2
  547. package/src/common/export.ts +179 -140
  548. package/src/common/input.ts +8 -4
  549. package/src/common/json-elements.ts +169 -38
  550. package/src/common/notes.ts +94 -0
  551. package/src/common/report.ts +41 -1
  552. package/src/common/units.ts +42 -0
  553. package/src/common/xml.ts +45 -5
  554. package/src/formats/cx/exporter.ts +95 -11
  555. package/src/formats/cx/importer.ts +126 -90
  556. package/src/formats/cx/styles.ts +304 -0
  557. package/src/formats/cx2/exporter.ts +234 -77
  558. package/src/formats/cx2/importer.ts +19 -1
  559. package/src/formats/cx2/styles.ts +29 -0
  560. package/src/formats/cys/constants.ts +3 -0
  561. package/src/formats/cys/exporter.ts +246 -60
  562. package/src/formats/cys/importer.ts +125 -9
  563. package/src/formats/cys/session.ts +6 -0
  564. package/src/formats/cys/styles.ts +254 -0
  565. package/src/formats/cys/tables.ts +117 -48
  566. package/src/formats/dot/exporter.ts +262 -126
  567. package/src/formats/dot/importer.ts +111 -20
  568. package/src/formats/dot/index.ts +1 -0
  569. package/src/formats/dot/positions.ts +77 -0
  570. package/src/formats/dot/styles.ts +1741 -0
  571. package/src/formats/gexf/exporter.ts +30 -13
  572. package/src/formats/gexf/importer.ts +308 -158
  573. package/src/formats/gexf/index.ts +10 -0
  574. package/src/formats/gexf/schema.ts +5 -0
  575. package/src/formats/gexf/styles.ts +719 -0
  576. package/src/formats/gml/exporter.ts +33 -14
  577. package/src/formats/gml/importer.ts +4 -0
  578. package/src/formats/gml/index.ts +2 -1
  579. package/src/formats/gml/positions.ts +52 -0
  580. package/src/formats/gml/styles.ts +1248 -0
  581. package/src/formats/gml/syntax.ts +173 -62
  582. package/src/formats/graphml/constants.ts +5 -0
  583. package/src/formats/graphml/exporter.ts +163 -71
  584. package/src/formats/graphml/importer.ts +119 -45
  585. package/src/formats/graphml/index.ts +1 -0
  586. package/src/formats/graphml/styles-plain.ts +236 -0
  587. package/src/formats/graphml/styles-yed.ts +1221 -0
  588. package/src/formats/graphml/styles-yfiles3.ts +573 -0
  589. package/src/formats/graphml/tree.ts +36 -20
  590. package/src/formats/graphml/yfiles.ts +89 -13
  591. package/src/formats/json/exporter.ts +76 -26
  592. package/src/formats/json/importer.ts +543 -323
  593. package/src/formats/json/positions.ts +50 -0
  594. package/src/formats/json/styles.ts +2082 -0
  595. package/src/formats/neo4j/exporter.ts +2 -1
  596. package/src/formats/pajek/exporter.ts +195 -106
  597. package/src/formats/pajek/importer.ts +78 -9
  598. package/src/formats/pajek/index.ts +2 -0
  599. package/src/formats/pajek/styles.ts +685 -0
  600. package/src/formats/pajek/syntax.ts +7 -0
  601. package/src/formats/xgmml/columns.ts +39 -9
  602. package/src/formats/xgmml/constants.ts +3 -0
  603. package/src/formats/xgmml/document.ts +54 -12
  604. package/src/formats/xgmml/emit.ts +11 -6
  605. package/src/formats/xgmml/exporter.ts +32 -13
  606. package/src/formats/xgmml/importer.ts +43 -29
  607. package/src/formats/xgmml/styles.ts +400 -0
  608. package/src/index.ts +16 -0
  609. package/src/positions/codes.ts +32 -0
  610. package/src/positions/convert.ts +123 -0
  611. package/src/positions/extract.ts +619 -0
  612. package/src/positions/index.ts +23 -0
  613. package/src/positions/types.ts +221 -0
  614. package/src/registry.ts +179 -8
  615. package/src/styles/annotations.ts +478 -0
  616. package/src/styles/budget.ts +60 -0
  617. package/src/styles/canon/bends.ts +84 -0
  618. package/src/styles/canon/color-tables.ts +386 -0
  619. package/src/styles/canon/color.ts +624 -0
  620. package/src/styles/canon/enums.ts +211 -0
  621. package/src/styles/canon/graphviz.ts +189 -0
  622. package/src/styles/canon/index.ts +13 -0
  623. package/src/styles/canon/number.ts +152 -0
  624. package/src/styles/canon/site.ts +87 -0
  625. package/src/styles/canon/text.ts +221 -0
  626. package/src/styles/codes.ts +104 -0
  627. package/src/styles/cyjs/cascade.ts +2670 -0
  628. package/src/styles/cyjs/defaults-table.ts +82 -0
  629. package/src/styles/cyjs/emit.ts +951 -0
  630. package/src/styles/cyjs/index.ts +37 -0
  631. package/src/styles/cyjs/live.ts +147 -0
  632. package/src/styles/cyjs/mappers.ts +879 -0
  633. package/src/styles/cyjs/selector.ts +778 -0
  634. package/src/styles/cyjs/stylesheet-text.ts +214 -0
  635. package/src/styles/cytoscape/emit.ts +1264 -0
  636. package/src/styles/cytoscape/index.ts +40 -0
  637. package/src/styles/cytoscape/lexicon.ts +656 -0
  638. package/src/styles/cytoscape/mappings.ts +603 -0
  639. package/src/styles/cytoscape/resolve.ts +521 -0
  640. package/src/styles/cytoscape/translate.ts +237 -0
  641. package/src/styles/defaults.ts +504 -0
  642. package/src/styles/index.ts +57 -0
  643. package/src/styles/internal.ts +17 -0
  644. package/src/styles/io/approximations.ts +47 -0
  645. package/src/styles/io/block.ts +1138 -0
  646. package/src/styles/io/generic.ts +687 -0
  647. package/src/styles/io/index.ts +18 -0
  648. package/src/styles/io/writer.ts +745 -0
  649. package/src/styles/notes.ts +165 -0
  650. package/src/styles/plan/classes.ts +166 -0
  651. package/src/styles/plan/continuous.ts +218 -0
  652. package/src/styles/plan/discrete.ts +165 -0
  653. package/src/styles/plan/families.ts +115 -0
  654. package/src/styles/plan/features.ts +234 -0
  655. package/src/styles/plan/index.ts +7 -0
  656. package/src/styles/plan/plan.ts +1129 -0
  657. package/src/styles/plan/resolve.ts +685 -0
  658. package/src/styles/types.ts +814 -0
  659. package/src/styles/vocabulary.ts +172 -0
  660. package/src/types.ts +76 -1
  661. package/dist/chunks/constants-fT3E8JYY.js.map +0 -1
  662. package/dist/chunks/escape-B62ZGM_a.js.map +0 -1
  663. package/dist/chunks/export-rKLeGQMo.js.map +0 -1
  664. package/dist/chunks/exporter-8hLNemFk.js.map +0 -1
  665. package/dist/chunks/exporter-BWwEuOPT.js.map +0 -1
  666. package/dist/chunks/exporter-CpRyHZ3H.js.map +0 -1
  667. package/dist/chunks/importer-BbNb7eNg.js.map +0 -1
  668. package/dist/chunks/importer-C98dpSH4.js.map +0 -1
  669. package/dist/chunks/importer-D794XUTe.js.map +0 -1
  670. package/dist/chunks/importer-Dz7tI8Sa.js.map +0 -1
  671. package/dist/chunks/importer-Ht7LNg8L.js.map +0 -1
  672. package/dist/chunks/importer-WrGRZb0N.js.map +0 -1
  673. package/dist/chunks/importer-xZ-3suY1.js.map +0 -1
  674. package/dist/chunks/json-elements-DKSqpNW1.js.map +0 -1
@@ -0,0 +1,2252 @@
1
+ /**
2
+ * The Cytoscape.js style engine: a stylesheet applied to the raw element JSON the way Cytoscape.js 3.34 applies it,
3
+ * giving what Cytoscape.js draws for every node and edge, and the stylesheet's rules as neutral rules.
4
+ *
5
+ * - Elements are taken as `cy.add()` takes them: nodes first, ids made text, duplicates and edges to missing nodes
6
+ * dropped, compound parents linked without cycles.
7
+ * - Comparisons read the RAW element data (a field of mixed types is compared with `===`, not as graph-io's column
8
+ * holds it), and a dotted field reads a nested path.
9
+ * - Beneath the file's rules lie Cytoscape.js's own default rules (edges 3px wide, compound parents gray rectangles,
10
+ * selected elements blue); per property the last matching rule wins; a mapper that fails resets the property to
11
+ * its Cytoscape.js default; an element's own `style` is a bypass over every rule.
12
+ * - Every selector is evaluated through indexes (class, id, value) where one test decides, so a sheet of 20,000
13
+ * per-value rules or a selector of 100,000 class tests costs one pass over the elements it names. Every step spends
14
+ * from the extraction's one counted budget.
15
+ *
16
+ * The rules: a selector a short predicate expresses exactly over graph-io's columns becomes that predicate; any other
17
+ * becomes a membership style column (`member.<n>`) with a short `has` test. A run of three or more rules that each
18
+ * test one class, one id or one value of the same field and only set values becomes ONE mapping rule over a winner
19
+ * column. A `data()` or `mapData()` mapper becomes a passthrough or continuous mapping when graph-io's column gives
20
+ * exactly Cytoscape.js's values, else the mapper's per-element values as a style column.
21
+ */
22
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
23
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
24
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
25
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
26
+ };
27
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
28
+ if (kind === "m") throw new TypeError("Private method is not writable");
29
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
30
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
31
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
32
+ };
33
+ var _Matcher_charge, _Matcher_charged, _Matcher_memo;
34
+ import { StyleBudget } from "../budget.js";
35
+ import { STYLE_ISSUE } from "../codes.js";
36
+ import { StyleNotes } from "../notes.js";
37
+ import { canonicalFor, degreeValues, evalContinuous, numberOf, plainCell } from "../plan/resolve.js";
38
+ import { CYJS_DEFAULT_STYLESHEET, CYJS_PROPERTY_DEFAULTS } from "./defaults-table.js";
39
+ import { applyCyjsMapper, CYJS_THROWS, cyjsNeutral, cyjsProperties, cyjsPropertyName, cyjsRendered, parseCyjsValue, } from "./mappers.js";
40
+ import { parseCyjsSelector } from "./selector.js";
41
+ import { parseCyjsStylesheetText } from "./stylesheet-text.js";
42
+ /**
43
+ * Whether a value is a plain object (not an array).
44
+ * @param v - the value
45
+ * @returns true for an object
46
+ */
47
+ function isObject(v) {
48
+ return v !== null && typeof v === "object" && !Array.isArray(v);
49
+ }
50
+ /**
51
+ * An id as Cytoscape.js keeps it: a finite number made text, a non-blank string as it is; null when Cytoscape.js
52
+ * refuses it.
53
+ * @param v - the value
54
+ * @returns the id, or null
55
+ */
56
+ function idText(v) {
57
+ if (typeof v === "number" && !Number.isNaN(v)) {
58
+ return String(v);
59
+ }
60
+ if (typeof v === "string" && v !== "" && !/^\s+$/.test(v)) {
61
+ return v;
62
+ }
63
+ return null;
64
+ }
65
+ /**
66
+ * The flags of an element from its JSON.
67
+ * @param json - the element
68
+ * @param edge - whether it is an edge
69
+ * @returns the selection, lock and grab flags
70
+ */
71
+ function flags(json, edge) {
72
+ const pannable = json.pannable === undefined ? edge : Boolean(json.pannable);
73
+ const grabbable = json.grabbable === undefined ? true : Boolean(json.grabbable);
74
+ return {
75
+ selected: Boolean(json.selected),
76
+ selectable: json.selectable === undefined ? true : Boolean(json.selectable),
77
+ locked: Boolean(json.locked),
78
+ grabbable: !pannable && grabbable,
79
+ };
80
+ }
81
+ /**
82
+ * An element's classes as Cytoscape.js reads them: an array's truthy items, or a string split at whitespace.
83
+ * @param v - the `classes` field
84
+ * @returns the classes
85
+ */
86
+ function classSet(v) {
87
+ const out = new Set();
88
+ let items = [];
89
+ if (Array.isArray(v)) {
90
+ items = v;
91
+ }
92
+ else if (typeof v === "string") {
93
+ items = v.split(/\s+/);
94
+ }
95
+ for (const c of items) {
96
+ if (c) {
97
+ out.add(c);
98
+ }
99
+ }
100
+ return out;
101
+ }
102
+ /**
103
+ * Each node's compound parent, as Cytoscape.js keeps it: a parent naming no node, an edge, or a descendant of the
104
+ * node itself (which would make a cycle) is dropped. Near-linear in the nodes, however deep the hierarchy.
105
+ * @param nodes - the core's nodes, in order; a dropped parent is recorded in their overrides
106
+ * @param ids - the index of each node id (edge ids map to -1)
107
+ * @returns each node's parent index (-1 for none) and each node's children
108
+ */
109
+ function parentsOf(nodes, ids) {
110
+ const parent = new Int32Array(nodes.length).fill(-1);
111
+ const children = nodes.map(() => []);
112
+ // root[x] leads to the root of x's parent chain; paths are halved as they are walked
113
+ const root = Int32Array.from(nodes, (_n, i) => i);
114
+ const rootOf = (x) => {
115
+ while (root[x] !== x) {
116
+ root[x] = root[root[x]];
117
+ x = root[x];
118
+ }
119
+ return x;
120
+ };
121
+ for (let i = 0; i < nodes.length; i++) {
122
+ const raw = nodes[i].data.parent;
123
+ if (raw === undefined || raw === null) {
124
+ continue;
125
+ }
126
+ const text = typeof raw === "number" && !Number.isNaN(raw) ? String(raw) : raw;
127
+ const p = typeof text === "string" ? ids.get(text) : undefined;
128
+ if (p === undefined || p < 0) {
129
+ nodes[i].overrides.set("parent", undefined);
130
+ continue;
131
+ }
132
+ if (typeof raw === "number") {
133
+ nodes[i].overrides.set("parent", text);
134
+ }
135
+ // a node never becomes its own ancestor: node i has no parent yet, so it is an ancestor of p exactly when it
136
+ // is the root of p's chain, found in near-constant time through the union-find roots
137
+ if (rootOf(p) === i) {
138
+ nodes[i].overrides.set("parent", undefined);
139
+ continue;
140
+ }
141
+ parent[i] = p;
142
+ root[i] = p;
143
+ children[p].push(i);
144
+ }
145
+ return { parent, children };
146
+ }
147
+ /**
148
+ * The elements a Cytoscape.js core holds after `cy.add(elements)`.
149
+ * @param elements - an array of element JSON, or `{ nodes, edges }`
150
+ * @returns the elements and their links
151
+ */
152
+ export function cyjsGraph(elements) {
153
+ const { nodeJson, edgeJson } = elementGroups(elements);
154
+ const ids = new Map();
155
+ const make = elementMaker(ids);
156
+ const nodes = [];
157
+ for (const json of nodeJson) {
158
+ const e = make(json, false, new Map());
159
+ if (e !== null) {
160
+ ids.set(e.id, nodes.length);
161
+ nodes.push(e);
162
+ }
163
+ }
164
+ const edges = [];
165
+ const src = [];
166
+ const tgt = [];
167
+ const edgeIds = new Set();
168
+ for (const json of edgeJson) {
169
+ const overrides = new Map();
170
+ const e = make(json, true, overrides);
171
+ const ends = e === null || edgeIds.has(e.id) ? null : edgeEnds(e, ids, overrides);
172
+ if (e !== null && ends !== null) {
173
+ edgeIds.add(e.id);
174
+ edges.push(e);
175
+ src.push(ends[0]);
176
+ tgt.push(ends[1]);
177
+ }
178
+ }
179
+ for (const id of edgeIds) {
180
+ ids.set(id, -1);
181
+ }
182
+ const { parent, children } = parentsOf(nodes, ids);
183
+ const incident = nodes.map(() => []);
184
+ for (let e = 0; e < edges.length; e++) {
185
+ incident[src[e]].push(e);
186
+ if (src[e] !== tgt[e]) {
187
+ incident[tgt[e]].push(e);
188
+ }
189
+ }
190
+ return {
191
+ nodes,
192
+ edges,
193
+ source: Int32Array.from(src),
194
+ target: Int32Array.from(tgt),
195
+ parent,
196
+ children,
197
+ incident,
198
+ };
199
+ }
200
+ /**
201
+ * The node and edge JSON of `cy.add(elements)`: an array's items by their `group`, else an edge when they name a
202
+ * source and a target; a `{ nodes, edges }` object's by where they are.
203
+ * @param elements - an array of element JSON, or `{ nodes, edges }`
204
+ * @returns the node and edge JSON, in order
205
+ */
206
+ function elementGroups(elements) {
207
+ const nodeJson = [];
208
+ const edgeJson = [];
209
+ const take = (item, group) => {
210
+ const g = groupOf(item, group);
211
+ if (g === "nodes") {
212
+ nodeJson.push(item);
213
+ }
214
+ else if (g === "edges") {
215
+ edgeJson.push(item);
216
+ }
217
+ };
218
+ if (Array.isArray(elements)) {
219
+ for (const item of elements) {
220
+ take(item, undefined);
221
+ }
222
+ }
223
+ else if (isObject(elements)) {
224
+ for (const item of Array.isArray(elements.nodes) ? elements.nodes : []) {
225
+ take(item, "nodes");
226
+ }
227
+ for (const item of Array.isArray(elements.edges) ? elements.edges : []) {
228
+ take(item, "edges");
229
+ }
230
+ }
231
+ return { nodeJson, edgeJson };
232
+ }
233
+ /**
234
+ * The group an element JSON is added to: the one its place gives, else its own `group`, else an edge when its data
235
+ * names a source and a target.
236
+ * @param item - the element JSON
237
+ * @param group - the group its place gives, or undefined
238
+ * @returns the group, or undefined for no element
239
+ */
240
+ function groupOf(item, group) {
241
+ if (!isObject(item)) {
242
+ return undefined;
243
+ }
244
+ const data = item.data ?? {};
245
+ if (!isObject(data)) {
246
+ return undefined;
247
+ }
248
+ const given = group ?? item.group;
249
+ if (given !== undefined && given !== null) {
250
+ return given;
251
+ }
252
+ const ends = data.source !== undefined && data.source !== null && data.target !== undefined && data.target !== null;
253
+ return ends ? "edges" : "nodes";
254
+ }
255
+ /**
256
+ * Makes the elements of one core: an element without an id gets a generated one; one whose id is taken or not an id
257
+ * is dropped.
258
+ * @param ids - the ids taken so far, by node index
259
+ * @returns the maker: the element of a JSON, or null when it is dropped
260
+ */
261
+ function elementMaker(ids) {
262
+ let generated = 0;
263
+ return (json, edge, overrides) => {
264
+ const data = isObject(json.data) ? json.data : {};
265
+ let id;
266
+ if (data.id === undefined) {
267
+ id = `${String.fromCodePoint(0)}generated-${String(generated++)}`;
268
+ overrides.set("id", id);
269
+ }
270
+ else {
271
+ id = idText(data.id);
272
+ if (id === null || ids.has(id)) {
273
+ return null;
274
+ }
275
+ if (typeof data.id === "number") {
276
+ overrides.set("id", id);
277
+ }
278
+ }
279
+ return { json, data, overrides, id, classes: classSet(json.classes), ...flags(json, edge) };
280
+ };
281
+ }
282
+ /**
283
+ * An edge's source and target nodes; a number endpoint is read as its text.
284
+ * @param e - the edge
285
+ * @param ids - the node ids
286
+ * @param overrides - the edge's data as Cytoscape.js rewrites it
287
+ * @returns the two node indexes, or null when an endpoint names no node
288
+ */
289
+ function edgeEnds(e, ids, overrides) {
290
+ const ends = [];
291
+ for (const field of ["source", "target"]) {
292
+ const raw = e.data[field];
293
+ const text = typeof raw === "number" && !Number.isNaN(raw) ? String(raw) : raw;
294
+ if (typeof raw === "number") {
295
+ overrides.set(field, text);
296
+ }
297
+ const at = typeof text === "string" ? ids.get(text) : undefined;
298
+ if (at !== undefined) {
299
+ ends.push(at);
300
+ }
301
+ }
302
+ return ends.length === 2 ? [ends[0], ends[1]] : null;
303
+ }
304
+ /**
305
+ * A data field as a selector reads it (`ele.data(field)`): the field itself, else a dotted path walked step by step.
306
+ * @param e - the element
307
+ * @param field - the field
308
+ * @returns the value, or undefined
309
+ */
310
+ function selectorField(e, field) {
311
+ if (e.overrides.has(field)) {
312
+ return e.overrides.get(field);
313
+ }
314
+ const direct = e.data[field];
315
+ if (direct !== undefined || !field.includes(".")) {
316
+ return direct;
317
+ }
318
+ let v = e.data;
319
+ const path = field.split(".");
320
+ let k = 0;
321
+ while (v !== null && v !== undefined && k < path.length) {
322
+ v = v[path[k++]];
323
+ }
324
+ return k === path.length ? v : undefined;
325
+ }
326
+ /**
327
+ * An element's data as a mapper reads it, with Cytoscape.js's rewrites of id, endpoints and parent.
328
+ * @param e - the element
329
+ * @returns an object to read fields from
330
+ */
331
+ function mapperData(e) {
332
+ if (e.overrides.size === 0) {
333
+ return e.data;
334
+ }
335
+ return new Proxy(e.data, {
336
+ get: (target, key) => typeof key === "string" && e.overrides.has(key)
337
+ ? e.overrides.get(key)
338
+ : target[key],
339
+ });
340
+ }
341
+ /**
342
+ * The entries of a stylesheet given as JSON (an array of `{ selector, style }`) or as text.
343
+ * @param style - the stylesheet
344
+ * @param notes - where problems are noted
345
+ * @returns the entries in order
346
+ */
347
+ function sheetEntries(style, notes) {
348
+ if (typeof style === "string") {
349
+ const { entries, stop } = parseCyjsStylesheetText(style);
350
+ if (stop !== null) {
351
+ notes.add(STYLE_ISSUE.UNREADABLE, null, "stylesheet", { sample: stop });
352
+ }
353
+ return entries;
354
+ }
355
+ if (!Array.isArray(style)) {
356
+ return [];
357
+ }
358
+ const out = [];
359
+ for (const item of style) {
360
+ if (!isObject(item)) {
361
+ continue;
362
+ }
363
+ const props = item.style ?? item.css;
364
+ const properties = [];
365
+ if (isObject(props)) {
366
+ for (const name of Object.keys(props)) {
367
+ properties.push([name, props[name]]);
368
+ }
369
+ }
370
+ out.push({ selector: item.selector, properties, dashOnly: false });
371
+ }
372
+ return out;
373
+ }
374
+ // ============================================================ matching
375
+ /** The most nested combinators a selector may hold before it is noted and matched to nothing. */
376
+ const MAX_SELECTOR_NESTING = 64;
377
+ /**
378
+ * How deep a query nests.
379
+ * @param q - the query
380
+ * @param depth - the depth so far
381
+ * @returns the depth, capped just above the limit
382
+ */
383
+ function nesting(q, depth = 0) {
384
+ if (depth > MAX_SELECTOR_NESTING) {
385
+ return depth;
386
+ }
387
+ let max = depth;
388
+ for (const c of q.checks) {
389
+ for (const sub of subQueries(c)) {
390
+ max = Math.max(max, nesting(sub, depth + 1));
391
+ if (max > MAX_SELECTOR_NESTING) {
392
+ return max;
393
+ }
394
+ }
395
+ }
396
+ return max;
397
+ }
398
+ /**
399
+ * The queries a check holds.
400
+ * @param c - the check
401
+ * @returns its sub-queries
402
+ */
403
+ function subQueries(c) {
404
+ switch (c.type) {
405
+ case "child":
406
+ case "parent":
407
+ return [c.parent, c.child];
408
+ case "descendant":
409
+ case "ancestor":
410
+ return [c.ancestor, c.descendant];
411
+ case "split":
412
+ return [c.left, c.right, c.subject];
413
+ case "directedEdge":
414
+ case "nodeSource":
415
+ case "nodeTarget":
416
+ return [c.source, c.target];
417
+ case "undirectedEdge":
418
+ return [c.nodes[0], c.nodes[1]];
419
+ case "nodeNeighbor":
420
+ return [c.node, c.neighbor];
421
+ default:
422
+ return [];
423
+ }
424
+ }
425
+ /**
426
+ * Cytoscape.js's comparison of a field with a selector's value.
427
+ * @param field - the element's value
428
+ * @param op - the base operator
429
+ * @param not - the `!` flag
430
+ * @param ci - the `@` flag
431
+ * @param value - the selector's value
432
+ * @returns whether it matches
433
+ */
434
+ function valCmp(field, op, not, ci, value) {
435
+ let a = field;
436
+ let b = value;
437
+ const isFieldStr = typeof field === "string";
438
+ const isFieldNum = typeof field === "number" && !Number.isNaN(field);
439
+ let fs = null;
440
+ let vs = null;
441
+ if (isFieldStr || typeof value === "string" || ci) {
442
+ fs = !isFieldStr && !isFieldNum ? "" : String(field);
443
+ vs = String(value);
444
+ }
445
+ if (ci && fs !== null && vs !== null) {
446
+ fs = fs.toLowerCase();
447
+ vs = vs.toLowerCase();
448
+ a = fs;
449
+ b = vs;
450
+ }
451
+ let m = false;
452
+ let ineq = false;
453
+ switch (op) {
454
+ case "*=":
455
+ m = fs !== null && vs !== null && fs.includes(vs);
456
+ break;
457
+ case "$=":
458
+ m = fs !== null && vs !== null && fs.endsWith(vs);
459
+ break;
460
+ case "^=":
461
+ m = fs !== null && vs !== null && fs.startsWith(vs);
462
+ break;
463
+ case "=":
464
+ m = a === b;
465
+ break;
466
+ case ">":
467
+ ineq = true;
468
+ m = a > b;
469
+ break;
470
+ case ">=":
471
+ ineq = true;
472
+ m = a >= b;
473
+ break;
474
+ case "<":
475
+ ineq = true;
476
+ m = a < b;
477
+ break;
478
+ case "<=":
479
+ ineq = true;
480
+ m = a <= b;
481
+ break;
482
+ default:
483
+ break;
484
+ }
485
+ if (not && ((field !== null && field !== undefined) || !ineq)) {
486
+ m = !m;
487
+ }
488
+ return m;
489
+ }
490
+ /** The checks of an element's place in the graph: its parents, children and edges. */
491
+ const STRUCTURE_CHECKS = new Set([
492
+ "child",
493
+ "parent",
494
+ "descendant",
495
+ "ancestor",
496
+ "split",
497
+ "directedEdge",
498
+ "undirectedEdge",
499
+ "nodeSource",
500
+ "nodeTarget",
501
+ "nodeNeighbor",
502
+ ]);
503
+ /** States whose value changes while Cytoscape.js runs; they are evaluated as at load and noted. */
504
+ const RUNTIME_STATES = new Set([
505
+ "active",
506
+ "inactive",
507
+ "grabbed",
508
+ "free",
509
+ "animated",
510
+ "unanimated",
511
+ "visible",
512
+ "hidden",
513
+ "transparent",
514
+ "backgrounding",
515
+ "nonbackgrounding",
516
+ ]);
517
+ /** Thrown inside a selector match when the counted budget runs out partway through it. */
518
+ class BudgetStop extends Error {
519
+ }
520
+ /** How many units of work a match does between checks of the budget and the signal. */
521
+ const CHECK_EVERY = 4096;
522
+ /** Evaluates selectors over one graph. */
523
+ class Matcher {
524
+ constructor(g, notes) {
525
+ this.g = g;
526
+ this.notes = notes;
527
+ this.work = 0;
528
+ /** Where the work is charged while a match runs; null between matches. */
529
+ _Matcher_charge.set(this, null);
530
+ _Matcher_charged.set(this, 0);
531
+ /**
532
+ * The answers of nested sub-queries for one match, per element: 0 unknown, 1 true, 2 false. Each sub-query is
533
+ * then evaluated at most once per element, so a nested compound selector costs polynomial, not exponential, time.
534
+ */
535
+ _Matcher_memo.set(this, { node: new Map(), edge: new Map() });
536
+ const n = g.nodes.length;
537
+ this.degree = new Int32Array(n);
538
+ this.indegree = new Int32Array(n);
539
+ this.outdegree = new Int32Array(n);
540
+ for (let e = 0; e < g.edges.length; e++) {
541
+ const s = g.source[e];
542
+ const t = g.target[e];
543
+ this.degree[s] += s === t ? 2 : 1;
544
+ if (s !== t) {
545
+ this.degree[t]++;
546
+ }
547
+ this.outdegree[s]++;
548
+ this.indegree[t]++;
549
+ }
550
+ }
551
+ /**
552
+ * Whether an element matches a query.
553
+ * @param q - the query
554
+ * @param kind - the element's kind
555
+ * @param i - the element
556
+ * @returns true when every check matches
557
+ */
558
+ query(q, kind, i) {
559
+ for (const c of q.checks) {
560
+ this.work++;
561
+ if (__classPrivateFieldGet(this, _Matcher_charge, "f") !== null && this.work - __classPrivateFieldGet(this, _Matcher_charged, "f") >= CHECK_EVERY) {
562
+ this.settle();
563
+ }
564
+ if (!this.check(c, kind, i)) {
565
+ return false;
566
+ }
567
+ }
568
+ return true;
569
+ }
570
+ /**
571
+ * Starts one selector match: its work is charged to the budget as it runs, and the sub-query answers are fresh.
572
+ * @param kind - the target the work is charged to
573
+ * @param budget - the counted budget
574
+ * @param signal - cancels the match
575
+ */
576
+ begin(kind, budget, signal) {
577
+ __classPrivateFieldSet(this, _Matcher_charge, { kind, budget, signal }, "f");
578
+ __classPrivateFieldSet(this, _Matcher_charged, this.work, "f");
579
+ __classPrivateFieldGet(this, _Matcher_memo, "f").node.clear();
580
+ __classPrivateFieldGet(this, _Matcher_memo, "f").edge.clear();
581
+ }
582
+ /** Ends a match: its remaining work is charged (never throwing) and its sub-query answers are dropped. */
583
+ end() {
584
+ const charge = __classPrivateFieldGet(this, _Matcher_charge, "f");
585
+ __classPrivateFieldSet(this, _Matcher_charge, null, "f");
586
+ charge?.budget.spend(charge.kind, this.work - __classPrivateFieldGet(this, _Matcher_charged, "f"));
587
+ __classPrivateFieldSet(this, _Matcher_charged, this.work, "f");
588
+ __classPrivateFieldGet(this, _Matcher_memo, "f").node.clear();
589
+ __classPrivateFieldGet(this, _Matcher_memo, "f").edge.clear();
590
+ }
591
+ /**
592
+ * Charges the work done since the last charge; throws BudgetStop once the budget is exhausted.
593
+ * @throws BudgetStop - when the target's budget is exhausted
594
+ */
595
+ settle() {
596
+ const charge = __classPrivateFieldGet(this, _Matcher_charge, "f");
597
+ if (charge === null) {
598
+ return;
599
+ }
600
+ charge.budget.spend(charge.kind, this.work - __classPrivateFieldGet(this, _Matcher_charged, "f"));
601
+ __classPrivateFieldSet(this, _Matcher_charged, this.work, "f");
602
+ charge.signal?.throwIfAborted();
603
+ if (charge.budget.exhausted(charge.kind)) {
604
+ throw new BudgetStop();
605
+ }
606
+ }
607
+ /**
608
+ * Whether an element matches a nested sub-query, remembered for the rest of the match.
609
+ * @param q - the sub-query
610
+ * @param kind - the element's kind
611
+ * @param i - the element
612
+ * @returns true when every check matches
613
+ */
614
+ sub(q, kind, i) {
615
+ const memo = __classPrivateFieldGet(this, _Matcher_memo, "f")[kind];
616
+ let seen = memo.get(q);
617
+ if (seen === undefined) {
618
+ seen = new Uint8Array(kind === "node" ? this.g.nodes.length : this.g.edges.length);
619
+ memo.set(q, seen);
620
+ }
621
+ if (seen[i] !== 0) {
622
+ return seen[i] === 1;
623
+ }
624
+ const m = this.query(q, kind, i);
625
+ seen[i] = m ? 1 : 2;
626
+ return m;
627
+ }
628
+ /**
629
+ * Whether an element matches one check.
630
+ * @param c - the check
631
+ * @param kind - the element's kind
632
+ * @param i - the element
633
+ * @returns true when it matches
634
+ */
635
+ check(c, kind, i) {
636
+ return STRUCTURE_CHECKS.has(c.type) ? this.structureCheck(c, kind, i) : this.elementCheck(c, kind, i);
637
+ }
638
+ /**
639
+ * Whether an element matches a check of its own: its group, state, id, classes or data.
640
+ * @param c - the check
641
+ * @param kind - the element's kind
642
+ * @param i - the element
643
+ * @returns true when it matches
644
+ */
645
+ elementCheck(c, kind, i) {
646
+ const { g } = this;
647
+ const e = kind === "node" ? g.nodes[i] : g.edges[i];
648
+ switch (c.type) {
649
+ case "group":
650
+ return c.value === "*" || c.value === `${kind}s`;
651
+ case "state":
652
+ return this.state(c.value, kind, i, e);
653
+ case "id":
654
+ return e.id === c.value;
655
+ case "class":
656
+ return e.classes.has(c.value);
657
+ case "exist":
658
+ return selectorField(e, c.field) !== undefined;
659
+ case "bool": {
660
+ const v = selectorField(e, c.field);
661
+ if (c.op === "?") {
662
+ return Boolean(v);
663
+ }
664
+ return c.op === "!" ? !v : v === undefined;
665
+ }
666
+ case "compare":
667
+ return valCmp(selectorField(e, c.field), c.op, c.not, c.ci, c.value);
668
+ case "meta": {
669
+ const v = kind === "node" ? this[c.field][i] : undefined;
670
+ return valCmp(v, c.op, c.not, c.ci, c.value);
671
+ }
672
+ case "true":
673
+ return true;
674
+ default:
675
+ return false;
676
+ }
677
+ }
678
+ /**
679
+ * Whether an element matches a check of its place in the graph: its parents, children and edges.
680
+ * @param c - the check
681
+ * @param kind - the element's kind
682
+ * @param i - the element
683
+ * @returns true when it matches
684
+ */
685
+ structureCheck(c, kind, i) {
686
+ const { g } = this;
687
+ switch (c.type) {
688
+ case "child":
689
+ return (this.sub(c.child, kind, i) &&
690
+ kind === "node" &&
691
+ g.parent[i] >= 0 &&
692
+ this.sub(c.parent, "node", g.parent[i]));
693
+ case "parent":
694
+ return (this.sub(c.parent, kind, i) &&
695
+ kind === "node" &&
696
+ g.children[i].some((k) => this.sub(c.child, "node", k)));
697
+ case "descendant":
698
+ return this.sub(c.descendant, kind, i) && kind === "node" && this.someAncestor(i, c.ancestor);
699
+ case "ancestor":
700
+ return this.sub(c.ancestor, kind, i) && kind === "node" && this.someDescendant(i, c.descendant);
701
+ case "split":
702
+ return this.sub(c.subject, kind, i) && this.sub(c.left, kind, i) && this.sub(c.right, kind, i);
703
+ case "directedEdge":
704
+ return (kind === "edge" &&
705
+ this.sub(c.source, "node", g.source[i]) &&
706
+ this.sub(c.target, "node", g.target[i]));
707
+ case "undirectedEdge": {
708
+ if (kind !== "edge") {
709
+ return false;
710
+ }
711
+ const [a, b] = c.nodes;
712
+ const s = g.source[i];
713
+ const t = g.target[i];
714
+ return ((this.sub(a, "node", s) && this.sub(b, "node", t)) ||
715
+ (this.sub(b, "node", s) && this.sub(a, "node", t)));
716
+ }
717
+ case "nodeSource":
718
+ return (kind === "node" &&
719
+ this.sub(c.source, kind, i) &&
720
+ g.incident[i].some((ed) => g.source[ed] === i && this.sub(c.target, "node", g.target[ed])));
721
+ case "nodeTarget":
722
+ return (kind === "node" &&
723
+ this.sub(c.target, kind, i) &&
724
+ g.incident[i].some((ed) => g.target[ed] === i && this.sub(c.source, "node", g.source[ed])));
725
+ case "nodeNeighbor":
726
+ return (kind === "node" &&
727
+ this.sub(c.node, kind, i) &&
728
+ g.incident[i].some((ed) => {
729
+ const other = g.source[ed] === i ? g.target[ed] : g.source[ed];
730
+ return this.sub(c.neighbor, "node", other);
731
+ }));
732
+ default:
733
+ return false;
734
+ }
735
+ }
736
+ /**
737
+ * Whether an ancestor of a node matches a query (cycle-safe: parents never form a cycle).
738
+ * @param i - the node
739
+ * @param q - the query
740
+ * @returns true when one does
741
+ */
742
+ someAncestor(i, q) {
743
+ for (let a = this.g.parent[i]; a >= 0; a = this.g.parent[a]) {
744
+ if (this.sub(q, "node", a)) {
745
+ return true;
746
+ }
747
+ }
748
+ return false;
749
+ }
750
+ /**
751
+ * Whether a descendant of a node matches a query, walked without recursion.
752
+ * @param i - the node
753
+ * @param q - the query
754
+ * @returns true when one does
755
+ */
756
+ someDescendant(i, q) {
757
+ const stack = [...this.g.children[i]];
758
+ while (stack.length > 0) {
759
+ const k = stack.pop();
760
+ if (this.sub(q, "node", k)) {
761
+ return true;
762
+ }
763
+ for (const c of this.g.children[k]) {
764
+ stack.push(c);
765
+ }
766
+ }
767
+ return false;
768
+ }
769
+ /**
770
+ * A state selector, evaluated as at load.
771
+ * @param s - the state
772
+ * @param kind - the element's kind
773
+ * @param i - the element
774
+ * @param e - the element
775
+ * @returns whether the element is in the state
776
+ */
777
+ state(s, kind, i, e) {
778
+ const { g } = this;
779
+ if (RUNTIME_STATES.has(s)) {
780
+ this.notes.add(STYLE_ISSUE.STATE_ASSUMED, kind, `:${s}`, { sample: `:${s}` });
781
+ }
782
+ const node = kind === "node";
783
+ switch (s) {
784
+ case "selected":
785
+ return e.selected;
786
+ case "unselected":
787
+ return !e.selected;
788
+ case "selectable":
789
+ return e.selectable;
790
+ case "unselectable":
791
+ return !e.selectable;
792
+ case "locked":
793
+ return e.locked;
794
+ case "unlocked":
795
+ return !e.locked;
796
+ case "grabbable":
797
+ return e.grabbable;
798
+ case "ungrabbable":
799
+ return !e.grabbable;
800
+ case "free":
801
+ case "inside":
802
+ case "unanimated":
803
+ case "inactive":
804
+ case "nonbackgrounding":
805
+ case "visible":
806
+ return true;
807
+ case "parent":
808
+ return node && g.children[i].length > 0;
809
+ case "childless":
810
+ return node && g.children[i].length === 0;
811
+ case "child":
812
+ case "nonorphan":
813
+ return node && g.parent[i] >= 0;
814
+ case "orphan":
815
+ return node && g.parent[i] < 0;
816
+ case "compound":
817
+ return node
818
+ ? g.children[i].length > 0
819
+ : g.children[g.source[i]].length > 0 || g.children[g.target[i]].length > 0;
820
+ case "loop":
821
+ return !node && g.source[i] === g.target[i];
822
+ case "simple":
823
+ return !node && g.source[i] !== g.target[i];
824
+ default:
825
+ return false;
826
+ }
827
+ }
828
+ }
829
+ _Matcher_charge = new WeakMap(), _Matcher_charged = new WeakMap(), _Matcher_memo = new WeakMap();
830
+ /** Indexes of one target's elements: by class, by id, and by value per field (built on first use). */
831
+ class Indexes {
832
+ constructor(elements, spend) {
833
+ this.elements = elements;
834
+ this.spend = spend;
835
+ this.byClass = new Map();
836
+ this.byId = new Map();
837
+ this.byValue = new Map();
838
+ /** The last stamp handed out. */
839
+ this.stamp = 0;
840
+ this.marks = new Int32Array(elements.length);
841
+ for (let i = 0; i < elements.length; i++) {
842
+ for (const c of elements[i].classes) {
843
+ let list = this.byClass.get(c);
844
+ if (list === undefined) {
845
+ list = [];
846
+ this.byClass.set(c, list);
847
+ }
848
+ list.push(i);
849
+ }
850
+ if (!this.byId.has(elements[i].id)) {
851
+ this.byId.set(elements[i].id, i);
852
+ }
853
+ }
854
+ spend(elements.length);
855
+ }
856
+ /**
857
+ * The elements whose field is `===` a value.
858
+ * @param field - the field
859
+ * @param value - the value
860
+ * @returns the element indexes
861
+ */
862
+ equal(field, value) {
863
+ let m = this.byValue.get(field);
864
+ if (m === undefined) {
865
+ m = new Map();
866
+ for (let i = 0; i < this.elements.length; i++) {
867
+ const v = selectorField(this.elements[i], field);
868
+ if (typeof v !== "string" && typeof v !== "number") {
869
+ continue;
870
+ }
871
+ const k = `${typeof v}:${String(v)}`;
872
+ let list = m.get(k);
873
+ if (list === undefined) {
874
+ list = [];
875
+ m.set(k, list);
876
+ }
877
+ list.push(i);
878
+ }
879
+ this.byValue.set(field, m);
880
+ this.spend(this.elements.length);
881
+ }
882
+ if (typeof value === "number" && Number.isNaN(value)) {
883
+ return [];
884
+ }
885
+ return m.get(`${typeof value}:${String(value)}`) ?? [];
886
+ }
887
+ }
888
+ /**
889
+ * The candidates of one query for a target: the element list of its most selective indexed check, or null when
890
+ * every element must be tested.
891
+ * @param q - the query
892
+ * @param kind - the target
893
+ * @param ix - the target's indexes
894
+ * @returns the candidates, or null
895
+ */
896
+ function candidates(q, kind, ix) {
897
+ let best = null;
898
+ for (const c of q.checks) {
899
+ let list = null;
900
+ if (c.type === "group" && c.value !== "*" && c.value !== `${kind}s`) {
901
+ return [];
902
+ }
903
+ if (c.type === "class") {
904
+ list = ix.byClass.get(c.value) ?? [];
905
+ }
906
+ else if (c.type === "id") {
907
+ const at = ix.byId.get(c.value);
908
+ list = at === undefined ? [] : [at];
909
+ }
910
+ else if (c.type === "compare" && c.op === "=" && !c.not && !c.ci) {
911
+ list = ix.equal(c.field, c.value);
912
+ }
913
+ if (list !== null && (best === null || list.length < best.length)) {
914
+ best = list;
915
+ }
916
+ }
917
+ return best;
918
+ }
919
+ const POSITIONS = new Map([
920
+ ["top,left", "top-left"],
921
+ ["top,center", "top"],
922
+ ["top,right", "top-right"],
923
+ ["center,left", "left"],
924
+ ["center,center", "center"],
925
+ ["center,right", "right"],
926
+ ["bottom,left", "bottom-left"],
927
+ ["bottom,center", "bottom"],
928
+ ["bottom,right", "bottom-right"],
929
+ ]);
930
+ /**
931
+ * Applies a Cytoscape.js stylesheet to its elements as Cytoscape.js 3.34 does.
932
+ * @param input - the elements, the stylesheet, the graph and the options
933
+ * @returns what is drawn per element and the stylesheet's rules, per target
934
+ */
935
+ export function evaluateCytoscapeJs(input) {
936
+ const notes = input.notes ?? new StyleNotes();
937
+ const budget = input.budget ?? new StyleBudget();
938
+ const graph = cyjsGraph(input.elements);
939
+ const sheet = [];
940
+ if (input.toolDefaults !== false) {
941
+ CYJS_DEFAULT_STYLESHEET.forEach((d, k) => {
942
+ sheet.push({
943
+ index: k - CYJS_DEFAULT_STYLESHEET.length,
944
+ tool: true,
945
+ text: d.selector,
946
+ selector: parseCyjsSelector(d.selector),
947
+ properties: Object.entries(d.style),
948
+ dashOnly: true,
949
+ });
950
+ });
951
+ }
952
+ const raw = sheetEntries(input.style, notes);
953
+ let invalid = 0;
954
+ let deep = 0;
955
+ raw.forEach((r, k) => {
956
+ let selector = parseCyjsSelector(r.selector);
957
+ if (selector.invalid) {
958
+ invalid++;
959
+ }
960
+ if (selector.queries.some((q) => nesting(q) > MAX_SELECTOR_NESTING)) {
961
+ deep++;
962
+ selector = { queries: [], invalid: true };
963
+ }
964
+ sheet.push({
965
+ index: k,
966
+ tool: false,
967
+ text: typeof r.selector === "string" ? r.selector : "",
968
+ selector,
969
+ properties: r.properties,
970
+ dashOnly: r.dashOnly,
971
+ });
972
+ });
973
+ if (invalid > 0) {
974
+ notes.add(STYLE_ISSUE.SELECTOR, null, "selector", { count: invalid, sample: "invalid" });
975
+ }
976
+ if (deep > 0) {
977
+ notes.add(STYLE_ISSUE.SELECTOR, null, "selector", { count: deep, sample: "nested too deep" });
978
+ }
979
+ const matcher = new Matcher(graph, notes);
980
+ const node = evaluateTarget("node", graph, sheet, matcher, input, notes, budget);
981
+ const edge = evaluateTarget("edge", graph, sheet, matcher, input, notes, budget);
982
+ return { node, edge, graph };
983
+ }
984
+ /**
985
+ * The order of the output: for each output index, the core's element (or -1).
986
+ * @param kind - the target
987
+ * @param graph - the core's elements
988
+ * @param snapshot - the graph, when given
989
+ * @param notes - where problems are noted
990
+ * @returns the core element of each output index
991
+ */
992
+ function outputOrder(kind, graph, snapshot, notes) {
993
+ const els = kind === "node" ? graph.nodes : graph.edges;
994
+ if (snapshot === undefined) {
995
+ return Int32Array.from(els, (_e, i) => i);
996
+ }
997
+ if (kind === "node") {
998
+ const order = new Int32Array(snapshot.nodeCount).fill(-1);
999
+ for (let i = 0; i < els.length; i++) {
1000
+ const at = snapshotIndex(snapshot, els[i].id);
1001
+ if (at >= 0 && order[at] < 0) {
1002
+ order[at] = i;
1003
+ }
1004
+ }
1005
+ return order;
1006
+ }
1007
+ const order = new Int32Array(snapshot.edgeCount).fill(-1);
1008
+ const nodeAt = outputOrder("node", graph, snapshot, notes);
1009
+ const coreToSnap = new Int32Array(graph.nodes.length).fill(-1);
1010
+ nodeAt.forEach((c, s) => {
1011
+ if (c >= 0) {
1012
+ coreToSnap[c] = s;
1013
+ }
1014
+ });
1015
+ let j = 0;
1016
+ for (let e = 0; e < els.length && j < snapshot.edgeCount; e++) {
1017
+ if (coreToSnap[graph.source[e]] === snapshot.edgeSource(j) &&
1018
+ coreToSnap[graph.target[e]] === snapshot.edgeTarget(j)) {
1019
+ order[j++] = e;
1020
+ }
1021
+ }
1022
+ if (j < snapshot.edgeCount) {
1023
+ notes.add(STYLE_ISSUE.UNRESOLVED, "edge", "elements", { count: snapshot.edgeCount - j, sample: "edge order" });
1024
+ }
1025
+ return order;
1026
+ }
1027
+ /**
1028
+ * A node's index in the graph by its Cytoscape.js id (text), trying the id as a number too.
1029
+ * @param snapshot - the graph
1030
+ * @param id - the id
1031
+ * @returns the index, or -1
1032
+ */
1033
+ function snapshotIndex(snapshot, id) {
1034
+ if (snapshot.ids.has(id)) {
1035
+ return snapshot.ids.indexOf(id);
1036
+ }
1037
+ const n = Number(id);
1038
+ return id.trim() !== "" && Number.isFinite(n) && snapshot.ids.has(n) ? snapshot.ids.indexOf(n) : -1;
1039
+ }
1040
+ /**
1041
+ * A property's cells, created on first use.
1042
+ * @param cells - the cells
1043
+ * @param name - the Cytoscape.js property
1044
+ * @param n - the element count
1045
+ * @returns the property's cells
1046
+ */
1047
+ function cellsOf(cells, name, n) {
1048
+ let c = cells.get(name);
1049
+ if (c === undefined) {
1050
+ c = new Array(n);
1051
+ cells.set(name, c);
1052
+ }
1053
+ return c;
1054
+ }
1055
+ /**
1056
+ * Applies the sheet to one target.
1057
+ * @param kind - nodes or edges
1058
+ * @param graph - the core's elements
1059
+ * @param sheet - the entries
1060
+ * @param matcher - the selector evaluator
1061
+ * @param input - the input
1062
+ * @param notes - where problems are noted
1063
+ * @param budget - the counted budget
1064
+ * @returns the target's values and rules
1065
+ */
1066
+ function evaluateTarget(kind, graph, sheet, matcher, input, notes, budget) {
1067
+ const els = kind === "node" ? graph.nodes : graph.edges;
1068
+ const spend = (ops) => {
1069
+ budget.spend(kind, ops);
1070
+ };
1071
+ const { cells, applied } = cascade(kind, els, sheet, matcher, input, notes, budget);
1072
+ const order = outputOrder(kind, graph, input.snapshot, notes);
1073
+ const coreToOut = new Int32Array(els.length).fill(-1);
1074
+ order.forEach((c, k) => {
1075
+ if (c >= 0) {
1076
+ coreToOut[c] = k;
1077
+ }
1078
+ });
1079
+ applyBypasses(kind, els, cells, coreToOut, notes);
1080
+ if (kind === "edge") {
1081
+ forceLoopCurves(graph, cells.get("curve-style"));
1082
+ }
1083
+ const drawn = drawnValues(kind, els, cells, order, input.rendered, notes, spend);
1084
+ if (kind === "edge") {
1085
+ straightenUnpairedBeziers(graph, curveStyles(graph, cells, input.rendered), coreToOut, drawn.curved);
1086
+ }
1087
+ const built = buildRules(kind, applied, { els, order, coreToOut }, input, drawn, { matcher, notes, spend });
1088
+ return {
1089
+ n: order.length,
1090
+ values: drawn,
1091
+ rules: built.rules,
1092
+ columns: built.columns,
1093
+ rawColumns: built.rawColumns,
1094
+ elements: Array.from(order, (i) => (i >= 0 ? els[i] : null)),
1095
+ };
1096
+ }
1097
+ /**
1098
+ * The cascade over one target: per property, the cell of the last rule that sets it, per element.
1099
+ * @param kind - nodes or edges
1100
+ * @param els - the core's elements of the target
1101
+ * @param sheet - the entries
1102
+ * @param matcher - the selector evaluator
1103
+ * @param input - the input
1104
+ * @param notes - where problems are noted
1105
+ * @param budget - the counted budget
1106
+ * @returns the cells and the entries applied
1107
+ */
1108
+ function cascade(kind, els, sheet, matcher, input, notes, budget) {
1109
+ const n = els.length;
1110
+ const specs = cyjsProperties(kind);
1111
+ const spend = (ops) => {
1112
+ budget.spend(kind, ops);
1113
+ };
1114
+ const ix = new Indexes(els, spend);
1115
+ const cells = new Map();
1116
+ const notCarried = new Map();
1117
+ const applied = [];
1118
+ let stopped = false;
1119
+ for (const entry of sheet) {
1120
+ input.signal?.throwIfAborted();
1121
+ const props = entryProperties(entry, kind, specs, notes, notCarried);
1122
+ if (props.length === 0) {
1123
+ continue;
1124
+ }
1125
+ const list = budget.exhausted(kind)
1126
+ ? null
1127
+ : budgetedMatch(entry.selector, { kind, n }, matcher, ix, input, budget);
1128
+ if (list === null) {
1129
+ stopped = true;
1130
+ break;
1131
+ }
1132
+ spend(list.length);
1133
+ applied.push({ entry, list, props });
1134
+ for (const p of props) {
1135
+ const col = cellsOf(cells, p.name, n);
1136
+ for (const i of list) {
1137
+ col[i] = cellFor(p, els[i]);
1138
+ }
1139
+ spend(list.length);
1140
+ }
1141
+ }
1142
+ if (stopped) {
1143
+ notes.add(STYLE_ISSUE.BUDGET, kind, null, { sample: "stylesheet" });
1144
+ }
1145
+ for (const [name, count] of notCarried) {
1146
+ notes.add(STYLE_ISSUE.NOT_CARRIED, kind, name, { count, sample: name });
1147
+ }
1148
+ return { cells, applied };
1149
+ }
1150
+ /**
1151
+ * The elements a selector matches, within the counted budget.
1152
+ * @param sel - the selector
1153
+ * @param target - the target and its element count
1154
+ * @param target.kind - nodes or edges
1155
+ * @param target.n - the element count
1156
+ * @param matcher - the evaluator
1157
+ * @param ix - the target's indexes
1158
+ * @param input - the input, whose signal cancels the match
1159
+ * @param budget - the counted budget
1160
+ * @returns the element indexes, or null when the budget ran out partway through
1161
+ */
1162
+ function budgetedMatch(sel, target, matcher, ix, input, budget) {
1163
+ matcher.begin(target.kind, budget, input.signal);
1164
+ try {
1165
+ return matchList(sel, target.kind, target.n, matcher, ix);
1166
+ }
1167
+ catch (error) {
1168
+ if (!(error instanceof BudgetStop)) {
1169
+ throw error;
1170
+ }
1171
+ return null;
1172
+ }
1173
+ finally {
1174
+ matcher.end();
1175
+ }
1176
+ }
1177
+ /**
1178
+ * Each element's own `style` (a bypass) over every rule; a mapper there is refused, as Cytoscape.js refuses it.
1179
+ * @param kind - nodes or edges
1180
+ * @param els - the core's elements of the target
1181
+ * @param cells - the cells; changed in place
1182
+ * @param coreToOut - the output index of each core element
1183
+ * @param notes - where problems are noted
1184
+ */
1185
+ function applyBypasses(kind, els, cells, coreToOut, notes) {
1186
+ const specs = cyjsProperties(kind);
1187
+ for (let i = 0; i < els.length; i++) {
1188
+ const { json } = els[i];
1189
+ const bypass = json.style ?? json.css;
1190
+ if (!isObject(bypass)) {
1191
+ continue;
1192
+ }
1193
+ for (const name0 of Object.keys(bypass)) {
1194
+ const name = cyjsPropertyName(name0);
1195
+ const spec = specs.get(name);
1196
+ const value = bypass[name0];
1197
+ if (spec === undefined || value === "" || value === null) {
1198
+ continue;
1199
+ }
1200
+ const parsed = parseCyjsValue(spec, value, "bypass");
1201
+ if (parsed === null || parsed === CYJS_THROWS || !isFlat(parsed)) {
1202
+ notes.add(STYLE_ISSUE.BAD_VALUE, kind, spec.property, { sample: value, element: coreToOut[i] });
1203
+ continue;
1204
+ }
1205
+ cellsOf(cells, name, els.length)[i] = parsed;
1206
+ }
1207
+ }
1208
+ }
1209
+ /**
1210
+ * What is drawn per neutral property, in output order: the cells as neutral values, overridden by what a live core
1211
+ * reports, with the label alignments and the visibility parts combined. Properties with no value are left out.
1212
+ * @param kind - nodes or edges
1213
+ * @param els - the core's elements of the target
1214
+ * @param cells - the cascade's cells
1215
+ * @param order - the core element of each output index
1216
+ * @param rendered - what a live core reports per element JSON, when given
1217
+ * @param notes - where problems are noted
1218
+ * @param spend - spends from the budget
1219
+ * @returns the values by property
1220
+ */
1221
+ function drawnValues(kind, els, cells, order, rendered, notes, spend) {
1222
+ var _a;
1223
+ const out = order.length;
1224
+ const values = {};
1225
+ const words = new Map();
1226
+ const drawnOf = { kind, els, cells, order, rendered, notes };
1227
+ for (const [name, spec] of cyjsProperties(kind)) {
1228
+ if (!cells.has(name) && rendered === undefined) {
1229
+ continue;
1230
+ }
1231
+ const col = drawnColumn(drawnOf, name, spec);
1232
+ spend(2 * out);
1233
+ if (spec.property.startsWith("_")) {
1234
+ words.set(spec.property, col.map((v) => (typeof v === "string" ? v : null)));
1235
+ continue;
1236
+ }
1237
+ values[_a = spec.property] ?? (values[_a] = new Array(out).fill(null));
1238
+ const target = values[spec.property];
1239
+ col.forEach((v, k) => {
1240
+ if (v !== null && v !== undefined) {
1241
+ target[k] = v;
1242
+ }
1243
+ });
1244
+ }
1245
+ combineParts(kind, out, words, values, notes);
1246
+ const drawn = {};
1247
+ for (const [p, col] of Object.entries(values)) {
1248
+ if (col.some((v) => v !== null)) {
1249
+ drawn[p] = col;
1250
+ }
1251
+ }
1252
+ return drawn;
1253
+ }
1254
+ /**
1255
+ * One Cytoscape.js property's neutral value per output element: its cell, overridden by what a live core reports.
1256
+ * @param d - the target's cells and what a live core reports
1257
+ * @param name - the property
1258
+ * @param spec - its spec
1259
+ * @returns the values, in output order
1260
+ */
1261
+ function drawnColumn(d, name, spec) {
1262
+ const { kind, order, notes, rendered } = d;
1263
+ const out = order.length;
1264
+ const col = new Array(out).fill(null);
1265
+ const cellCol = d.cells.get(name);
1266
+ for (let k = 0; k < out && cellCol !== undefined; k++) {
1267
+ const c = order[k] >= 0 ? cellCol[order[k]] : undefined;
1268
+ if (c !== undefined) {
1269
+ col[k] = neutralOfCell(spec, name, c, { notes, target: kind, property: spec.property, element: k });
1270
+ }
1271
+ }
1272
+ if (rendered !== undefined) {
1273
+ overrideRendered(d, rendered, name, spec, col);
1274
+ }
1275
+ return col;
1276
+ }
1277
+ /**
1278
+ * Overrides a property's values with what a live core reports.
1279
+ * @param d - the target's cells
1280
+ * @param rendered - what a live core reports
1281
+ * @param name - the property
1282
+ * @param spec - its spec
1283
+ * @param col - the values, in output order, changed in place
1284
+ */
1285
+ function overrideRendered(d, rendered, name, spec, col) {
1286
+ const { kind, order, notes } = d;
1287
+ for (let k = 0; k < order.length; k++) {
1288
+ const r = order[k] >= 0 ? rendered.get(d.els[order[k]].json) : undefined;
1289
+ if (r !== undefined && Object.hasOwn(r, name)) {
1290
+ const site = { notes, target: kind, property: spec.property, element: k };
1291
+ const v = cyjsRendered(kind, name, r[name], site);
1292
+ // a live core reports "" for a label it does not draw
1293
+ col[k] = v === undefined || (v === "" && spec.type === "text") ? null : v;
1294
+ }
1295
+ }
1296
+ }
1297
+ /**
1298
+ * Each edge's curve style as Cytoscape.js draws it: what a live core reports, else the winning cell.
1299
+ * @param graph - the core's elements
1300
+ * @param cells - the winning cells
1301
+ * @param rendered - what a live core reports, when given
1302
+ * @returns the curve style per edge, in core order
1303
+ */
1304
+ function curveStyles(graph, cells, rendered) {
1305
+ const col = cells.get("curve-style");
1306
+ return graph.edges.map((el, e) => {
1307
+ const r = rendered?.get(el.json);
1308
+ if (r !== undefined && Object.hasOwn(r, "curve-style")) {
1309
+ return r["curve-style"];
1310
+ }
1311
+ const c = col?.[e];
1312
+ return typeof c === "object" && c.kind === "word" ? c.value : undefined;
1313
+ });
1314
+ }
1315
+ /**
1316
+ * Cytoscape.js bows a `bezier` edge only to keep it apart from the other `bezier` edges joining the same two nodes:
1317
+ * it draws a lone one, and the middle one of an odd number, straight. Loops stay curved.
1318
+ * @param graph - the core's elements
1319
+ * @param styles - each edge's curve style, in core order
1320
+ * @param coreToOut - each edge's output index, or -1
1321
+ * @param curved - the drawn `curved` values in output order, changed in place
1322
+ */
1323
+ function straightenUnpairedBeziers(graph, styles, coreToOut, curved) {
1324
+ if (curved === undefined) {
1325
+ return;
1326
+ }
1327
+ for (const bundle of bezierBundles(graph, styles)) {
1328
+ const k = bundle.length % 2 === 1 ? coreToOut[bundle[(bundle.length - 1) / 2]] : -1;
1329
+ if (k >= 0) {
1330
+ curved[k] = false;
1331
+ }
1332
+ }
1333
+ }
1334
+ /**
1335
+ * The `bezier` edges that are not loops, grouped by the two nodes they join (either way round), in core order.
1336
+ * @param graph - the core's elements
1337
+ * @param styles - each edge's curve style, in core order
1338
+ * @returns the groups
1339
+ */
1340
+ function bezierBundles(graph, styles) {
1341
+ const bundles = new Map();
1342
+ for (let e = 0; e < graph.edges.length; e++) {
1343
+ const s = graph.source[e];
1344
+ const t = graph.target[e];
1345
+ if (s === t || styles[e] !== "bezier") {
1346
+ continue;
1347
+ }
1348
+ const key = s < t ? `${s} ${t}` : `${t} ${s}`;
1349
+ const bundle = bundles.get(key);
1350
+ if (bundle === undefined) {
1351
+ bundles.set(key, [e]);
1352
+ }
1353
+ else {
1354
+ bundle.push(e);
1355
+ }
1356
+ }
1357
+ return bundles.values();
1358
+ }
1359
+ /**
1360
+ * Cytoscape.js draws every loop curved: a loop whose curve style is anything but `bezier` becomes `bezier`, except
1361
+ * `haystack`, which Cytoscape.js leaves as it is because it is the property's own default.
1362
+ * @param graph - the core's elements
1363
+ * @param col - the winning curve style per edge, if any rule set one
1364
+ */
1365
+ function forceLoopCurves(graph, col) {
1366
+ if (col === undefined) {
1367
+ return;
1368
+ }
1369
+ for (let e = 0; e < graph.edges.length; e++) {
1370
+ const c = col[e];
1371
+ if (graph.source[e] === graph.target[e] &&
1372
+ typeof c === "object" &&
1373
+ c.kind === "word" &&
1374
+ c.value !== "bezier" &&
1375
+ c.value !== "haystack") {
1376
+ col[e] = { kind: "word", value: "bezier", str: "bezier" };
1377
+ }
1378
+ }
1379
+ }
1380
+ /**
1381
+ * The properties of one entry that apply to a target, parsed.
1382
+ * @param entry - the entry
1383
+ * @param kind - the target
1384
+ * @param specs - the target's carried properties
1385
+ * @param notes - where problems are noted
1386
+ * @param notCarried - counts of property names not carried
1387
+ * @returns the parsed properties, later duplicates last
1388
+ */
1389
+ function entryProperties(entry, kind, specs, notes, notCarried) {
1390
+ const out = [];
1391
+ for (const [name0, value] of entry.properties) {
1392
+ const name = entry.dashOnly ? dashOnlyName(name0) : cyjsPropertyName(name0);
1393
+ const spec = specs.get(name);
1394
+ if (spec === undefined) {
1395
+ if (kind === "node" && !CYJS_EDGE_ONLY.has(name) && !entry.tool) {
1396
+ notCarried.set(name, (notCarried.get(name) ?? 0) + 1);
1397
+ }
1398
+ continue;
1399
+ }
1400
+ const parsed = parseCyjsValue(spec, value, "rule");
1401
+ if (parsed === null || parsed === CYJS_THROWS) {
1402
+ // a rule's own value: noted for the target as a whole, so per-element notes keep their element lists
1403
+ if (!entry.tool) {
1404
+ notes.add(STYLE_ISSUE.BAD_VALUE, kind, null, { sample: `${name}: ${String(value)}` });
1405
+ }
1406
+ continue;
1407
+ }
1408
+ out.push({ name, spec, parsed });
1409
+ }
1410
+ return out;
1411
+ }
1412
+ /**
1413
+ * A property name of an entry Cytoscape.js reads in dash form only: `content` is `label`, any other name as it is.
1414
+ * @param name - the name as written
1415
+ * @returns the name
1416
+ */
1417
+ function dashOnlyName(name) {
1418
+ return name === "content" ? "label" : name;
1419
+ }
1420
+ /** Edge properties a node never carries: not noted as dropped on nodes. */
1421
+ const CYJS_EDGE_ONLY = new Set([
1422
+ "line-color",
1423
+ "line-style",
1424
+ "target-arrow-shape",
1425
+ "source-arrow-shape",
1426
+ "target-arrow-color",
1427
+ "source-arrow-color",
1428
+ "curve-style",
1429
+ "arrow-scale",
1430
+ "source-label",
1431
+ "target-label",
1432
+ ]);
1433
+ /**
1434
+ * The elements of a target a selector matches, in order.
1435
+ * @param sel - the selector
1436
+ * @param kind - the target
1437
+ * @param n - the element count
1438
+ * @param matcher - the evaluator
1439
+ * @param ix - the target's indexes
1440
+ * @returns the element indexes
1441
+ */
1442
+ function matchList(sel, kind, n, matcher, ix) {
1443
+ if (sel.queries.length === 0) {
1444
+ return [];
1445
+ }
1446
+ // one stamp per call marks the elements found, so a selector costs what its candidates cost, not the graph
1447
+ const stamp = ++ix.stamp;
1448
+ const marked = ix.marks;
1449
+ const hits = [];
1450
+ let scanned = false;
1451
+ const visit = (q, i) => {
1452
+ if (marked[i] !== stamp && matcher.query(q, kind, i)) {
1453
+ marked[i] = stamp;
1454
+ hits.push(i);
1455
+ }
1456
+ };
1457
+ for (const q of sel.queries) {
1458
+ const cands = candidates(q, kind, ix);
1459
+ if (cands === null) {
1460
+ scanned = true;
1461
+ for (let i = 0; i < n; i++) {
1462
+ visit(q, i);
1463
+ }
1464
+ }
1465
+ else {
1466
+ matcher.work += cands.length;
1467
+ for (const i of cands) {
1468
+ visit(q, i);
1469
+ }
1470
+ }
1471
+ }
1472
+ if (scanned || sel.queries.length > 1) {
1473
+ hits.sort((a, b) => a - b);
1474
+ }
1475
+ matcher.work += hits.length;
1476
+ return hits;
1477
+ }
1478
+ /**
1479
+ * The cell a property gives one element: its constant, or its mapper evaluated.
1480
+ * @param p - the property
1481
+ * @param e - the element
1482
+ * @returns the cell
1483
+ */
1484
+ function cellFor(p, e) {
1485
+ const v = p.parsed;
1486
+ if (v.kind === "data" || v.kind === "mapData") {
1487
+ return applyCyjsMapper(p.spec, v, mapperData(e)) ?? "reset";
1488
+ }
1489
+ if (v.kind === "fn") {
1490
+ return "fn";
1491
+ }
1492
+ return v;
1493
+ }
1494
+ /** Parsed property defaults, per property name. */
1495
+ const DEFAULT_CELLS = new Map();
1496
+ /**
1497
+ * A property's Cytoscape.js default as a flat value.
1498
+ * @param name - the property
1499
+ * @param spec - its spec
1500
+ * @returns the default
1501
+ */
1502
+ function defaultCell(name, spec) {
1503
+ const key = `${spec.type}|${name}`;
1504
+ if (!DEFAULT_CELLS.has(key)) {
1505
+ const raw = CYJS_PROPERTY_DEFAULTS.get(name);
1506
+ const parsed = raw === undefined ? null : parseCyjsValue(spec, raw, "flat");
1507
+ DEFAULT_CELLS.set(key, parsed === null || parsed === CYJS_THROWS || !isFlat(parsed) ? null : parsed);
1508
+ }
1509
+ return DEFAULT_CELLS.get(key) ?? null;
1510
+ }
1511
+ /**
1512
+ * Whether a parsed value is flat.
1513
+ * @param v - the value
1514
+ * @returns true for a color, number or word
1515
+ */
1516
+ function isFlat(v) {
1517
+ return v.kind === "color" || v.kind === "number" || v.kind === "word";
1518
+ }
1519
+ /**
1520
+ * The neutral value of a cell.
1521
+ * @param spec - the property
1522
+ * @param name - its Cytoscape.js name
1523
+ * @param c - the cell
1524
+ * @param site - where it is read
1525
+ * @returns the value, null for none, or undefined when it cannot be evaluated (noted)
1526
+ */
1527
+ function neutralOfCell(spec, name, c, site) {
1528
+ if (c === CYJS_THROWS) {
1529
+ site.notes.add(STYLE_ISSUE.BAD_VALUE, site.target, site.property, {
1530
+ sample: "unstyleable",
1531
+ element: site.element,
1532
+ });
1533
+ return undefined;
1534
+ }
1535
+ if (c === "fn") {
1536
+ site.notes.add(STYLE_ISSUE.LAYER_FLATTENED, site.target, site.property, {
1537
+ sample: "FUNCTION",
1538
+ element: site.element,
1539
+ });
1540
+ return undefined;
1541
+ }
1542
+ const flat = c === "reset" ? defaultCell(name, spec) : c;
1543
+ if (flat === null) {
1544
+ return null;
1545
+ }
1546
+ return cyjsNeutral(spec, flat, site);
1547
+ }
1548
+ /**
1549
+ * Combines the label alignments into `labelPosition` and `visibility` with `display` into `visible`.
1550
+ * @param kind - the target
1551
+ * @param n - the element count
1552
+ * @param words - the parts by internal name
1553
+ * @param values - the values; changed in place
1554
+ * @param notes - where problems are noted
1555
+ */
1556
+ function combineParts(kind, n, words, values, notes) {
1557
+ const va = words.get("_valign");
1558
+ const ha = words.get("_halign");
1559
+ if (kind === "node" && (va !== undefined || ha !== undefined)) {
1560
+ values.labelPosition = Array.from({ length: n }, (_, i) => labelPosition(va?.[i] ?? null, ha?.[i] ?? null, (sample) => {
1561
+ notes.add(STYLE_ISSUE.UNKNOWN_VALUE, kind, "labelPosition", { sample, element: i });
1562
+ }));
1563
+ }
1564
+ const vis = words.get("_visibility");
1565
+ const disp = words.get("_display");
1566
+ if (vis !== undefined || disp !== undefined) {
1567
+ const col = new Array(n).fill(null);
1568
+ for (let i = 0; i < n; i++) {
1569
+ const a = vis?.[i] ?? null;
1570
+ const b = disp?.[i] ?? null;
1571
+ if (a === null && b === null) {
1572
+ continue;
1573
+ }
1574
+ col[i] = a !== "hidden" && b !== "none";
1575
+ }
1576
+ values.visible = col;
1577
+ }
1578
+ }
1579
+ /**
1580
+ * A node label's position from its vertical and horizontal alignments; an `-inside` alignment is read as its
1581
+ * outside one, noted.
1582
+ * @param v - the vertical alignment, or null
1583
+ * @param h - the horizontal alignment, or null
1584
+ * @param note - notes an alignment read as another
1585
+ * @returns the position, or null
1586
+ */
1587
+ function labelPosition(v, h, note) {
1588
+ if (v === null && h === null) {
1589
+ return null;
1590
+ }
1591
+ const vv = (v ?? "top").replace("-inside", "");
1592
+ const hh = (h ?? "center").replace("-inside", "");
1593
+ if ((v ?? "").endsWith("-inside") || (h ?? "").endsWith("-inside")) {
1594
+ note(`${v ?? ""} ${h ?? ""}`);
1595
+ }
1596
+ return POSITIONS.get(`${vv},${hh}`) ?? null;
1597
+ }
1598
+ // ============================================================ rules
1599
+ /**
1600
+ * The stylesheet as neutral rules over graph-io's columns and the style columns it adds.
1601
+ * @param kind - the target
1602
+ * @param applied - the entries with their matched elements and properties
1603
+ * @param core - the core's elements, the core element of each output index and the output index of each core element
1604
+ * (or -1)
1605
+ * @param core.els - the core's elements
1606
+ * @param core.order - the core element of each output index
1607
+ * @param core.coreToOut - the output index of each core element, or -1
1608
+ * @param input - the input (the graph, the rendered values)
1609
+ * @param truth - what is drawn per property, by output index
1610
+ * @param env - the evaluator (degrees), where problems are noted and how the budget is spent
1611
+ * @param env.matcher - the evaluator
1612
+ * @param env.notes - where problems are noted
1613
+ * @param env.spend - spends from the budget
1614
+ * @returns the rules, the style columns and the data columns they read
1615
+ */
1616
+ function buildRules(kind, applied, core, input, truth, env) {
1617
+ const { els, order, coreToOut } = core;
1618
+ const { matcher, notes, spend } = env;
1619
+ const out = order.length;
1620
+ const columns = new Map();
1621
+ const raw = new Set();
1622
+ const ctx = {
1623
+ kind,
1624
+ els,
1625
+ coreToOut,
1626
+ out,
1627
+ snapshot: input.snapshot,
1628
+ truth: input.rendered === undefined ? null : truth,
1629
+ matcher,
1630
+ notes,
1631
+ spend,
1632
+ columns,
1633
+ raw,
1634
+ members: new Map(),
1635
+ faithful: new Map(),
1636
+ degrees: new Map(),
1637
+ };
1638
+ const drafts = [];
1639
+ for (const a of applied) {
1640
+ const props = a.props.filter((p) => !p.spec.property.startsWith("_"));
1641
+ if (props.length === 0 || a.list.length === 0) {
1642
+ continue;
1643
+ }
1644
+ drafts.push(draftOf(ctx, a.entry, a.list, props));
1645
+ }
1646
+ const rules = collapse(ctx, drafts);
1647
+ return { rules, columns, rawColumns: [...raw] };
1648
+ }
1649
+ /**
1650
+ * One entry as a rule.
1651
+ * @param ctx - the shared state
1652
+ * @param entry - the entry
1653
+ * @param list - the matched core elements
1654
+ * @param props - the carried properties
1655
+ * @returns the draft
1656
+ */
1657
+ function draftOf(ctx, entry, list, props) {
1658
+ const setting = new Map();
1659
+ const mapping = new Map();
1660
+ let flattened = false;
1661
+ const id = entry.tool
1662
+ ? `${ctx.kind}.cytoscape-js.${String(entry.index + CYJS_DEFAULT_STYLESHEET.length)}`
1663
+ : `${ctx.kind}.sheet.${String(entry.index)}`;
1664
+ for (const p of props) {
1665
+ // a later duplicate of a property replaces the earlier one
1666
+ setting.delete(p.spec.property);
1667
+ mapping.delete(p.spec.property);
1668
+ const v = p.parsed;
1669
+ if (v.kind === "fn") {
1670
+ const copied = functionCopy(ctx, entry, list, p.spec.property);
1671
+ if (copied !== null) {
1672
+ mapping.set(p.spec.property, copied);
1673
+ flattened = true;
1674
+ }
1675
+ }
1676
+ else if (isFlat(v)) {
1677
+ const neutral = cyjsNeutral(p.spec, v, {
1678
+ notes: new StyleNotes(),
1679
+ target: ctx.kind,
1680
+ property: p.spec.property,
1681
+ });
1682
+ if (neutral !== undefined) {
1683
+ setting.set(p.spec.property, neutral);
1684
+ }
1685
+ }
1686
+ else {
1687
+ mapping.set(p.spec.property, mapperMapping(ctx, entry, list, p));
1688
+ }
1689
+ }
1690
+ const set = Object.fromEntries(setting);
1691
+ const map = Object.fromEntries(mapping);
1692
+ const hasMap = mapping.size > 0;
1693
+ // the predicate is built only for a rule that is not collapsed into a run: a run's rules need no column each
1694
+ const rule = () => {
1695
+ const where = predicateOf(ctx, entry, list);
1696
+ return {
1697
+ id,
1698
+ target: ctx.kind,
1699
+ role: roleOf(hasMap, where),
1700
+ origin: entry.tool ? "tool" : "declared",
1701
+ where,
1702
+ ...(setting.size > 0 ? { set } : {}),
1703
+ ...(hasMap ? { map } : {}),
1704
+ facts: flattened ? { elements: list.length, reason: "FUNCTION" } : { elements: list.length },
1705
+ };
1706
+ };
1707
+ return {
1708
+ rule,
1709
+ id,
1710
+ set,
1711
+ tool: entry.tool,
1712
+ single: hasMap || entry.tool ? null : singleTest(entry.selector, ctx.kind),
1713
+ list,
1714
+ };
1715
+ }
1716
+ /**
1717
+ * A function-valued property: its values as the live core drew them, copied per element into a style column.
1718
+ * @param ctx - the shared state
1719
+ * @param entry - the entry
1720
+ * @param list - the matched core elements
1721
+ * @param property - the neutral property
1722
+ * @returns the passthrough of the copy, or null without a live core's values
1723
+ */
1724
+ function functionCopy(ctx, entry, list, property) {
1725
+ const drawn = ctx.truth?.[property];
1726
+ if (drawn === undefined) {
1727
+ return null;
1728
+ }
1729
+ const key = `function.${String(entry.index)}.${property}`;
1730
+ const col = new Array(ctx.out).fill(null);
1731
+ for (const i of list) {
1732
+ const k = ctx.coreToOut[i];
1733
+ if (k >= 0) {
1734
+ col[k] = drawn[k];
1735
+ }
1736
+ }
1737
+ ctx.columns.set(key, col);
1738
+ return { kind: "passthrough", by: { style: key } };
1739
+ }
1740
+ /**
1741
+ * A rule's role from what it does.
1742
+ * @param hasMap - whether it maps values
1743
+ * @param where - its predicate
1744
+ * @returns "mapping", "defaults" (constants on every element) or "group"
1745
+ */
1746
+ function roleOf(hasMap, where) {
1747
+ if (hasMap) {
1748
+ return "mapping";
1749
+ }
1750
+ return "all" in where ? "defaults" : "group";
1751
+ }
1752
+ /**
1753
+ * The varying test of a single-query selector, for collapsing runs: its last class, id or value test, with the other
1754
+ * tests (a shared scope such as `[graphty_import = "a"]`) in the signature so a run only joins rules that agree on them.
1755
+ * @param sel - the selector
1756
+ * @param kind - the target
1757
+ * @returns the run signature and the rule's key, or null
1758
+ */
1759
+ function singleTest(sel, kind) {
1760
+ if (sel.invalid || sel.queries.length !== 1) {
1761
+ return null;
1762
+ }
1763
+ const checks = sel.queries[0].checks.filter((c) => !(c.type === "group" && (c.value === "*" || c.value === `${kind}s`)));
1764
+ const c = checks.at(-1);
1765
+ if (c === undefined || checks.slice(0, -1).some((x) => x.type !== "compare" && x.type !== "class")) {
1766
+ return null;
1767
+ }
1768
+ const context = JSON.stringify(checks.slice(0, -1));
1769
+ if (c.type === "class" && typeof c.value === "string") {
1770
+ return { sig: `class\u0000${context}`, key: c.value };
1771
+ }
1772
+ if (c.type === "id") {
1773
+ return { sig: `id\u0000${context}`, key: c.value };
1774
+ }
1775
+ if (c.type === "compare" && c.op === "=" && !c.not && !c.ci) {
1776
+ return { sig: `eq\u0000${context}\u0000${c.field}`, key: c.value };
1777
+ }
1778
+ return null;
1779
+ }
1780
+ /**
1781
+ * Whether graph-io's column holds exactly what a selector reads for every element: the same value (`===`) where the
1782
+ * raw data has a scalar, nothing where it has none, and no raw null or false (a selector sees those, a column does
1783
+ * not).
1784
+ * @param ctx - the shared state
1785
+ * @param field - the field
1786
+ * @returns true when a predicate over the column selects what the selector selects
1787
+ */
1788
+ function faithful(ctx, field) {
1789
+ const known = ctx.faithful.get(field);
1790
+ if (known !== undefined) {
1791
+ return known;
1792
+ }
1793
+ let ok = ctx.snapshot !== undefined;
1794
+ const table = ctx.kind === "node" ? ctx.snapshot?.nodes : ctx.snapshot?.edges;
1795
+ const has = table?.names().includes(field) ?? false;
1796
+ for (let c = 0; ok && c < ctx.els.length; c++) {
1797
+ const k = ctx.coreToOut[c];
1798
+ const rv = selectorField(ctx.els[c], field);
1799
+ if (rv === null || rv === false) {
1800
+ ok = false;
1801
+ break;
1802
+ }
1803
+ const gv = k >= 0 && has && table !== undefined ? plainCell(table.value(field, k)) : null;
1804
+ if (rv === undefined ? gv !== null : rv !== gv) {
1805
+ ok = false;
1806
+ }
1807
+ }
1808
+ ctx.spend(ctx.els.length);
1809
+ ctx.faithful.set(field, ok);
1810
+ return ok;
1811
+ }
1812
+ /**
1813
+ * Whether the graph's degree equals Cytoscape.js's for every node.
1814
+ * @param ctx - the shared state
1815
+ * @param which - the degree
1816
+ * @returns true when a predicate over the computed degree selects what the selector selects
1817
+ */
1818
+ function degreeAgrees(ctx, which) {
1819
+ const known = ctx.degrees.get(which);
1820
+ if (known !== undefined) {
1821
+ return known;
1822
+ }
1823
+ let ok = ctx.snapshot !== undefined && ctx.kind === "node" && (which === "degree" || ctx.snapshot.directed);
1824
+ if (ok && ctx.snapshot !== undefined) {
1825
+ const mine = degreeValues(ctx.snapshot, which);
1826
+ for (let c = 0; c < ctx.els.length; c++) {
1827
+ const k = ctx.coreToOut[c];
1828
+ if (k < 0 || mine[k] !== ctx.matcher[which][c]) {
1829
+ ok = false;
1830
+ break;
1831
+ }
1832
+ }
1833
+ ok && (ok = ctx.els.length === ctx.out);
1834
+ }
1835
+ ctx.degrees.set(which, ok);
1836
+ return ok;
1837
+ }
1838
+ /**
1839
+ * A selector as a short predicate when one expresses it exactly, else a membership style column.
1840
+ * @param ctx - the shared state
1841
+ * @param entry - the entry
1842
+ * @param list - the matched core elements
1843
+ * @returns the predicate
1844
+ */
1845
+ function predicateOf(ctx, entry, list) {
1846
+ const short = shortPredicate(ctx, entry.selector);
1847
+ if (short !== null) {
1848
+ return short;
1849
+ }
1850
+ if (list.length === ctx.els.length && ctx.els.length === ctx.out) {
1851
+ return { all: true };
1852
+ }
1853
+ const sig = `${entry.tool ? "tool" : "file"}\u0000${entry.text}`;
1854
+ let key = ctx.members.get(sig);
1855
+ if (key === undefined) {
1856
+ key = `member.${String(ctx.members.size + 1)}`;
1857
+ ctx.members.set(sig, key);
1858
+ const col = new Array(ctx.out).fill(null);
1859
+ for (const i of list) {
1860
+ const k = ctx.coreToOut[i];
1861
+ if (k >= 0) {
1862
+ col[k] = true;
1863
+ }
1864
+ }
1865
+ ctx.spend(ctx.out + list.length);
1866
+ ctx.columns.set(key, col);
1867
+ ctx.notes.add(STYLE_ISSUE.SELECTOR_AS_COLUMN, ctx.kind, key, { sample: entry.text });
1868
+ }
1869
+ return { has: { style: key } };
1870
+ }
1871
+ /**
1872
+ * The short predicate of a selector, or null: every query of one alternative with at most 8 tests, each a group,
1873
+ * a value test or an existence test over a column graph-io holds exactly, or a degree test the graph computes the
1874
+ * same way; several alternatives only as equal tests of one field (`in`).
1875
+ * @param ctx - the shared state
1876
+ * @param sel - the selector
1877
+ * @returns the predicate, or null
1878
+ */
1879
+ function shortPredicate(ctx, sel) {
1880
+ if (sel.invalid) {
1881
+ return null;
1882
+ }
1883
+ const alts = [];
1884
+ for (const q of sel.queries) {
1885
+ const terms = queryTerms(ctx, q);
1886
+ if (terms === null) {
1887
+ return null;
1888
+ }
1889
+ if (terms !== "never") {
1890
+ alts.push(terms);
1891
+ }
1892
+ }
1893
+ if (alts.length === 0) {
1894
+ return null;
1895
+ }
1896
+ if (alts.some((t) => t.length === 0)) {
1897
+ return ctx.els.length === ctx.out ? { all: true } : null;
1898
+ }
1899
+ if (alts.length === 1) {
1900
+ const t = alts[0];
1901
+ if (t.length > 8) {
1902
+ return null;
1903
+ }
1904
+ return t.length === 1 ? t[0] : { and: t };
1905
+ }
1906
+ return equalTests(alts);
1907
+ }
1908
+ /**
1909
+ * A query's checks as short predicate terms.
1910
+ * @param ctx - the shared state
1911
+ * @param q - the query
1912
+ * @returns the terms; "never" when its group test excludes the target; null when a check has no short term
1913
+ */
1914
+ function queryTerms(ctx, q) {
1915
+ const terms = [];
1916
+ let never = false;
1917
+ for (const c of q.checks) {
1918
+ if (c.type === "group") {
1919
+ never || (never = c.value !== "*" && c.value !== `${ctx.kind}s`);
1920
+ continue;
1921
+ }
1922
+ const t = termOf(ctx, c);
1923
+ if (t === null) {
1924
+ return null;
1925
+ }
1926
+ terms.push(t);
1927
+ }
1928
+ return never ? "never" : terms;
1929
+ }
1930
+ /**
1931
+ * Several alternatives as one `in` predicate: only equal tests of one column, at most 8.
1932
+ * @param alts - the alternatives' terms
1933
+ * @returns the predicate, or null
1934
+ */
1935
+ function equalTests(alts) {
1936
+ if (alts.length > 8 || !alts.every((t) => t.length === 1 && "eq" in t[0])) {
1937
+ return null;
1938
+ }
1939
+ const by = alts[0][0].eq[0];
1940
+ const values = [];
1941
+ for (const t of alts) {
1942
+ const [r, v] = t[0].eq;
1943
+ if (JSON.stringify(r) !== JSON.stringify(by)) {
1944
+ return null;
1945
+ }
1946
+ values.push(v);
1947
+ }
1948
+ return { in: [by, values] };
1949
+ }
1950
+ /**
1951
+ * One check as a short predicate term, or null.
1952
+ * @param ctx - the shared state
1953
+ * @param c - the check
1954
+ * @returns the term, or null
1955
+ */
1956
+ function termOf(ctx, c) {
1957
+ switch (c.type) {
1958
+ case "compare":
1959
+ if (c.op !== "=" || c.ci || !faithful(ctx, c.field)) {
1960
+ return null;
1961
+ }
1962
+ return c.not ? { not: { eq: [{ data: c.field }, c.value] } } : { eq: [{ data: c.field }, c.value] };
1963
+ case "exist":
1964
+ return faithful(ctx, c.field) ? { has: { data: c.field } } : null;
1965
+ case "bool":
1966
+ return c.op === "^" && faithful(ctx, c.field) ? { not: { has: { data: c.field } } } : null;
1967
+ case "meta":
1968
+ if (c.ci || !degreeAgrees(ctx, c.field)) {
1969
+ return null;
1970
+ }
1971
+ return degreeTerm(c.field, c.op, c.not, c.value);
1972
+ default:
1973
+ return null;
1974
+ }
1975
+ }
1976
+ /**
1977
+ * A degree test as a predicate over the computed degree, so it follows later edits: `=` as `eq`, and an order test
1978
+ * as the degrees it keeps or the degrees it leaves out (degrees are whole numbers from 0), at most 8 of them.
1979
+ * @param field - the degree
1980
+ * @param op - the comparison
1981
+ * @param not - whether the test is negated
1982
+ * @param value - the number compared with
1983
+ * @returns the predicate, or null when it needs more than 8 values
1984
+ */
1985
+ function degreeTerm(field, op, not, value) {
1986
+ const ref = { computed: field };
1987
+ if (op === "=") {
1988
+ return not ? { not: { eq: [ref, value] } } : { eq: [ref, value] };
1989
+ }
1990
+ // The whole numbers from 0 the test leaves out (`>`, `>=`) or keeps (`<`, `<=`).
1991
+ let below;
1992
+ if (op === ">" || op === "<=") {
1993
+ below = Math.floor(value) + 1;
1994
+ }
1995
+ else if (op === ">=" || op === "<") {
1996
+ below = Math.ceil(value);
1997
+ }
1998
+ else {
1999
+ return null;
2000
+ }
2001
+ if (!Number.isFinite(below) || below < 1 || below > 8) {
2002
+ return null;
2003
+ }
2004
+ const values = Array.from({ length: below }, (_, k) => k);
2005
+ const keeps = op === "<" || op === "<=";
2006
+ const inSet = { in: [ref, values] };
2007
+ return keeps !== not ? inSet : { not: inSet };
2008
+ }
2009
+ /**
2010
+ * A mapper as a neutral mapping over graph-io's column when that gives Cytoscape.js's values for every element the
2011
+ * rule applies to, else the mapper's per-element values as a style column (`value.<rule>.<property>`).
2012
+ * @param ctx - the shared state
2013
+ * @param entry - the entry
2014
+ * @param list - the matched core elements
2015
+ * @param p - the property
2016
+ * @returns the mapping
2017
+ */
2018
+ function mapperMapping(ctx, entry, list, p) {
2019
+ const v = p.parsed;
2020
+ const want = new Array(list.length);
2021
+ const site = { notes: new StyleNotes(), target: ctx.kind, property: p.spec.property };
2022
+ for (let k = 0; k < list.length; k++) {
2023
+ const c = cellFor(p, ctx.els[list[k]]);
2024
+ const neutral = neutralOfCell(p.spec, p.name, c, site);
2025
+ want[k] = neutral ?? null;
2026
+ }
2027
+ ctx.spend(list.length * 2);
2028
+ const candidate = candidateMapping(ctx, v, p);
2029
+ if (candidate !== null && ctx.snapshot !== undefined) {
2030
+ const exact = givesWanted(ctx, ctx.snapshot, candidate, { field: v.field, property: p.spec.property }, list, want);
2031
+ ctx.spend(list.length);
2032
+ if (exact) {
2033
+ ctx.raw.add(v.field);
2034
+ return candidate;
2035
+ }
2036
+ }
2037
+ const key = `value.${entry.tool ? "tool" : String(entry.index)}.${p.spec.property}`;
2038
+ const col = new Array(ctx.out).fill(null);
2039
+ for (let k = 0; k < list.length; k++) {
2040
+ const o = ctx.coreToOut[list[k]];
2041
+ if (o >= 0) {
2042
+ col[o] = want[k];
2043
+ }
2044
+ }
2045
+ ctx.columns.set(key, col);
2046
+ return { kind: "passthrough", by: { style: key } };
2047
+ }
2048
+ /**
2049
+ * Whether a mapping over graph-io's column gives Cytoscape.js's value for every element a rule applies to.
2050
+ * @param ctx - the shared state
2051
+ * @param snapshot - the graph
2052
+ * @param candidate - the mapping
2053
+ * @param what - the column and the neutral property
2054
+ * @param what.field - the column
2055
+ * @param what.property - the neutral property
2056
+ * @param list - the matched core elements
2057
+ * @param want - Cytoscape.js's value of each, in list order
2058
+ * @returns true when it gives every one
2059
+ */
2060
+ function givesWanted(ctx, snapshot, candidate, what, list, want) {
2061
+ const table = ctx.kind === "node" ? snapshot.nodes : snapshot.edges;
2062
+ if (!table.names().includes(what.field)) {
2063
+ return false;
2064
+ }
2065
+ const canon = canonicalFor(ctx.kind, what.property);
2066
+ for (let k = 0; k < list.length; k++) {
2067
+ const o = ctx.coreToOut[list[k]];
2068
+ const cell = o < 0 ? null : plainCell(table.value(what.field, o));
2069
+ let got = null;
2070
+ if (cell !== null && !Array.isArray(cell)) {
2071
+ got = candidate.kind === "passthrough" ? canon(cell) : evalContinuous(candidate.points, numberOf(cell));
2072
+ }
2073
+ if (o >= 0 && got !== want[k]) {
2074
+ return false;
2075
+ }
2076
+ }
2077
+ return true;
2078
+ }
2079
+ /**
2080
+ * The neutral mapping a mapper would be over its field, before it is checked.
2081
+ * @param ctx - the shared state
2082
+ * @param v - the mapper
2083
+ * @param p - the property
2084
+ * @returns a passthrough for `data()`, a two-point continuous mapping for `mapData()`, or null
2085
+ */
2086
+ function candidateMapping(ctx, v, p) {
2087
+ if (v.kind === "data") {
2088
+ return { kind: "passthrough", by: { data: v.field } };
2089
+ }
2090
+ if (v.fieldMin === v.fieldMax) {
2091
+ return null;
2092
+ }
2093
+ const site = { notes: new StyleNotes(), target: ctx.kind, property: p.spec.property };
2094
+ const a = cyjsNeutral(p.spec, v.min, site);
2095
+ const b = cyjsNeutral(p.spec, v.max, site);
2096
+ if (a === undefined || b === undefined) {
2097
+ return null;
2098
+ }
2099
+ const lo = { at: v.fieldMin, below: a, value: a, above: a };
2100
+ const hi = { at: v.fieldMax, below: b, value: b, above: b };
2101
+ return { kind: "continuous", by: { data: v.field }, points: v.fieldMin < v.fieldMax ? [lo, hi] : [hi, lo] };
2102
+ }
2103
+ /**
2104
+ * Collapses runs of three or more rules that each test one class, one id or one value of the same field and only set
2105
+ * values into ONE mapping rule: per property, a winner column holds the key (class, id or value) of the last rule in
2106
+ * the run that matches the element and sets the property (the cascade's winner), and a discrete table maps each key
2107
+ * to that rule's value. A run keyed by a value whose column graph-io holds exactly reads that column instead.
2108
+ * @param ctx - the shared state
2109
+ * @param drafts - the rules in order
2110
+ * @returns the rules
2111
+ */
2112
+ function collapse(ctx, drafts) {
2113
+ const out = [];
2114
+ let run = 0;
2115
+ let i = 0;
2116
+ while (i < drafts.length) {
2117
+ const sig = drafts[i].single?.sig ?? null;
2118
+ let j = i + 1;
2119
+ while (sig !== null && j < drafts.length && drafts[j].single?.sig === sig) {
2120
+ j++;
2121
+ }
2122
+ if (sig === null || j - i < 3) {
2123
+ for (const d of drafts.slice(i, j)) {
2124
+ const rule = d.rule();
2125
+ // Cytoscape.js's own default rule over every element: the writing tool's constants already say it
2126
+ if (!(d.tool && "all" in rule.where)) {
2127
+ out.push(rule);
2128
+ }
2129
+ }
2130
+ }
2131
+ else {
2132
+ run++;
2133
+ out.push(runRule(ctx, drafts.slice(i, j), sig, run));
2134
+ }
2135
+ i = j;
2136
+ }
2137
+ return out;
2138
+ }
2139
+ /**
2140
+ * A run of rules collapsed into one mapping rule.
2141
+ * @param ctx - the shared state
2142
+ * @param members - the run's rules, in order
2143
+ * @param sig - their shared signature
2144
+ * @param run - the run's number
2145
+ * @returns the rule
2146
+ */
2147
+ function runRule(ctx, members, sig, run) {
2148
+ const props = new Set(members.flatMap((d) => Object.keys(d.set)));
2149
+ // a value run with no shared tests may read the field itself
2150
+ const parts = sig.split("\u0000");
2151
+ const field = parts[0] === "eq" && parts[1] === "[]" ? parts[2] : null;
2152
+ const map = {};
2153
+ for (const p of props) {
2154
+ map[p] = runMapping(ctx, members, p, { field, key: `winner.${String(run)}.${p}` });
2155
+ }
2156
+ const first = members[0].id.split(".").pop() ?? "";
2157
+ return {
2158
+ id: `${ctx.kind}.sheet.by.${parts[0] === "eq" ? "value" : parts[0]}.${first}`,
2159
+ target: ctx.kind,
2160
+ role: "mapping",
2161
+ origin: "declared",
2162
+ where: { all: true },
2163
+ map,
2164
+ facts: { elements: members.reduce((sum, d) => sum + d.list.length, 0) },
2165
+ };
2166
+ }
2167
+ /**
2168
+ * One property of a collapsed run: a winner column holds the key of the last rule in the run that matches the
2169
+ * element and sets the property (the cascade's winner), and a discrete table maps each key to that rule's value; a
2170
+ * run keyed by a value whose column graph-io holds exactly reads that column instead.
2171
+ * @param ctx - the shared state
2172
+ * @param members - the run's rules, in order
2173
+ * @param p - the property
2174
+ * @param names - the field a value run tests (null for another run) and the winner column's key
2175
+ * @param names.field - the field a value run tests, or null
2176
+ * @param names.key - the winner column's key
2177
+ * @returns the mapping
2178
+ */
2179
+ function runMapping(ctx, members, p, names) {
2180
+ const winner = new Array(ctx.out).fill(null);
2181
+ const table = new Map();
2182
+ for (const d of members) {
2183
+ const value = d.set[p];
2184
+ if (value === undefined || d.single === null) {
2185
+ continue;
2186
+ }
2187
+ const { key } = d.single;
2188
+ table.set(`${typeof key}:${String(key)}`, [key, value]);
2189
+ for (const c of d.list) {
2190
+ const k = ctx.coreToOut[c];
2191
+ if (k >= 0) {
2192
+ winner[k] = key;
2193
+ }
2194
+ }
2195
+ ctx.spend(d.list.length);
2196
+ }
2197
+ const entries = [...table.values()];
2198
+ // a table key that names a later rule's value: the table maps each key to the last rule's value for it
2199
+ const byKey = new Map(entries.map(([k, v]) => [`${typeof k}:${String(k)}`, v]));
2200
+ const { field } = names;
2201
+ if (field !== null && faithful(ctx, field) && sameByData(ctx, field, winner, byKey)) {
2202
+ return { kind: "discrete", by: { data: field }, table: entries };
2203
+ }
2204
+ ctx.columns.set(names.key, winner);
2205
+ return { kind: "discrete", by: { style: names.key }, table: entries };
2206
+ }
2207
+ /**
2208
+ * Whether a discrete table keyed by a column's own values gives every element its winner's value.
2209
+ * @param ctx - the shared state
2210
+ * @param field - the column
2211
+ * @param winner - each element's winning key, or null
2212
+ * @param byKey - the table
2213
+ * @returns true when reading the column gives the same values
2214
+ */
2215
+ function sameByData(ctx, field, winner, byKey) {
2216
+ const table = ctx.kind === "node" ? ctx.snapshot?.nodes : ctx.snapshot?.edges;
2217
+ if (!table?.names().includes(field)) {
2218
+ return false;
2219
+ }
2220
+ for (let k = 0; k < ctx.out; k++) {
2221
+ const v = plainCell(table.value(field, k));
2222
+ const viaData = typeof v === "string" || typeof v === "number" ? (byKey.get(`${typeof v}:${String(v)}`) ?? null) : null;
2223
+ const w = winner[k];
2224
+ const viaWinner = w === null ? null : (byKey.get(`${typeof w}:${String(w)}`) ?? null);
2225
+ if (viaData !== viaWinner) {
2226
+ return false;
2227
+ }
2228
+ }
2229
+ return true;
2230
+ }
2231
+ // ============================================================ the importer path
2232
+ /**
2233
+ * A Cytoscape.js file's styles as an importer's `styles()` returns them: what Cytoscape.js draws per element and the
2234
+ * stylesheet's rules, with Cytoscape.js as the writing tool whose defaults fill what the stylesheet leaves unset.
2235
+ * @param input - the elements, the stylesheet, the graph and the options
2236
+ * @returns the styles for graph-io's planner
2237
+ */
2238
+ export function cytoscapeJsStyles(input) {
2239
+ const notes = input.notes ?? new StyleNotes();
2240
+ const r = evaluateCytoscapeJs({ ...input, notes });
2241
+ const output = (t) => ({ values: t.values, rules: t.rules, columns: t.columns });
2242
+ return {
2243
+ canonical: true,
2244
+ dialect: "cytoscape-js",
2245
+ tool: "cytoscape-js",
2246
+ units: "px",
2247
+ node: output(r.node),
2248
+ edge: output(r.edge),
2249
+ notes: notes.list(),
2250
+ };
2251
+ }
2252
+ //# sourceMappingURL=cascade.js.map