@graview/core 0.1.28 → 0.1.30

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 (647) hide show
  1. package/README.md +17 -0
  2. package/dist/amount-input.d.ts +21 -0
  3. package/dist/amount-input.d.ts.map +1 -0
  4. package/dist/amount-input.js +96 -0
  5. package/dist/amount-input.js.map +1 -0
  6. package/dist/answer-seen.d.ts +38 -0
  7. package/dist/answer-seen.d.ts.map +1 -0
  8. package/dist/answer-seen.js +122 -0
  9. package/dist/answer-seen.js.map +1 -0
  10. package/dist/app-places.d.ts +56 -0
  11. package/dist/app-places.d.ts.map +1 -0
  12. package/dist/app-places.js +203 -0
  13. package/dist/app-places.js.map +1 -0
  14. package/dist/app.d.ts +16 -0
  15. package/dist/app.d.ts.map +1 -1
  16. package/dist/app.js.map +1 -1
  17. package/dist/arrange.d.ts +4 -2
  18. package/dist/arrange.d.ts.map +1 -1
  19. package/dist/arrange.js +4 -2
  20. package/dist/arrange.js.map +1 -1
  21. package/dist/arrangement-words.d.ts +3 -0
  22. package/dist/arrangement-words.d.ts.map +1 -0
  23. package/dist/arrangement-words.js +50 -0
  24. package/dist/arrangement-words.js.map +1 -0
  25. package/dist/arrangement.d.ts +43 -3
  26. package/dist/arrangement.d.ts.map +1 -1
  27. package/dist/arrangement.js +69 -31
  28. package/dist/arrangement.js.map +1 -1
  29. package/dist/arranging.d.ts.map +1 -1
  30. package/dist/arranging.js +36 -14
  31. package/dist/arranging.js.map +1 -1
  32. package/dist/bind.d.ts +3 -0
  33. package/dist/bind.d.ts.map +1 -1
  34. package/dist/bind.js.map +1 -1
  35. package/dist/blocks.d.ts +1 -1
  36. package/dist/blocks.d.ts.map +1 -1
  37. package/dist/capabilities.js +1 -1
  38. package/dist/capabilities.js.map +1 -1
  39. package/dist/check.d.ts +3 -0
  40. package/dist/check.d.ts.map +1 -1
  41. package/dist/check.js +3 -0
  42. package/dist/check.js.map +1 -1
  43. package/dist/city.d.ts +58 -50
  44. package/dist/city.d.ts.map +1 -1
  45. package/dist/city.js +160 -147
  46. package/dist/city.js.map +1 -1
  47. package/dist/cli/check/brand.d.ts.map +1 -1
  48. package/dist/cli/check/brand.js +30 -2
  49. package/dist/cli/check/brand.js.map +1 -1
  50. package/dist/cli/check/clock-rules.d.ts +4 -0
  51. package/dist/cli/check/clock-rules.d.ts.map +1 -0
  52. package/dist/cli/check/clock-rules.js +26 -0
  53. package/dist/cli/check/clock-rules.js.map +1 -0
  54. package/dist/cli/check/field-sight.d.ts +11 -0
  55. package/dist/cli/check/field-sight.d.ts.map +1 -0
  56. package/dist/cli/check/field-sight.js +113 -0
  57. package/dist/cli/check/field-sight.js.map +1 -0
  58. package/dist/cli/check/index.d.ts +2 -0
  59. package/dist/cli/check/index.d.ts.map +1 -1
  60. package/dist/cli/check/index.js +2 -0
  61. package/dist/cli/check/index.js.map +1 -1
  62. package/dist/cli/check/lenses.d.ts +1 -1
  63. package/dist/cli/check/lenses.d.ts.map +1 -1
  64. package/dist/cli/check/lenses.js +48 -2
  65. package/dist/cli/check/lenses.js.map +1 -1
  66. package/dist/cli/check/relations.d.ts +23 -0
  67. package/dist/cli/check/relations.d.ts.map +1 -1
  68. package/dist/cli/check/relations.js +55 -4
  69. package/dist/cli/check/relations.js.map +1 -1
  70. package/dist/cli/check.d.ts.map +1 -1
  71. package/dist/cli/check.js +7 -4
  72. package/dist/cli/check.js.map +1 -1
  73. package/dist/cli/create.d.ts.map +1 -1
  74. package/dist/cli/create.js +32 -0
  75. package/dist/cli/create.js.map +1 -1
  76. package/dist/cli/describe.d.ts.map +1 -1
  77. package/dist/cli/describe.js +71 -7
  78. package/dist/cli/describe.js.map +1 -1
  79. package/dist/cli/docs.d.ts.map +1 -1
  80. package/dist/cli/docs.js +4 -3
  81. package/dist/cli/docs.js.map +1 -1
  82. package/dist/cli/doctor.d.ts +18 -1
  83. package/dist/cli/doctor.d.ts.map +1 -1
  84. package/dist/cli/doctor.js +58 -5
  85. package/dist/cli/doctor.js.map +1 -1
  86. package/dist/cli/document-schema.d.ts +2 -0
  87. package/dist/cli/document-schema.d.ts.map +1 -1
  88. package/dist/cli/document-schema.js +154 -5
  89. package/dist/cli/document-schema.js.map +1 -1
  90. package/dist/cli/index.d.ts +1 -1
  91. package/dist/cli/index.d.ts.map +1 -1
  92. package/dist/cli/types.d.ts.map +1 -1
  93. package/dist/cli/types.js +16 -2
  94. package/dist/cli/types.js.map +1 -1
  95. package/dist/clock-readers.d.ts +18 -0
  96. package/dist/clock-readers.d.ts.map +1 -0
  97. package/dist/clock-readers.js +70 -0
  98. package/dist/clock-readers.js.map +1 -0
  99. package/dist/clock.d.ts +30 -0
  100. package/dist/clock.d.ts.map +1 -0
  101. package/dist/clock.js +41 -0
  102. package/dist/clock.js.map +1 -0
  103. package/dist/columns.d.ts.map +1 -1
  104. package/dist/columns.js +2 -1
  105. package/dist/columns.js.map +1 -1
  106. package/dist/conformance/fixtures.d.ts.map +1 -1
  107. package/dist/conformance/fixtures.js +491 -43
  108. package/dist/conformance/fixtures.js.map +1 -1
  109. package/dist/coverage-words.d.ts +18 -0
  110. package/dist/coverage-words.d.ts.map +1 -0
  111. package/dist/coverage-words.js +18 -0
  112. package/dist/coverage-words.js.map +1 -0
  113. package/dist/days.d.ts +53 -4
  114. package/dist/days.d.ts.map +1 -1
  115. package/dist/days.js +136 -16
  116. package/dist/days.js.map +1 -1
  117. package/dist/describe.d.ts +1 -0
  118. package/dist/describe.d.ts.map +1 -1
  119. package/dist/describe.js +1 -0
  120. package/dist/describe.js.map +1 -1
  121. package/dist/document/act-findings.d.ts.map +1 -1
  122. package/dist/document/act-findings.js +32 -4
  123. package/dist/document/act-findings.js.map +1 -1
  124. package/dist/document/amount.d.ts +4 -0
  125. package/dist/document/amount.d.ts.map +1 -0
  126. package/dist/document/amount.js +22 -0
  127. package/dist/document/amount.js.map +1 -0
  128. package/dist/document/block-context.d.ts.map +1 -1
  129. package/dist/document/block-context.js +1 -0
  130. package/dist/document/block-context.js.map +1 -1
  131. package/dist/document/blocks.d.ts +33 -10
  132. package/dist/document/blocks.d.ts.map +1 -1
  133. package/dist/document/blocks.js +139 -25
  134. package/dist/document/blocks.js.map +1 -1
  135. package/dist/document/brand-check.d.ts +5 -0
  136. package/dist/document/brand-check.d.ts.map +1 -1
  137. package/dist/document/brand-check.js +16 -2
  138. package/dist/document/brand-check.js.map +1 -1
  139. package/dist/document/compile-checked.d.ts.map +1 -1
  140. package/dist/document/compile-checked.js +12 -4
  141. package/dist/document/compile-checked.js.map +1 -1
  142. package/dist/document/compile.d.ts +0 -2
  143. package/dist/document/compile.d.ts.map +1 -1
  144. package/dist/document/compile.js +49 -24
  145. package/dist/document/compile.js.map +1 -1
  146. package/dist/document/compiled.d.ts +6 -2
  147. package/dist/document/compiled.d.ts.map +1 -1
  148. package/dist/document/compiled.js +94 -26
  149. package/dist/document/compiled.js.map +1 -1
  150. package/dist/document/computed-values.d.ts +3 -0
  151. package/dist/document/computed-values.d.ts.map +1 -1
  152. package/dist/document/computed-values.js +12 -2
  153. package/dist/document/computed-values.js.map +1 -1
  154. package/dist/document/describe-coverage.d.ts +3 -0
  155. package/dist/document/describe-coverage.d.ts.map +1 -1
  156. package/dist/document/describe-coverage.js +14 -6
  157. package/dist/document/describe-coverage.js.map +1 -1
  158. package/dist/document/describe-place.d.ts +6 -2
  159. package/dist/document/describe-place.d.ts.map +1 -1
  160. package/dist/document/describe-place.js +17 -9
  161. package/dist/document/describe-place.js.map +1 -1
  162. package/dist/document/diff.d.ts +2 -0
  163. package/dist/document/diff.d.ts.map +1 -1
  164. package/dist/document/diff.js +70 -11
  165. package/dist/document/diff.js.map +1 -1
  166. package/dist/document/durations.d.ts +8 -0
  167. package/dist/document/durations.d.ts.map +1 -0
  168. package/dist/document/durations.js +82 -0
  169. package/dist/document/durations.js.map +1 -0
  170. package/dist/document/edit.d.ts +1 -1
  171. package/dist/document/edit.d.ts.map +1 -1
  172. package/dist/document/edit.js +436 -27
  173. package/dist/document/edit.js.map +1 -1
  174. package/dist/document/expr/evaluate.d.ts +26 -1
  175. package/dist/document/expr/evaluate.d.ts.map +1 -1
  176. package/dist/document/expr/evaluate.js +55 -4
  177. package/dist/document/expr/evaluate.js.map +1 -1
  178. package/dist/document/field-spec.d.ts.map +1 -1
  179. package/dist/document/field-spec.js +15 -1
  180. package/dist/document/field-spec.js.map +1 -1
  181. package/dist/document/format-findings.d.ts +4 -0
  182. package/dist/document/format-findings.d.ts.map +1 -0
  183. package/dist/document/format-findings.js +39 -0
  184. package/dist/document/format-findings.js.map +1 -0
  185. package/dist/document/format-rules.d.ts +8 -0
  186. package/dist/document/format-rules.d.ts.map +1 -0
  187. package/dist/document/format-rules.js +19 -0
  188. package/dist/document/format-rules.js.map +1 -0
  189. package/dist/document/format-words.d.ts +9 -0
  190. package/dist/document/format-words.d.ts.map +1 -0
  191. package/dist/document/format-words.js +31 -0
  192. package/dist/document/format-words.js.map +1 -0
  193. package/dist/document/framework-path.d.ts +11 -0
  194. package/dist/document/framework-path.d.ts.map +1 -0
  195. package/dist/document/framework-path.js +122 -0
  196. package/dist/document/framework-path.js.map +1 -0
  197. package/dist/document/graview-template.d.ts +2 -2
  198. package/dist/document/index.d.ts +2 -2
  199. package/dist/document/index.d.ts.map +1 -1
  200. package/dist/document/index.js +1 -1
  201. package/dist/document/index.js.map +1 -1
  202. package/dist/document/linked-findings.d.ts +5 -0
  203. package/dist/document/linked-findings.d.ts.map +1 -0
  204. package/dist/document/linked-findings.js +100 -0
  205. package/dist/document/linked-findings.js.map +1 -0
  206. package/dist/document/migrate.d.ts +1 -0
  207. package/dist/document/migrate.d.ts.map +1 -1
  208. package/dist/document/migrate.js +48 -1
  209. package/dist/document/migrate.js.map +1 -1
  210. package/dist/document/money.d.ts +14 -0
  211. package/dist/document/money.d.ts.map +1 -0
  212. package/dist/document/money.js +14 -0
  213. package/dist/document/money.js.map +1 -0
  214. package/dist/document/policy-words.d.ts +4 -0
  215. package/dist/document/policy-words.d.ts.map +1 -1
  216. package/dist/document/policy-words.js +34 -4
  217. package/dist/document/policy-words.js.map +1 -1
  218. package/dist/document/right-names.d.ts +10 -0
  219. package/dist/document/right-names.d.ts.map +1 -0
  220. package/dist/document/right-names.js +57 -0
  221. package/dist/document/right-names.js.map +1 -0
  222. package/dist/document/rule-line.d.ts.map +1 -1
  223. package/dist/document/rule-line.js +16 -12
  224. package/dist/document/rule-line.js.map +1 -1
  225. package/dist/document/rules.d.ts.map +1 -1
  226. package/dist/document/rules.js +15 -6
  227. package/dist/document/rules.js.map +1 -1
  228. package/dist/document/schema.d.ts +142 -22
  229. package/dist/document/schema.d.ts.map +1 -1
  230. package/dist/document/schema.js +86 -10
  231. package/dist/document/schema.js.map +1 -1
  232. package/dist/document/template-parse.d.ts.map +1 -1
  233. package/dist/document/template-parse.js +45 -5
  234. package/dist/document/template-parse.js.map +1 -1
  235. package/dist/document/template.d.ts +16 -14
  236. package/dist/document/template.d.ts.map +1 -1
  237. package/dist/document/template.js +52 -30
  238. package/dist/document/template.js.map +1 -1
  239. package/dist/document/thumbnail.d.ts.map +1 -1
  240. package/dist/document/thumbnail.js +4 -3
  241. package/dist/document/thumbnail.js.map +1 -1
  242. package/dist/document/to-document.d.ts +0 -1
  243. package/dist/document/to-document.d.ts.map +1 -1
  244. package/dist/document/to-document.js +30 -2
  245. package/dist/document/to-document.js.map +1 -1
  246. package/dist/document/view-specs.d.ts.map +1 -1
  247. package/dist/document/view-specs.js +3 -0
  248. package/dist/document/view-specs.js.map +1 -1
  249. package/dist/document/views.d.ts +38 -4
  250. package/dist/document/views.d.ts.map +1 -1
  251. package/dist/document/views.js +81 -26
  252. package/dist/document/views.js.map +1 -1
  253. package/dist/document.schema.json +1184 -141
  254. package/dist/excerpt-of.d.ts +14 -0
  255. package/dist/excerpt-of.d.ts.map +1 -0
  256. package/dist/excerpt-of.js +120 -0
  257. package/dist/excerpt-of.js.map +1 -0
  258. package/dist/excerpt.d.ts +9 -0
  259. package/dist/excerpt.d.ts.map +1 -0
  260. package/dist/excerpt.js +43 -0
  261. package/dist/excerpt.js.map +1 -0
  262. package/dist/field-sight.d.ts +33 -0
  263. package/dist/field-sight.d.ts.map +1 -0
  264. package/dist/field-sight.js +313 -0
  265. package/dist/field-sight.js.map +1 -0
  266. package/dist/forms.d.ts +2 -0
  267. package/dist/forms.d.ts.map +1 -1
  268. package/dist/forms.js +3 -0
  269. package/dist/forms.js.map +1 -1
  270. package/dist/graph/archived.d.ts +34 -0
  271. package/dist/graph/archived.d.ts.map +1 -0
  272. package/dist/graph/archived.js +25 -0
  273. package/dist/graph/archived.js.map +1 -0
  274. package/dist/graph/diff.d.ts +16 -0
  275. package/dist/graph/diff.d.ts.map +1 -1
  276. package/dist/graph/diff.js +20 -1
  277. package/dist/graph/diff.js.map +1 -1
  278. package/dist/graph/graph.d.ts +37 -13
  279. package/dist/graph/graph.d.ts.map +1 -1
  280. package/dist/graph/graph.js +84 -41
  281. package/dist/graph/graph.js.map +1 -1
  282. package/dist/graph/tracked.d.ts +8 -8
  283. package/dist/graph/tracked.d.ts.map +1 -1
  284. package/dist/graph/tracked.js +15 -20
  285. package/dist/graph/tracked.js.map +1 -1
  286. package/dist/graph/types.d.ts +16 -8
  287. package/dist/graph/types.d.ts.map +1 -1
  288. package/dist/graph/types.js.map +1 -1
  289. package/dist/grid-sort.d.ts +20 -0
  290. package/dist/grid-sort.d.ts.map +1 -0
  291. package/dist/grid-sort.js +58 -0
  292. package/dist/grid-sort.js.map +1 -0
  293. package/dist/history.d.ts +88 -0
  294. package/dist/history.d.ts.map +1 -0
  295. package/dist/history.js +146 -0
  296. package/dist/history.js.map +1 -0
  297. package/dist/import/coerce.d.ts +45 -0
  298. package/dist/import/coerce.d.ts.map +1 -0
  299. package/dist/import/coerce.js +252 -0
  300. package/dist/import/coerce.js.map +1 -0
  301. package/dist/import/csv.d.ts +16 -0
  302. package/dist/import/csv.d.ts.map +1 -0
  303. package/dist/import/csv.js +77 -0
  304. package/dist/import/csv.js.map +1 -0
  305. package/dist/import/index.d.ts +17 -0
  306. package/dist/import/index.d.ts.map +1 -0
  307. package/dist/import/index.js +13 -0
  308. package/dist/import/index.js.map +1 -0
  309. package/dist/import/mapping.d.ts +99 -0
  310. package/dist/import/mapping.d.ts.map +1 -0
  311. package/dist/import/mapping.js +182 -0
  312. package/dist/import/mapping.js.map +1 -0
  313. package/dist/import/rows.d.ts +116 -0
  314. package/dist/import/rows.d.ts.map +1 -0
  315. package/dist/import/rows.js +584 -0
  316. package/dist/import/rows.js.map +1 -0
  317. package/dist/index.d.ts +53 -26
  318. package/dist/index.d.ts.map +1 -1
  319. package/dist/index.js +38 -18
  320. package/dist/index.js.map +1 -1
  321. package/dist/invariants/engine.d.ts +5 -1
  322. package/dist/invariants/engine.d.ts.map +1 -1
  323. package/dist/invariants/engine.js +4 -3
  324. package/dist/invariants/engine.js.map +1 -1
  325. package/dist/invariants/types.d.ts +18 -3
  326. package/dist/invariants/types.d.ts.map +1 -1
  327. package/dist/json-schema.d.ts +1 -0
  328. package/dist/json-schema.d.ts.map +1 -1
  329. package/dist/json-schema.js +2 -0
  330. package/dist/json-schema.js.map +1 -1
  331. package/dist/kind-list.d.ts +78 -0
  332. package/dist/kind-list.d.ts.map +1 -0
  333. package/dist/kind-list.js +176 -0
  334. package/dist/kind-list.js.map +1 -0
  335. package/dist/labels.d.ts.map +1 -1
  336. package/dist/labels.js +2 -1
  337. package/dist/labels.js.map +1 -1
  338. package/dist/lines.d.ts +1 -0
  339. package/dist/lines.d.ts.map +1 -1
  340. package/dist/lines.js +5 -3
  341. package/dist/lines.js.map +1 -1
  342. package/dist/linked.d.ts +95 -0
  343. package/dist/linked.d.ts.map +1 -0
  344. package/dist/linked.js +181 -0
  345. package/dist/linked.js.map +1 -0
  346. package/dist/markdown.d.ts +102 -0
  347. package/dist/markdown.d.ts.map +1 -0
  348. package/dist/markdown.js +460 -0
  349. package/dist/markdown.js.map +1 -0
  350. package/dist/mutations/arg-shape.d.ts +95 -0
  351. package/dist/mutations/arg-shape.d.ts.map +1 -0
  352. package/dist/mutations/arg-shape.js +101 -0
  353. package/dist/mutations/arg-shape.js.map +1 -0
  354. package/dist/mutations/define-mutation.d.ts +48 -2
  355. package/dist/mutations/define-mutation.d.ts.map +1 -1
  356. package/dist/mutations/define-mutation.js +103 -36
  357. package/dist/mutations/define-mutation.js.map +1 -1
  358. package/dist/mutations/derive-edits.d.ts +16 -1
  359. package/dist/mutations/derive-edits.d.ts.map +1 -1
  360. package/dist/mutations/derive-edits.js +146 -56
  361. package/dist/mutations/derive-edits.js.map +1 -1
  362. package/dist/mutations/derive-repeats.d.ts +8 -0
  363. package/dist/mutations/derive-repeats.d.ts.map +1 -0
  364. package/dist/mutations/derive-repeats.js +118 -0
  365. package/dist/mutations/derive-repeats.js.map +1 -0
  366. package/dist/mutations/derived-names.d.ts +22 -0
  367. package/dist/mutations/derived-names.d.ts.map +1 -0
  368. package/dist/mutations/derived-names.js +21 -0
  369. package/dist/mutations/derived-names.js.map +1 -0
  370. package/dist/mutations/edit-start.d.ts +28 -0
  371. package/dist/mutations/edit-start.d.ts.map +1 -0
  372. package/dist/mutations/edit-start.js +24 -0
  373. package/dist/mutations/edit-start.js.map +1 -0
  374. package/dist/mutations/form.d.ts +33 -1
  375. package/dist/mutations/form.d.ts.map +1 -1
  376. package/dist/mutations/form.js +23 -2
  377. package/dist/mutations/form.js.map +1 -1
  378. package/dist/mutations/invalid-arguments.d.ts +14 -0
  379. package/dist/mutations/invalid-arguments.d.ts.map +1 -0
  380. package/dist/mutations/invalid-arguments.js +18 -0
  381. package/dist/mutations/invalid-arguments.js.map +1 -0
  382. package/dist/mutations/keep-link.d.ts +27 -0
  383. package/dist/mutations/keep-link.d.ts.map +1 -0
  384. package/dist/mutations/keep-link.js +56 -0
  385. package/dist/mutations/keep-link.js.map +1 -0
  386. package/dist/mutations/kept-arguments.d.ts +26 -0
  387. package/dist/mutations/kept-arguments.d.ts.map +1 -0
  388. package/dist/mutations/kept-arguments.js +77 -0
  389. package/dist/mutations/kept-arguments.js.map +1 -0
  390. package/dist/mutations/node-ref.d.ts +0 -80
  391. package/dist/mutations/node-ref.d.ts.map +1 -1
  392. package/dist/mutations/node-ref.js +0 -93
  393. package/dist/mutations/node-ref.js.map +1 -1
  394. package/dist/mutations/types.d.ts +17 -1
  395. package/dist/mutations/types.d.ts.map +1 -1
  396. package/dist/mutations/words.d.ts +0 -13
  397. package/dist/mutations/words.d.ts.map +1 -1
  398. package/dist/mutations/words.js +1 -12
  399. package/dist/mutations/words.js.map +1 -1
  400. package/dist/navigate.d.ts +13 -0
  401. package/dist/navigate.d.ts.map +1 -0
  402. package/dist/navigate.js +13 -0
  403. package/dist/navigate.js.map +1 -0
  404. package/dist/ops/digest.d.ts +33 -0
  405. package/dist/ops/digest.d.ts.map +1 -0
  406. package/dist/ops/digest.js +47 -0
  407. package/dist/ops/digest.js.map +1 -0
  408. package/dist/ops/kept-fields.d.ts +7 -0
  409. package/dist/ops/kept-fields.d.ts.map +1 -0
  410. package/dist/ops/kept-fields.js +24 -0
  411. package/dist/ops/kept-fields.js.map +1 -0
  412. package/dist/ops/lineage.d.ts +43 -0
  413. package/dist/ops/lineage.d.ts.map +1 -0
  414. package/dist/ops/lineage.js +27 -0
  415. package/dist/ops/lineage.js.map +1 -0
  416. package/dist/ops/log.d.ts +6 -0
  417. package/dist/ops/log.d.ts.map +1 -1
  418. package/dist/ops/log.js +20 -12
  419. package/dist/ops/log.js.map +1 -1
  420. package/dist/ops/provenance.d.ts +68 -0
  421. package/dist/ops/provenance.d.ts.map +1 -0
  422. package/dist/ops/provenance.js +83 -0
  423. package/dist/ops/provenance.js.map +1 -0
  424. package/dist/ops/suggestions.d.ts +26 -0
  425. package/dist/ops/suggestions.d.ts.map +1 -0
  426. package/dist/ops/suggestions.js +21 -0
  427. package/dist/ops/suggestions.js.map +1 -0
  428. package/dist/ops/tidying.d.ts +48 -0
  429. package/dist/ops/tidying.d.ts.map +1 -0
  430. package/dist/ops/tidying.js +84 -0
  431. package/dist/ops/tidying.js.map +1 -0
  432. package/dist/ops/types.d.ts +42 -0
  433. package/dist/ops/types.d.ts.map +1 -1
  434. package/dist/ops/undo.d.ts.map +1 -1
  435. package/dist/ops/undo.js +10 -0
  436. package/dist/ops/undo.js.map +1 -1
  437. package/dist/ops/withheld.d.ts +25 -2
  438. package/dist/ops/withheld.d.ts.map +1 -1
  439. package/dist/ops/withheld.js +6 -15
  440. package/dist/ops/withheld.js.map +1 -1
  441. package/dist/past.d.ts +35 -0
  442. package/dist/past.d.ts.map +1 -0
  443. package/dist/past.js +173 -0
  444. package/dist/past.js.map +1 -0
  445. package/dist/permissions/policy.d.ts +13 -1
  446. package/dist/permissions/policy.d.ts.map +1 -1
  447. package/dist/permissions/policy.js +44 -9
  448. package/dist/permissions/policy.js.map +1 -1
  449. package/dist/permissions/sight.d.ts +40 -2
  450. package/dist/permissions/sight.d.ts.map +1 -1
  451. package/dist/permissions/sight.js +25 -2
  452. package/dist/permissions/sight.js.map +1 -1
  453. package/dist/permissions/types.d.ts +21 -0
  454. package/dist/permissions/types.d.ts.map +1 -1
  455. package/dist/permissions/types.js.map +1 -1
  456. package/dist/places.d.ts +6 -51
  457. package/dist/places.d.ts.map +1 -1
  458. package/dist/places.js +50 -144
  459. package/dist/places.js.map +1 -1
  460. package/dist/provenance.d.ts +14 -0
  461. package/dist/provenance.d.ts.map +1 -0
  462. package/dist/provenance.js +13 -0
  463. package/dist/provenance.js.map +1 -0
  464. package/dist/repeat-words.d.ts +13 -0
  465. package/dist/repeat-words.d.ts.map +1 -0
  466. package/dist/repeat-words.js +56 -0
  467. package/dist/repeat-words.js.map +1 -0
  468. package/dist/repeat.d.ts +59 -0
  469. package/dist/repeat.d.ts.map +1 -0
  470. package/dist/repeat.js +155 -0
  471. package/dist/repeat.js.map +1 -0
  472. package/dist/scaffold/agents.d.ts.map +1 -1
  473. package/dist/scaffold/agents.js +13 -0
  474. package/dist/scaffold/agents.js.map +1 -1
  475. package/dist/scaffold/project.d.ts.map +1 -1
  476. package/dist/scaffold/project.js +18 -0
  477. package/dist/scaffold/project.js.map +1 -1
  478. package/dist/scaffold/ui.d.ts.map +1 -1
  479. package/dist/scaffold/ui.js +17 -7
  480. package/dist/scaffold/ui.js.map +1 -1
  481. package/dist/scene-districts.d.ts +2 -1
  482. package/dist/scene-districts.d.ts.map +1 -1
  483. package/dist/scene-districts.js +2 -1
  484. package/dist/scene-districts.js.map +1 -1
  485. package/dist/scene.d.ts +4 -2
  486. package/dist/scene.d.ts.map +1 -1
  487. package/dist/scene.js +2 -1
  488. package/dist/scene.js.map +1 -1
  489. package/dist/schema/amount-mark.d.ts +13 -0
  490. package/dist/schema/amount-mark.d.ts.map +1 -0
  491. package/dist/schema/amount-mark.js +20 -0
  492. package/dist/schema/amount-mark.js.map +1 -0
  493. package/dist/schema/amount-words.d.ts +12 -0
  494. package/dist/schema/amount-words.d.ts.map +1 -0
  495. package/dist/schema/amount-words.js +31 -0
  496. package/dist/schema/amount-words.js.map +1 -0
  497. package/dist/schema/app-address.d.ts +5 -0
  498. package/dist/schema/app-address.d.ts.map +1 -0
  499. package/dist/schema/app-address.js +10 -0
  500. package/dist/schema/app-address.js.map +1 -0
  501. package/dist/schema/app-link-field.d.ts +4 -0
  502. package/dist/schema/app-link-field.d.ts.map +1 -0
  503. package/dist/schema/app-link-field.js +19 -0
  504. package/dist/schema/app-link-field.js.map +1 -0
  505. package/dist/schema/app-link.d.ts +38 -0
  506. package/dist/schema/app-link.d.ts.map +1 -0
  507. package/dist/schema/app-link.js +38 -0
  508. package/dist/schema/app-link.js.map +1 -0
  509. package/dist/schema/define-node.d.ts +39 -92
  510. package/dist/schema/define-node.d.ts.map +1 -1
  511. package/dist/schema/define-node.js +8 -246
  512. package/dist/schema/define-node.js.map +1 -1
  513. package/dist/schema/field-words.d.ts +45 -0
  514. package/dist/schema/field-words.d.ts.map +1 -0
  515. package/dist/schema/field-words.js +124 -0
  516. package/dist/schema/field-words.js.map +1 -0
  517. package/dist/schema/files.d.ts +8 -0
  518. package/dist/schema/files.d.ts.map +1 -1
  519. package/dist/schema/files.js.map +1 -1
  520. package/dist/schema/json-schema.d.ts +6 -1
  521. package/dist/schema/json-schema.d.ts.map +1 -1
  522. package/dist/schema/json-schema.js +101 -2
  523. package/dist/schema/json-schema.js.map +1 -1
  524. package/dist/schema/linked-field.d.ts +6 -0
  525. package/dist/schema/linked-field.d.ts.map +1 -0
  526. package/dist/schema/linked-field.js +34 -0
  527. package/dist/schema/linked-field.js.map +1 -0
  528. package/dist/schema/linked-reads.d.ts +20 -0
  529. package/dist/schema/linked-reads.d.ts.map +1 -0
  530. package/dist/schema/linked-reads.js +69 -0
  531. package/dist/schema/linked-reads.js.map +1 -0
  532. package/dist/schema/linked-schema.d.ts +5 -0
  533. package/dist/schema/linked-schema.d.ts.map +1 -0
  534. package/dist/schema/linked-schema.js +9 -0
  535. package/dist/schema/linked-schema.js.map +1 -0
  536. package/dist/schema/linked.d.ts +147 -0
  537. package/dist/schema/linked.d.ts.map +1 -0
  538. package/dist/schema/linked.js +151 -0
  539. package/dist/schema/linked.js.map +1 -0
  540. package/dist/schema/markdown-field.d.ts +4 -0
  541. package/dist/schema/markdown-field.d.ts.map +1 -0
  542. package/dist/schema/markdown-field.js +20 -0
  543. package/dist/schema/markdown-field.js.map +1 -0
  544. package/dist/schema/markdown.d.ts +6 -0
  545. package/dist/schema/markdown.d.ts.map +1 -0
  546. package/dist/schema/markdown.js +27 -0
  547. package/dist/schema/markdown.js.map +1 -0
  548. package/dist/schema/reading.d.ts +86 -0
  549. package/dist/schema/reading.d.ts.map +1 -0
  550. package/dist/schema/reading.js +325 -0
  551. package/dist/schema/reading.js.map +1 -0
  552. package/dist/schema/repeat-field.d.ts +5 -0
  553. package/dist/schema/repeat-field.d.ts.map +1 -0
  554. package/dist/schema/repeat-field.js +20 -0
  555. package/dist/schema/repeat-field.js.map +1 -0
  556. package/dist/schema/schema.d.ts.map +1 -1
  557. package/dist/schema/schema.js +12 -1
  558. package/dist/schema/schema.js.map +1 -1
  559. package/dist/schema/to-json-schema.d.ts +14 -0
  560. package/dist/schema/to-json-schema.d.ts.map +1 -0
  561. package/dist/schema/to-json-schema.js +616 -0
  562. package/dist/schema/to-json-schema.js.map +1 -0
  563. package/dist/schema/typed-field-builders.d.ts +8 -0
  564. package/dist/schema/typed-field-builders.d.ts.map +1 -0
  565. package/dist/schema/typed-field-builders.js +30 -0
  566. package/dist/schema/typed-field-builders.js.map +1 -0
  567. package/dist/schema/typed-field-of.d.ts +4 -0
  568. package/dist/schema/typed-field-of.d.ts.map +1 -0
  569. package/dist/schema/typed-field-of.js +14 -0
  570. package/dist/schema/typed-field-of.js.map +1 -0
  571. package/dist/schema/typed-fields.d.ts +11 -0
  572. package/dist/schema/typed-fields.d.ts.map +1 -0
  573. package/dist/schema/typed-fields.js +16 -0
  574. package/dist/schema/typed-fields.js.map +1 -0
  575. package/dist/schema/types.d.ts +31 -0
  576. package/dist/schema/types.d.ts.map +1 -1
  577. package/dist/schema/value-words.d.ts +21 -0
  578. package/dist/schema/value-words.d.ts.map +1 -0
  579. package/dist/schema/value-words.js +32 -0
  580. package/dist/schema/value-words.js.map +1 -0
  581. package/dist/search.d.ts +91 -4
  582. package/dist/search.d.ts.map +1 -1
  583. package/dist/search.js +317 -54
  584. package/dist/search.js.map +1 -1
  585. package/dist/seat-of.d.ts +9 -0
  586. package/dist/seat-of.d.ts.map +1 -0
  587. package/dist/seat-of.js +14 -0
  588. package/dist/seat-of.js.map +1 -0
  589. package/dist/seat.d.ts +19 -0
  590. package/dist/seat.d.ts.map +1 -0
  591. package/dist/seat.js +19 -0
  592. package/dist/seat.js.map +1 -0
  593. package/dist/seen.d.ts +15 -45
  594. package/dist/seen.d.ts.map +1 -1
  595. package/dist/seen.js +49 -135
  596. package/dist/seen.js.map +1 -1
  597. package/dist/store.d.ts +104 -1
  598. package/dist/store.d.ts.map +1 -1
  599. package/dist/store.js +214 -30
  600. package/dist/store.js.map +1 -1
  601. package/dist/theme/derive.d.ts +16 -0
  602. package/dist/theme/derive.d.ts.map +1 -1
  603. package/dist/theme/derive.js +14 -0
  604. package/dist/theme/derive.js.map +1 -1
  605. package/dist/theme/marks.d.ts +19 -2
  606. package/dist/theme/marks.d.ts.map +1 -1
  607. package/dist/theme/marks.js +67 -2
  608. package/dist/theme/marks.js.map +1 -1
  609. package/dist/theme/types.d.ts +14 -3
  610. package/dist/theme/types.d.ts.map +1 -1
  611. package/dist/theme/types.js.map +1 -1
  612. package/dist/tidying.d.ts +62 -0
  613. package/dist/tidying.d.ts.map +1 -0
  614. package/dist/tidying.js +131 -0
  615. package/dist/tidying.js.map +1 -0
  616. package/dist/typed.d.ts +12 -3
  617. package/dist/typed.d.ts.map +1 -1
  618. package/dist/typed.js.map +1 -1
  619. package/dist/validate-graph.d.ts.map +1 -1
  620. package/dist/validate-graph.js +3 -10
  621. package/dist/validate-graph.js.map +1 -1
  622. package/dist/version.d.ts +1 -1
  623. package/dist/version.js +1 -1
  624. package/dist/via.d.ts.map +1 -1
  625. package/dist/via.js +2 -1
  626. package/dist/via.js.map +1 -1
  627. package/dist/views/address.d.ts +13 -0
  628. package/dist/views/address.d.ts.map +1 -0
  629. package/dist/views/address.js +29 -0
  630. package/dist/views/address.js.map +1 -0
  631. package/dist/views/types.d.ts +106 -8
  632. package/dist/views/types.d.ts.map +1 -1
  633. package/dist/views/types.js +24 -4
  634. package/dist/views/types.js.map +1 -1
  635. package/dist/village.d.ts +63 -0
  636. package/dist/village.d.ts.map +1 -0
  637. package/dist/village.js +143 -0
  638. package/dist/village.js.map +1 -0
  639. package/dist/watched.d.ts +12 -45
  640. package/dist/watched.d.ts.map +1 -1
  641. package/dist/watched.js +7 -119
  642. package/dist/watched.js.map +1 -1
  643. package/dist/words.d.ts +33 -0
  644. package/dist/words.d.ts.map +1 -0
  645. package/dist/words.js +36 -0
  646. package/dist/words.js.map +1 -0
  647. package/package.json +57 -2
@@ -1,26 +1,37 @@
1
+ import { DERIVED_ACTS, derivedActOf, derivedActsOf, givenWhenNeverArchived, givenWhenNeverTidied } from "../mutations/derived-names.js";
1
2
  import { z } from "zod";
2
3
  import { ExprSyntaxError, parseExpr } from "./expr/parse.js";
3
4
  import { printExpr } from "./expr/print.js";
4
5
  import { error } from "./findings.js";
5
6
  import { coerce } from "./migrate.js";
6
7
  import { outsideRange, rangeWords } from "./range.js";
8
+ import { formatWords } from "./format-words.js";
9
+ import { formatFits, formatMisplaced } from "./format-rules.js";
10
+ /** Why a format is refused where it does not fit, in the checker's words (`field-format`). */
11
+ const refusedFormat = (format, type) => {
12
+ const { sentence, fix } = formatMisplaced(format, type);
13
+ return `${sentence}; ${fix}`;
14
+ };
7
15
  import { farEnd } from "./far-end.js";
8
16
  import { ActSpec, EDGE_NAME, EdgeSpec, FIELD_NAME, FIELD_TYPES, FieldSpec, GrantSpec, KindSpec, NAME, RuleSpec, SightSpec, } from "./schema.js";
9
17
  import { SHIPPED_LENSES, isShippedLens, SHIPPED_LENS_NAMES } from "../places.js";
10
18
  import { placeSlug } from "../views/types.js";
19
+ import { documentListFields, kindListFindings, kindListWords, listGroup, listSort, sortTypeOfDocumentField } from "../kind-list.js";
11
20
  import { computedOf, validateComputed } from "./computed.js";
12
21
  import { parseTemplate, templateBraces, TemplateError } from "./template-parse.js";
13
22
  import { validateViews, VIEW_SLOTS } from "./views.js";
14
- import { brandFindings } from "./brand-check.js";
23
+ import { brandFindings, emojiIconSentence } from "./brand-check.js";
24
+ import { emojiOf } from "../theme/marks.js";
15
25
  import { canonicalize } from "./canonical.js";
16
26
  import { quotedAtTheEnd } from "./quote.js";
17
27
  import { isRecord as isObject, respellDocument } from "./respell.js";
18
28
  import { refName } from "./compiled.js";
29
+ import { localeSentence } from "./diff.js";
19
30
  import { accentProblem } from "../theme/accent.js";
20
31
  import { pageFieldFindings, pageNames, renamedOnPage, withoutOnPage } from "./page-fields.js";
21
32
  import { capitalize, listed as listOf } from "../capital.js";
22
33
  import { quoted } from "./quote.js";
23
- import { FIRST_GRANT, FIRST_SIGHT, grantBody, grantGone, grantSentence, NO_GRANT_LEFT, NO_SIGHT_LEFT, peopleKinds, peopleSentence, nounWords, pluralWords as pluralOf, sightGone, sightSentence, sightWords, whoWords } from "./policy-words.js";
34
+ import { FIRST_GRANT, FIRST_SIGHT, grantBody, grantGone, grantSentence, NO_GRANT_LEFT, NO_SIGHT_LEFT, peopleKinds, peopleSentence, archivesSentence, tidyingSentence, nounWords, pluralWords as pluralOf, sightGone, sightSentence, sightWords, whoWords } from "./policy-words.js";
24
35
  /** The ops, for tool schemas and the guide. */
25
36
  export const EDIT_OPS = [
26
37
  "add-kind",
@@ -31,8 +42,10 @@ export const EDIT_OPS = [
31
42
  "retype-field",
32
43
  "set-options",
33
44
  "set-range",
45
+ "set-format",
34
46
  "set-required",
35
47
  "set-default",
48
+ "set-repeats",
36
49
  "remove-field",
37
50
  "add-relation",
38
51
  "rename-relation",
@@ -51,10 +64,13 @@ export const EDIT_OPS = [
51
64
  "set-page-fields",
52
65
  "add-lens",
53
66
  "remove-lens",
67
+ "set-lens-hidden",
54
68
  "set-home",
55
69
  "arrange-pages",
56
70
  "set-computed",
57
71
  "set-people",
72
+ "set-archives",
73
+ "set-tidying",
58
74
  "add-grant",
59
75
  "remove-grant",
60
76
  "add-sight",
@@ -65,6 +81,10 @@ const KEYWORDS = new Set(["and", "or", "not", "in", "where", "true", "false", "n
65
81
  const MAX_EDITS = 50;
66
82
  // ── shapes ─────────────────────────────────────────────────────────────────
67
83
  const kindName = z.string().regex(NAME, 'kind names are lower-case words joined by hyphens, like "guest-list"');
84
+ const listKey = z.string().min(1).max(120);
85
+ const listDirection = z.enum(["asc", "desc"]).optional();
86
+ const listSortShape = z.union([listKey, z.object({ by: listKey, direction: listDirection, then: z.union([listKey, z.object({ by: listKey, direction: listDirection }).strict()]).optional() }).strict()]);
87
+ const listGroupShape = z.union([listKey, z.object({ by: listKey, order: z.array(z.string().min(1).max(80)).max(40).optional(), closed: z.array(z.string().min(1).max(80)).max(40).optional() }).strict()]);
68
88
  const fieldName = z.string().regex(FIELD_NAME, 'field names are one word or camelCase, like "dueDate"');
69
89
  const edgeName = z.string().regex(EDGE_NAME, 'relation names are one camelCase word, like "tendedBy"');
70
90
  const actName = z.string().regex(NAME, 'act names are lower-case words joined by hyphens, like "mark-paid"');
@@ -75,11 +95,13 @@ const SHAPES = {
75
95
  "remove-kind": z.object({ op: z.literal("remove-kind"), kind: kindName }).strict(),
76
96
  "add-field": z.object({ op: z.literal("add-field"), kind: kindName, field: fieldName, fill: z.unknown().optional(), spec: z.record(z.string(), z.unknown()).optional() }).passthrough(),
77
97
  "rename-field": z.object({ op: z.literal("rename-field"), kind: kindName, field: fieldName, to: fieldName }).strict(),
78
- "retype-field": z.object({ op: z.literal("retype-field"), kind: kindName, field: fieldName, type: z.enum(FIELD_TYPES), options: z.array(z.string().min(1).max(80)).min(1).max(100).optional(), of: z.enum(["string", "number", "date", "image", "file"]).optional(), format: z.enum(["money", "percent", "duration"]).optional() }).strict(),
98
+ "retype-field": z.object({ op: z.literal("retype-field"), kind: kindName, field: fieldName, type: z.enum(FIELD_TYPES), options: z.array(z.string().min(1).max(80)).min(1).max(100).optional(), of: z.enum(["string", "number", "date", "image", "file"]).optional(), format: z.enum(["money", "percent", "duration", "markdown"]).optional() }).strict(),
79
99
  "set-options": z.object({ op: z.literal("set-options"), kind: kindName, field: fieldName, add: z.array(z.string().min(1).max(80)).optional(), remove: z.array(z.string().min(1).max(80)).optional() }).strict(),
100
+ "set-format": z.object({ op: z.literal("set-format"), kind: kindName, field: fieldName, format: z.union([z.enum(["money", "percent", "duration", "markdown"]), z.null()]).optional(), unit: z.union([z.string().min(1).max(12), z.null()]).optional() }).strict(),
80
101
  "set-range": z.object({ op: z.literal("set-range"), kind: kindName, field: fieldName, min: z.union([z.number(), z.null()]).optional(), max: z.union([z.number(), z.null()]).optional(), step: z.union([z.number().positive(), z.null()]).optional() }).strict(),
81
102
  "set-required": z.object({ op: z.literal("set-required"), kind: kindName, field: fieldName, required: z.boolean() }).strict(),
82
103
  "set-default": z.object({ op: z.literal("set-default"), kind: kindName, field: fieldName, default: z.unknown() }).strict(),
104
+ "set-repeats": z.object({ op: z.literal("set-repeats"), kind: kindName, field: fieldName, repeats: z.boolean() }).strict(),
83
105
  "remove-field": z.object({ op: z.literal("remove-field"), kind: kindName, field: fieldName }).strict(),
84
106
  "add-relation": z.object({ op: z.literal("add-relation"), kind: kindName, relation: edgeName }).passthrough(),
85
107
  "rename-relation": z.object({ op: z.literal("rename-relation"), kind: kindName, relation: edgeName, to: edgeName }).strict(),
@@ -97,7 +119,7 @@ const SHAPES = {
97
119
  locale: z.union([z.string(), z.null()]).optional(),
98
120
  // The rest of the brand (FR-124, FR-125): each as the document holds it, null to clear it.
99
121
  logo: z.union([z.string().min(1), z.object({ src: z.string().min(1), alt: z.string().min(1).max(120).optional() }).strict(), z.null()]).optional(),
100
- favicon: z.union([z.string().min(1), z.null()]).optional(),
122
+ favicon: z.union([z.string().min(1), z.object({ emoji: z.string() }).strict(), z.null()]).optional(),
101
123
  typography: z.union([z.object({ display: z.union([z.string().min(1).max(200), z.null()]).optional(), body: z.union([z.string().min(1).max(200), z.null()]).optional(), mono: z.union([z.string().min(1).max(200), z.null()]).optional() }).strict(), z.null()]).optional(),
102
124
  shape: z.union([z.object({ radius: z.union([z.number().min(0).max(32), z.null()]).optional(), density: z.union([z.number().min(0.75).max(1.5), z.null()]).optional() }).strict(), z.null()]).optional(),
103
125
  accents: z.union([z.record(z.string(), z.union([z.number().min(0).max(360), z.null()])), z.null()]).optional(),
@@ -128,11 +150,15 @@ const SHAPES = {
128
150
  on: kindName.optional(),
129
151
  bindings: z.record(z.string(), z.unknown()).optional(),
130
152
  options: z.record(z.string(), z.unknown()).optional(),
153
+ // False: the place's page leaves off the forms that begin its kind.
154
+ create: z.boolean().optional(),
131
155
  at: z.number().int().min(0).optional(),
132
156
  replace: lensTitle.optional(),
133
157
  })
134
158
  .strict(),
135
159
  "remove-lens": z.object({ op: z.literal("remove-lens"), title: lensTitle, on: kindName.optional() }).strict(),
160
+ // A lens kept off the bar's places, the page list and the home's gallery, still reached by its address, a link or navigate.
161
+ "set-lens-hidden": z.object({ op: z.literal("set-lens-hidden"), title: lensTitle, on: kindName.optional(), hidden: z.boolean() }).strict(),
136
162
  "set-home": z.object({ op: z.literal("set-home"), blocks: z.union([z.array(z.unknown()).min(1), z.null()]) }).strict(),
137
163
  "arrange-pages": z
138
164
  .object({
@@ -143,6 +169,12 @@ const SHAPES = {
143
169
  primary: z.union([z.array(z.string().min(1).max(80)).max(40), z.null()]).optional(),
144
170
  scene: z.union([z.string().min(1).max(40), z.null()]).optional(),
145
171
  pages: z.union([z.string().min(1).max(40), z.null()]).optional(),
172
+ // What a kind's list offers to filter by: `{ "request": ["status", "became.stage"] }`; null or [] gives a kind back its derived filters.
173
+ filters: z.record(kindName, z.union([z.array(z.string().min(1).max(120)).max(40), z.null()])).optional(),
174
+ // The order a kind's list opens in: `{ "feature": { "by": "score", "direction": "desc", "then": "label" } }` or a key; null gives it back its own.
175
+ sort: z.record(kindName, z.union([listSortShape, z.null()])).optional(),
176
+ // How a kind's list opens grouped: `{ "request": { "by": "status", "order": [...], "closed": ["done"] } }` or a field; null opens it ungrouped.
177
+ group: z.record(kindName, z.union([listGroupShape, z.null()])).optional(),
146
178
  // The scene's word as a chat or a tool written before 0.1.17 sends it (FR-132's key, RESPELLED as `scene`).
147
179
  overview: z.union([z.string().min(1).max(40), z.null()]).optional(),
148
180
  })
@@ -159,6 +191,10 @@ const SHAPES = {
159
191
  .strict(),
160
192
  // Who the people are, and who may do and see what (FR-170): a grant and a sight as the document holds one.
161
193
  "set-people": z.object({ op: z.literal("set-people"), kind: kindName, people: z.boolean() }).strict(),
194
+ // Whether a kind's records are archived and merged, or only kept and removed (FR-173).
195
+ "set-archives": z.object({ op: z.literal("set-archives"), kind: kindName, archives: z.boolean() }).strict(),
196
+ // What the app's own actor may do on its own to a kind, or to one relation of it (`@graview/core/tidying`).
197
+ "set-tidying": z.object({ op: z.literal("set-tidying"), kind: kindName, relation: z.optional(z.string()), tidying: z.enum(["never", "no-links", "allowed"]) }).strict(),
162
198
  "add-grant": z.object({ op: z.literal("add-grant") }).passthrough(),
163
199
  "remove-grant": z.object({ op: z.literal("remove-grant") }).passthrough(),
164
200
  "add-sight": z.object({ op: z.literal("add-sight") }).passthrough(),
@@ -271,9 +307,10 @@ function mapNames(doc, e, ctx, rename) {
271
307
  const first = x.args[0];
272
308
  const literal = first?.t === "lit" && typeof first.value === "string" ? first.value : undefined;
273
309
  let args;
274
- if ((x.fn === "out" || x.fn === "in" || x.fn === "all") && literal !== undefined && x.args.length === 1) {
310
+ if ((x.fn === "out" || x.fn === "in" || x.fn === "all") && literal !== undefined && (x.args.length === 1 || (x.fn === "all" && x.args.length === 2))) {
275
311
  const name = rename({ role: x.fn === "all" ? "kind" : "edge", kinds: NONE, name: literal });
276
- args = name === literal ? [...x.args] : [{ ...first, value: name }];
312
+ // all('task', 'all') keeps what it asked of the archived (FR-173).
313
+ args = name === literal ? [...x.args] : [{ ...first, value: name }, ...x.args.slice(1)];
277
314
  }
278
315
  else if ((x.fn === "out" || x.fn === "in") && x.args.length === 2 && x.args[1].t === "lit" && typeof x.args[1].value === "string") {
279
316
  // out(S, 'edge'): the set is read where the walk stands, and its relation renamed like any walk's (FR-101).
@@ -481,7 +518,7 @@ class Editor {
481
518
  const emptyPart = ["typography", "shape", "accents"].find((key) => isObject(e[key]) && Object.keys(e[key]).length === 0);
482
519
  if (emptyPart)
483
520
  return this.fail(i, emptyPart, `${emptyPart} names no part to set; name one, or give null to clear all of it`);
484
- const judged = brandFindings({ ...(typeof e.logo === "string" || isObject(e.logo) ? { logo: e.logo } : {}), ...(typeof e.favicon === "string" ? { favicon: e.favicon } : {}), ...(isObject(e.typography) ? { typography: Object.fromEntries(Object.entries(e.typography).filter(([, v]) => typeof v === "string")) } : {}) }, { at, ...(this.options.fonts ? { fonts: this.options.fonts } : {}) });
521
+ const judged = brandFindings({ ...(typeof e.logo === "string" || isObject(e.logo) ? { logo: e.logo } : {}), ...(typeof e.favicon === "string" || isObject(e.favicon) ? { favicon: e.favicon } : {}), ...(isObject(e.typography) ? { typography: Object.fromEntries(Object.entries(e.typography).filter(([, v]) => typeof v === "string")) } : {}) }, { at, ...(this.options.fonts ? { fonts: this.options.fonts } : {}) });
485
522
  if (judged.length > 0)
486
523
  return void this.findings.push(...judged);
487
524
  if (e.accent === null) {
@@ -507,13 +544,17 @@ class Editor {
507
544
  brand["currency"] = e.currency;
508
545
  this.said.push(`Money is said in ${e.currency}.`);
509
546
  }
510
- if (e.locale === null)
547
+ if (e.locale === null) {
548
+ if (brand["locale"] !== undefined)
549
+ this.said.push(localeSentence(undefined));
511
550
  delete brand["locale"];
551
+ }
512
552
  else if (e.locale !== undefined) {
513
553
  if (!/^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*$/.test(e.locale))
514
554
  return this.fail(i, "locale", 'a locale is a language tag, like "en-US" or "de-DE"');
515
555
  brand["locale"] = e.locale;
516
- this.said.push(`Money is written for ${e.locale}.`);
556
+ // Its days, times and numbers as well as its money (FR-178).
557
+ this.said.push(localeSentence(e.locale));
517
558
  }
518
559
  if (e.name === null) {
519
560
  delete brand["name"];
@@ -535,6 +576,8 @@ class Editor {
535
576
  const alt = (mark) => (isObject(mark) && typeof mark["alt"] === "string" ? mark["alt"] : undefined);
536
577
  if (e[key] === null)
537
578
  this.said.push(`The app has no ${what}.`);
579
+ else if (key === "favicon" && emojiOf(e[key]) !== undefined)
580
+ this.said.push(emojiIconSentence(emojiOf(e[key]), brand["logo"] !== undefined));
538
581
  else if (was === undefined)
539
582
  this.said.push(`The app gets a ${what}.`);
540
583
  else if (canonicalize(was) === canonicalize(e[key]))
@@ -651,6 +694,8 @@ class Editor {
651
694
  return this.setOptions(i, e);
652
695
  case "set-range":
653
696
  return this.setRange(i, e);
697
+ case "set-format":
698
+ return this.setFormat(i, e);
654
699
  case "set-required": {
655
700
  const f = this.field(i, e.kind, e.field);
656
701
  if (!f)
@@ -681,6 +726,20 @@ class Editor {
681
726
  }
682
727
  return;
683
728
  }
729
+ case "set-repeats": {
730
+ // A date that repeats keeps how it does beside it, as `<field>Repeat` (`repeat.ts`).
731
+ const f = this.field(i, e.kind, e.field);
732
+ if (!f)
733
+ return;
734
+ if (e.repeats && f.type !== "date" && f.type !== "datetime")
735
+ return this.fail(i, "repeats", `${e.kind}'s ${e.field} is ${f.type === "enum" ? "a choice" : `a ${f.type}`}, and only a date or a date and time can repeat`);
736
+ if (e.repeats)
737
+ f.repeats = true;
738
+ else
739
+ delete f.repeats;
740
+ this.said.push(e.repeats ? `${e.kind}'s ${e.field} may repeat: weekly, monthly, on chosen days, until a day.` : `${e.kind}'s ${e.field} no longer repeats.`);
741
+ return;
742
+ }
684
743
  case "remove-field":
685
744
  return this.removeField(i, e.kind, e.field);
686
745
  case "add-relation":
@@ -792,6 +851,8 @@ class Editor {
792
851
  return this.addLens(i, e);
793
852
  case "remove-lens":
794
853
  return this.removeLens(i, e);
854
+ case "set-lens-hidden":
855
+ return this.setLensHidden(i, e);
795
856
  case "set-home":
796
857
  return this.setHome(i, e.blocks);
797
858
  case "arrange-pages":
@@ -800,6 +861,10 @@ class Editor {
800
861
  return this.setComputed(i, e);
801
862
  case "set-people":
802
863
  return this.setPeople(i, e);
864
+ case "set-archives":
865
+ return this.setArchives(i, e);
866
+ case "set-tidying":
867
+ return this.setTidying(i, e);
803
868
  case "add-grant":
804
869
  case "remove-grant":
805
870
  case "add-sight":
@@ -930,7 +995,8 @@ class Editor {
930
995
  return;
931
996
  was = lenses[at];
932
997
  }
933
- const lens = { name, title: e.title, ...(e.on !== undefined ? { on: e.on } : {}), ...(e.bindings !== undefined ? { bindings: e.bindings } : {}), ...(e.options !== undefined ? { options: e.options } : {}) };
998
+ // A lens drawn anew in another's place stays off the lists if that one was.
999
+ const lens = { name, title: e.title, ...(e.on !== undefined ? { on: e.on } : {}), ...(e.bindings !== undefined ? { bindings: e.bindings } : {}), ...(e.options !== undefined ? { options: e.options } : {}), ...(was?.["hidden"] === true ? { hidden: true } : {}), ...(e.create === false ? { create: false } : {}) };
934
1000
  // A title is an address: one lens a title on a kind.
935
1001
  const clash = lenses.findIndex((other, index) => index !== at && isObject(other) && typeof other["title"] === "string" && placeSlug(other["title"]) === placeSlug(e.title) && (e.on === undefined || other["on"] === undefined || other["on"] === e.on));
936
1002
  if (clash >= 0)
@@ -952,8 +1018,9 @@ class Editor {
952
1018
  return;
953
1019
  const over = lens.on ?? kindsBound(lens)[0];
954
1020
  const where = over ? `, over ${pluralWords(this.doc, over)}` : "";
1021
+ const formless = lens.create === false ? "; its page offers no form to add one" : "";
955
1022
  if (!was) {
956
- this.said.push(`A lens "${e.title}" is added${where}.`);
1023
+ this.said.push(`A lens "${e.title}" is added${where}${formless}.`);
957
1024
  return;
958
1025
  }
959
1026
  const retitled = was["title"] !== e.title;
@@ -994,6 +1061,31 @@ class Editor {
994
1061
  }
995
1062
  return true;
996
1063
  }
1064
+ /**
1065
+ * A LENS KEPT OFF THE LISTS, or put back on them: still a place at its
1066
+ * address, reached by a link or `navigate`, but not offered by the bar,
1067
+ * the page list or the home's gallery. A lens a custom home links to.
1068
+ */
1069
+ setLensHidden(i, e) {
1070
+ const index = this.lensIndex(i, e.title, e.on);
1071
+ if (index < 0)
1072
+ return;
1073
+ const lens = this.doc.lenses[index];
1074
+ const title = String(lens["title"]);
1075
+ const primary = Array.isArray(this.doc.pages?.primary) ? this.doc.pages.primary : [];
1076
+ if (e.hidden && primary.some((word) => namesLens(word, title))) {
1077
+ return this.fail(i, "hidden", `pages.primary stands "${title}" on the bar, so it cannot be kept off the lists`, 'take it out of "primary" with arrange-pages first');
1078
+ }
1079
+ const was = lens["hidden"] === true;
1080
+ if (e.hidden)
1081
+ lens["hidden"] = true;
1082
+ else
1083
+ delete lens["hidden"];
1084
+ if (was === e.hidden)
1085
+ this.said.push(e.hidden ? `The lens "${title}" was already kept off the lists.` : `The lens "${title}" was already listed.`);
1086
+ else
1087
+ this.said.push(e.hidden ? `The lens "${title}" is kept off the bar and the page list; a link or navigate still reaches it.` : `The lens "${title}" is listed on the bar and the page list again.`);
1088
+ }
997
1089
  removeLens(i, e) {
998
1090
  const index = this.lensIndex(i, e.title, e.on);
999
1091
  if (index < 0)
@@ -1005,8 +1097,29 @@ class Editor {
1005
1097
  // `overview` is the scene's word as 0.1.15 and 0.1.16 took it (FR-134): read as `scene`, which wins when both are said.
1006
1098
  const { overview, ...rest } = given;
1007
1099
  const e = rest.scene === undefined && overview !== undefined ? { ...rest, scene: overview } : rest;
1008
- if (e.order === undefined && e.hide === undefined && e.first === undefined && e.scene === undefined && e.pages === undefined && e.primary === undefined)
1009
- return this.fail(i, "", 'arrange-pages says at least one of "order", "hide", "first", "primary", "scene" or "pages"');
1100
+ if (e.order === undefined && e.hide === undefined && e.first === undefined && e.scene === undefined && e.pages === undefined && e.primary === undefined && e.filters === undefined && e.sort === undefined && e.group === undefined)
1101
+ return this.fail(i, "", 'arrange-pages says at least one of "order", "hide", "first", "primary", "scene", "pages", "filters", "sort" or "group"');
1102
+ // A list's order and grouping are judged as the checker judges them, each refusal its sentence.
1103
+ for (const part of ["sort", "group"]) {
1104
+ for (const [kind, spec] of Object.entries((e[part] ?? {}))) {
1105
+ if (!this.doc.kinds[kind])
1106
+ return this.fail(i, `${part}.${kind}`, `"${kind}" is not a kind this app has; it has ${Object.keys(this.doc.kinds).join(", ")}`);
1107
+ if (spec === null)
1108
+ continue;
1109
+ const [finding] = kindListFindings(kind, { [part]: spec }, documentListFields(this.doc.kinds[kind]), `${part}.${kind}`);
1110
+ if (finding)
1111
+ return this.fail(i, finding.path.replace(new RegExp(`^${part}\\.${kind}\\.${part}`), `${part}.${kind}`), finding.message.replace(/\.$/, ""), finding.fix.replace(/\.$/, ""));
1112
+ }
1113
+ }
1114
+ for (const [kind, keys] of Object.entries((e.filters ?? {}))) {
1115
+ if (!this.doc.kinds[kind])
1116
+ return this.fail(i, `filters.${kind}`, `"${kind}" is not a kind this app has; it has ${Object.keys(this.doc.kinds).join(", ")}`);
1117
+ for (const [n, key] of (keys ?? []).entries()) {
1118
+ const offered = this.filterKeys(kind);
1119
+ if (!offered.includes(key))
1120
+ return this.fail(i, `filters.${kind}.${n}`, `${kind} cannot be filtered by "${key}"`, `name one of ${offered.join(", ")}`);
1121
+ }
1122
+ }
1010
1123
  for (const [n, word] of (e.primary ?? []).entries()) {
1011
1124
  if (typeof word !== "string" || !this.opens(word) || word.trim().toLowerCase() === "home") {
1012
1125
  const titles = (this.doc.lenses ?? []).flatMap((lens) => (isObject(lens) && typeof lens["title"] === "string" ? [`"${lens["title"]}"`] : []));
@@ -1085,10 +1198,156 @@ class Editor {
1085
1198
  said.push(`the switch calls the ${face} "${pages[face]}"`);
1086
1199
  }
1087
1200
  }
1201
+ // Each kind's list keeps what this edit does not say: its filters, its order, its grouping.
1202
+ const listOfKind = (kind, part, value) => {
1203
+ const lists = (pages.lists ??= {});
1204
+ const list = (lists[kind] ??= {});
1205
+ if (value === null)
1206
+ delete list[part];
1207
+ else
1208
+ list[part] = value;
1209
+ if (Object.keys(list).length === 0)
1210
+ delete lists[kind];
1211
+ if (Object.keys(lists).length === 0)
1212
+ delete pages.lists;
1213
+ };
1214
+ for (const [kind, keys] of Object.entries((e.filters ?? {}))) {
1215
+ if (keys === null || keys.length === 0) {
1216
+ listOfKind(kind, "filters", null);
1217
+ said.push(`the list of ${pluralWords(this.doc, kind)} offers its own filters again`);
1218
+ }
1219
+ else {
1220
+ listOfKind(kind, "filters", [...keys]);
1221
+ said.push(`the list of ${pluralWords(this.doc, kind)} filters by ${listOf(keys.map((key) => `"${key}"`))}`);
1222
+ }
1223
+ }
1224
+ for (const part of ["sort", "group"]) {
1225
+ for (const [kind, spec] of Object.entries((e[part] ?? {}))) {
1226
+ listOfKind(kind, part, spec === null ? null : clone(spec));
1227
+ const plural = pluralWords(this.doc, kind);
1228
+ if (spec === null)
1229
+ said.push(part === "sort" ? `the list of ${plural} opens in its own order again` : `the list of ${plural} opens ungrouped again`);
1230
+ else
1231
+ said.push(`the list of ${plural} opens ${kindListWords({ [part]: spec }, this.listKeyType(kind))[part]}`);
1232
+ }
1233
+ }
1088
1234
  if (Object.keys(pages).length === 0)
1089
1235
  delete this.doc.pages;
1090
1236
  this.said.push(`${capitalize(listOf(said))}.`);
1091
1237
  }
1238
+ /**
1239
+ * A KIND'S LIST FOLLOWS ITS FIELDS. Its order and grouping name a field
1240
+ * renamed by its new name; one gone (or a computed field no longer worked
1241
+ * out) lets go of the part that named it — a tiebreak, the order, the
1242
+ * grouping — and says so. A list left saying nothing is unsaid.
1243
+ */
1244
+ listsFollow(kind, from, to) {
1245
+ const list = this.doc.pages?.lists?.[kind];
1246
+ if (!list)
1247
+ return [];
1248
+ const out = [];
1249
+ const sort = listSort(list.sort);
1250
+ if (sort && (sort.by === from || sort.then?.by === from)) {
1251
+ if (to !== undefined) {
1252
+ if (typeof list.sort === "string")
1253
+ list.sort = to;
1254
+ else {
1255
+ if (list.sort.by === from)
1256
+ list.sort.by = to;
1257
+ if (list.sort.then === from)
1258
+ list.sort.then = to;
1259
+ else if (isObject(list.sort.then) && list.sort.then["by"] === from)
1260
+ list.sort.then.by = to;
1261
+ }
1262
+ }
1263
+ else if (sort.by === from)
1264
+ delete list.sort;
1265
+ else
1266
+ delete list.sort.then;
1267
+ out.push(`the ${kind} list's order`);
1268
+ }
1269
+ if (listGroup(list.group)?.by === from) {
1270
+ if (to === undefined)
1271
+ delete list.group;
1272
+ else if (typeof list.group === "string")
1273
+ list.group = to;
1274
+ else
1275
+ list.group.by = to;
1276
+ out.push(`the ${kind} list's grouping`);
1277
+ }
1278
+ this.listsTidied(kind);
1279
+ return out;
1280
+ }
1281
+ /** A field retyped or a choice dropped: the list's order and grouping keep what still holds, and let go of what does not. */
1282
+ listsHold(kind, removedOptions = []) {
1283
+ const list = this.doc.pages?.lists?.[kind];
1284
+ if (!list)
1285
+ return [];
1286
+ const out = [];
1287
+ if (isObject(list.group) && removedOptions.length > 0) {
1288
+ for (const part of ["order", "closed"]) {
1289
+ if (!Array.isArray(list.group[part]))
1290
+ continue;
1291
+ const kept = list.group[part].filter((value) => !removedOptions.includes(value));
1292
+ if (kept.length === list.group[part].length)
1293
+ continue;
1294
+ if (kept.length > 0)
1295
+ list.group[part] = kept;
1296
+ else
1297
+ delete list.group[part];
1298
+ if (!out.includes(`the ${kind} list's grouping`))
1299
+ out.push(`the ${kind} list's grouping`);
1300
+ }
1301
+ }
1302
+ for (const finding of kindListFindings(kind, list, documentListFields(this.doc.kinds[kind]))) {
1303
+ const part = finding.path.slice(`pages.lists.${kind}.`.length).startsWith("sort") ? "sort" : "group";
1304
+ if (list[part] === undefined)
1305
+ continue;
1306
+ delete list[part];
1307
+ out.push(`the ${kind} list's ${part === "sort" ? "order" : "grouping"}`);
1308
+ }
1309
+ this.listsTidied(kind);
1310
+ return out;
1311
+ }
1312
+ listsTidied(kind) {
1313
+ const lists = this.doc.pages?.lists;
1314
+ if (!lists)
1315
+ return;
1316
+ if (lists[kind] && Object.keys(lists[kind]).length === 0)
1317
+ delete lists[kind];
1318
+ if (Object.keys(lists).length === 0)
1319
+ delete this.doc.pages.lists;
1320
+ if (Object.keys(this.doc.pages).length === 0)
1321
+ delete this.doc.pages;
1322
+ }
1323
+ /** What a key of a kind's list reads as, for the words its order is said in: a computed field is a number. */
1324
+ listKeyType(kind) {
1325
+ const spec = this.doc.kinds[kind];
1326
+ return (key) => (spec?.computed?.[key] !== undefined ? "number" : sortTypeOfDocumentField(spec?.fields?.[key]?.type));
1327
+ }
1328
+ /** What a kind's list may be filtered by: its fields, its relations either way, `is`, and a choice at a relation's single far kind. */
1329
+ filterKeys(kind) {
1330
+ const kinds = this.doc.kinds;
1331
+ const keys = new Set(["is", ...Object.keys(kinds[kind]?.fields ?? {})]);
1332
+ const edges = new Map();
1333
+ for (const [edge, spec] of Object.entries((kinds[kind]?.edges ?? {})))
1334
+ edges.set(edge, spec.to === "*" ? [] : [spec.to].flat());
1335
+ for (const [other, spec] of Object.entries(kinds)) {
1336
+ for (const [edge, declared] of Object.entries((spec.edges ?? {}))) {
1337
+ if (other !== kind && !edges.has(edge) && (declared.to === "*" || [declared.to].flat().includes(kind)))
1338
+ edges.set(edge, [other]);
1339
+ }
1340
+ }
1341
+ for (const [edge, far] of edges) {
1342
+ keys.add(edge);
1343
+ if (far.length !== 1 || far[0] === kind)
1344
+ continue;
1345
+ for (const [field, spec] of Object.entries((kinds[far[0]]?.fields ?? {})))
1346
+ if (spec.type === "enum")
1347
+ keys.add(`${edge}.${field}`);
1348
+ }
1349
+ return [...keys];
1350
+ }
1092
1351
  /** Whether `first` names something the app can open on: home, a kind or its plural, a titled lens. */
1093
1352
  opens(first) {
1094
1353
  const word = first.trim();
@@ -1179,6 +1438,73 @@ class Editor {
1179
1438
  delete spec.people;
1180
1439
  this.said.push(peopleSentence(this.doc.kinds, e.kind, e.people, already));
1181
1440
  }
1441
+ /** A kind's records kept or removed, never archived (FR-173) — or archived and merged again. */
1442
+ setArchives(i, e) {
1443
+ const spec = this.kind(i, e.kind);
1444
+ if (!spec)
1445
+ return;
1446
+ const already = (spec.archives !== false) === e.archives;
1447
+ if (!e.archives && !already) {
1448
+ // A grant that names one of the three acts would name an act the app no longer has.
1449
+ const gone = new Set(["archive", "unarchive", "merge"].map((verb) => `${verb}-${e.kind}`).filter((act) => !this.doc.acts?.[act]));
1450
+ const grant = (this.doc.policy?.grants ?? []).find((g) => Array.isArray(g.mutations) && g.mutations.some((m) => gone.has(m)));
1451
+ if (grant) {
1452
+ const named = grant.mutations.filter((m) => gone.has(m));
1453
+ return this.failAs("grant-unknown-mutation", i, "archives", `a grant names ${listOf(named.map((m) => `"${m}"`))}, which ${pluralOf(this.doc.kinds, e.kind)} would no longer have`, `{"op": "remove-grant", "roles": ${JSON.stringify(grant.roles)}, "mutations": ${JSON.stringify(grant.mutations)}} first, in the same change`);
1454
+ }
1455
+ spec.archives = false;
1456
+ }
1457
+ else if (e.archives)
1458
+ delete spec.archives;
1459
+ if (!already)
1460
+ this.toolsMoved.add(`archive-${e.kind}, unarchive-${e.kind} and merge-${e.kind} ${e.archives ? "are offered" : "are gone"}`);
1461
+ this.said.push(archivesSentence(this.doc.kinds, e.kind, e.archives, already));
1462
+ }
1463
+ /**
1464
+ * WHAT THE APP'S OWN ACTOR MAY DO ON ITS OWN (`@graview/core/tidying`):
1465
+ * a kind never tidied, or never linked automatically, or tidied again; a
1466
+ * relation never made or broken automatically, or tidied again. A kind
1467
+ * never tidied is given no leave-alone-<kind> or allow-tidying-<kind>,
1468
+ * which a grant may not then name.
1469
+ */
1470
+ setTidying(i, e) {
1471
+ const spec = this.kind(i, e.kind);
1472
+ if (!spec)
1473
+ return;
1474
+ const tidying = e.tidying;
1475
+ if (e.relation !== undefined) {
1476
+ const relation = spec.edges?.[e.relation];
1477
+ if (!relation)
1478
+ return this.failAs("edit", i, "relation", `${e.kind} has no relation "${e.relation}"; it has ${Object.keys(spec.edges ?? {}).join(", ") || "none"}`);
1479
+ if (tidying === "no-links")
1480
+ return this.failAs("edit", i, "tidying", `a relation is tidied or never ("never"); "no-links" is said of a kind`, `{"op": "set-tidying", "kind": "${e.kind}", "relation": "${e.relation}", "tidying": "never"}`);
1481
+ const already = (relation.tidying === "never") === (tidying === "never");
1482
+ if (tidying === "never")
1483
+ relation.tidying = "never";
1484
+ else
1485
+ delete relation.tidying;
1486
+ this.said.push(tidyingSentence(this.doc.kinds, e.kind, e.relation, tidying, already));
1487
+ return;
1488
+ }
1489
+ const was = spec.tidying ?? "allowed";
1490
+ const already = was === tidying;
1491
+ if (tidying === "never" && !already) {
1492
+ // A grant that names leave-alone-<kind> or allow-tidying-<kind> would name an act the app no longer has.
1493
+ const gone = new Set(["leave-alone", "allow-tidying"].map((verb) => `${verb}-${e.kind}`).filter((act) => !this.doc.acts?.[act]));
1494
+ const grant = (this.doc.policy?.grants ?? []).find((g) => Array.isArray(g.mutations) && g.mutations.some((m) => gone.has(m)));
1495
+ if (grant) {
1496
+ const named = grant.mutations.filter((m) => gone.has(m));
1497
+ return this.failAs("grant-unknown-mutation", i, "tidying", `a grant names ${listOf(named.map((m) => `"${m}"`))}, which ${pluralOf(this.doc.kinds, e.kind)} would no longer have`, `{"op": "remove-grant", "roles": ${JSON.stringify(grant.roles)}, "mutations": ${JSON.stringify(grant.mutations)}} first, in the same change`);
1498
+ }
1499
+ }
1500
+ if (tidying === "allowed")
1501
+ delete spec.tidying;
1502
+ else
1503
+ spec.tidying = tidying;
1504
+ if (!already && (was === "never" || tidying === "never"))
1505
+ this.toolsMoved.add(`leave-alone-${e.kind} and allow-tidying-${e.kind} ${tidying === "never" ? "are gone" : "are offered"}`);
1506
+ this.said.push(tidyingSentence(this.doc.kinds, e.kind, undefined, tidying, already));
1507
+ }
1182
1508
  /** A grant or a sight as the document holds one, or undefined having said why not. */
1183
1509
  policyPart(i, e, sight) {
1184
1510
  const { op: _op, ...rest } = e;
@@ -1202,12 +1528,21 @@ class Editor {
1202
1528
  if (!this.doc.kinds[kind])
1203
1529
  return this.failAs(sight ? "sight-kind" : "edit", i, `kinds.${n}`, `"${kind}" is not a kind this app has; it has ${Object.keys(this.doc.kinds).join(", ")}`);
1204
1530
  }
1531
+ // A field a sight shows or hides is one of the kinds it shows (Roadmap f-field-sight).
1532
+ for (const key of sight ? ["fields", "hide"] : []) {
1533
+ for (const [n, field] of (part[key] ?? []).entries()) {
1534
+ const kinds = part.kinds;
1535
+ if (kinds.some((kind) => this.doc.kinds[kind]?.fields[field]))
1536
+ continue;
1537
+ return this.failAs("sight-field", i, `${key}.${n}`, `"${field}" is not a field of ${kinds.join(" or ")}`, `one of ${[...new Set(kinds.flatMap((kind) => Object.keys(this.doc.kinds[kind]?.fields ?? {})))].join(", ")}`);
1538
+ }
1539
+ }
1205
1540
  if (!sight && part.mutations !== "*") {
1206
1541
  for (const [n, act] of part.mutations.entries()) {
1207
- const derived = /^(?:edit|remove)-(.+)$/.exec(act);
1208
- if (this.doc.acts?.[act] || (derived && this.doc.kinds[derived[1]]))
1542
+ const derived = derivedActOf(act);
1543
+ if (this.doc.acts?.[act] || (derived && this.doc.kinds[derived.kind] && (this.doc.kinds[derived.kind].archives !== false || givenWhenNeverArchived(derived.act)) && (this.doc.kinds[derived.kind].tidying !== "never" || givenWhenNeverTidied(derived.act))))
1209
1544
  continue;
1210
- return this.failAs("grant-act", i, `mutations.${n}`, `"${act}" is not an act this app has`, `one of ${[...Object.keys(this.doc.acts ?? {}), ...Object.keys(this.doc.kinds).flatMap((kind) => [`edit-${kind}`, `remove-${kind}`])].join(", ")}`);
1545
+ return this.failAs("grant-act", i, `mutations.${n}`, `"${act}" is not an act this app has`, `one of ${[...Object.keys(this.doc.acts ?? {}), ...Object.keys(this.doc.kinds).flatMap(derivedActsOf)].join(", ")}`);
1211
1546
  }
1212
1547
  }
1213
1548
  const said = [];
@@ -1306,8 +1641,8 @@ class Editor {
1306
1641
  const to = e.to;
1307
1642
  const touched = this.rewriteAll({ t: "kind", from, to });
1308
1643
  // The acts the framework derives for every kind are named for it, so they move with it.
1309
- this.toolsMoved.add(`edit-${from} is now edit-${to}`);
1310
- this.toolsMoved.add(`remove-${from} is now remove-${to}`);
1644
+ for (const act of DERIVED_ACTS)
1645
+ this.toolsMoved.add(`${act}-${from} is now ${act}-${to}`);
1311
1646
  // The kind itself, in order, continuing its records.
1312
1647
  const kinds = {};
1313
1648
  for (const [k, v] of Object.entries(this.doc.kinds))
@@ -1338,6 +1673,13 @@ class Editor {
1338
1673
  spec.plural = e.plural;
1339
1674
  else if (spec.plural && (spec.plural === `${words(from)}s` || spec.plural === `${from}s`))
1340
1675
  spec.plural = `${words(to)}s`;
1676
+ // Its list's filters, order and grouping follow it.
1677
+ const lists = this.doc.pages?.lists;
1678
+ if (lists?.[from] !== undefined && lists[to] === undefined) {
1679
+ lists[to] = lists[from];
1680
+ delete lists[from];
1681
+ touched.push(`its list`);
1682
+ }
1341
1683
  // Where the app opens, when it named the kind by its plural, follows the plural (FR-80).
1342
1684
  const pluralNow = spec.plural ?? `${words(to)}s`;
1343
1685
  if (typeof this.doc.pages?.first === "string" && placeSlug(this.doc.pages.first) === placeSlug(pluralWas) && placeSlug(pluralWas) !== placeSlug(pluralNow)) {
@@ -1424,7 +1766,7 @@ class Editor {
1424
1766
  * whose last act is removed — kept, it read as a grant on every kind.
1425
1767
  */
1426
1768
  if (this.doc.policy) {
1427
- const derived = [`edit-${kind}`, `remove-${kind}`];
1769
+ const derived = derivedActsOf(kind);
1428
1770
  this.doc.policy.grants = this.doc.policy.grants.flatMap((g) => {
1429
1771
  const kinds = Array.isArray(g.kinds) ? g.kinds.filter((k) => k !== kind) : g.kinds;
1430
1772
  const mutations = Array.isArray(g.mutations) ? g.mutations.filter((m) => !derived.includes(m) || this.doc.acts?.[m]) : g.mutations;
@@ -1491,6 +1833,8 @@ class Editor {
1491
1833
  delete f.renamedFrom;
1492
1834
  if (f.type === "enum" && f.default !== undefined && !f.options.includes(f.default))
1493
1835
  return this.fail(i, "default", `"${String(f.default)}" is not one of the options`);
1836
+ if (f.format && !formatFits(f.format, f.type))
1837
+ return this.fail(i, "format", refusedFormat(f.format, f.type));
1494
1838
  spec.fields[field] = f;
1495
1839
  this.fieldOrigin.set(`${kind}.${field}`, undefined);
1496
1840
  let filled = "";
@@ -1510,7 +1854,9 @@ class Editor {
1510
1854
  filled = `, set to ${JSON.stringify(fill)} on the records already there`;
1511
1855
  }
1512
1856
  }
1513
- this.said.push(`${kind} gains a field, ${field} (${f.type}${f.required ? ", required" : ""})${filled}.`);
1857
+ // What it is said as, in words: "(number, money in USD — 10000 reads $10,000)".
1858
+ const said = formatWords(f, this.doc.brand);
1859
+ this.said.push(`${kind} gains a field, ${field} (${f.type}${said ? `, ${said}` : ""}${f.required ? ", required" : ""})${filled}.`);
1514
1860
  }
1515
1861
  renameField(i, kind, field, to) {
1516
1862
  const f = this.field(i, kind, field);
@@ -1554,6 +1900,7 @@ class Editor {
1554
1900
  spec.page = renamedOnPage(spec.page, field, to);
1555
1901
  touched.push(`${kind}'s page`);
1556
1902
  }
1903
+ touched.push(...this.listsFollow(kind, field, to));
1557
1904
  for (const x of this.fills) {
1558
1905
  if (x.kind === kind && x.field === field)
1559
1906
  x.field = to;
@@ -1572,6 +1919,9 @@ class Editor {
1572
1919
  return;
1573
1920
  if (e.type === "enum" && !e.options && !f.options)
1574
1921
  return this.fail(i, "options", `to make ${e.field} a choice, list its "options"`);
1922
+ // A format goes where it says something (FR-180): money, a percent and a duration on a number, Markdown on a text field.
1923
+ if (e.format && !formatFits(e.format, e.type))
1924
+ return this.fail(i, "format", refusedFormat(e.format, e.type));
1575
1925
  const was = f.type;
1576
1926
  f.type = e.type;
1577
1927
  if (e.type === "enum")
@@ -1584,25 +1934,73 @@ class Editor {
1584
1934
  delete f.of;
1585
1935
  if (e.format)
1586
1936
  f.format = e.format;
1587
- else if (e.type !== "number" && e.type !== "integer")
1937
+ else if (e.type === "text" || !formatFits(f.format ?? "", e.type))
1588
1938
  delete f.format;
1589
1939
  // A range is a number's (FR-114): a field that is no longer one lets it go.
1590
- if (e.type !== "number" && e.type !== "integer")
1940
+ if (e.type !== "number" && e.type !== "integer" && e.type !== "duration")
1591
1941
  for (const key of ["min", "max", "step"])
1592
1942
  delete f[key];
1943
+ // Only a date repeats: a field that is no longer one lets its repeat go.
1944
+ if (e.type !== "date" && e.type !== "datetime")
1945
+ delete f.repeats;
1593
1946
  if (f.default !== undefined && coerce(f.default, was, f) === undefined)
1594
1947
  delete f.default;
1595
1948
  else if (f.default !== undefined)
1596
1949
  f.default = coerce(f.default, was, f);
1597
- this.said.push(`${e.kind}'s ${e.field} changes from ${was} to ${e.type}; values that convert are kept.`);
1950
+ const said = f.format && f.format !== "markdown" ? formatWords(f, this.doc.brand) : undefined;
1951
+ // A list grouped by a choice that is no longer one opens ungrouped, and says so.
1952
+ const held = this.listsHold(e.kind);
1953
+ if (held.length > 0)
1954
+ this.said.push(`${capitalize(listOf(held))} ${held.length === 1 ? "goes" : "go"} back to the list's own, since ${e.field} is no longer ${was === "enum" ? "a choice" : `a ${was}`}.`);
1955
+ if (was === e.type && e.type === "text")
1956
+ this.said.push(`${e.kind}'s ${e.field} ${e.format === "markdown" ? "is now written in Markdown, drawn as prose on the record's page" : "is drawn as written, not as Markdown"}; its values are kept.`);
1957
+ else
1958
+ this.said.push(`${e.kind}'s ${e.field} changes from ${was} to ${e.type}${said ? `, said as ${said}` : ""}; values that convert are kept.`);
1959
+ }
1960
+ /**
1961
+ * HOW A FIELD IS SAID, and nothing else about it: a number's `format`
1962
+ * (money, a percent, a duration) and `unit` (a currency like "EUR" for
1963
+ * money, a measure like "kg"), or a text field's `format`, `markdown`
1964
+ * (FR-180) — each set by a value, cleared by `null`, kept when left out.
1965
+ * The values stay as they are; every face says them anew.
1966
+ */
1967
+ setFormat(i, e) {
1968
+ const f = this.field(i, e.kind, e.field);
1969
+ if (!f)
1970
+ return;
1971
+ if (e.format === undefined && e.unit === undefined)
1972
+ return this.fail(i, "format", 'say a "format" ("money", "percent" or "duration" for a number, "markdown" for a text field, or null for neither), a "unit" ("EUR", "kg", or null), or both');
1973
+ if (f.type === "text") {
1974
+ if (e.unit !== undefined && e.unit !== null)
1975
+ return this.fail(i, "unit", refusedFormat("a unit", f.type));
1976
+ if (e.format && e.format !== "markdown")
1977
+ return this.fail(i, "format", refusedFormat(e.format, f.type));
1978
+ if (e.format === "markdown")
1979
+ f.format = "markdown";
1980
+ else if (e.format === null)
1981
+ delete f.format;
1982
+ this.said.push(`${e.kind}'s ${e.field} ${f.format === "markdown" ? "is now written in Markdown, drawn as prose on the record's page" : "is drawn as written, not as Markdown"}; its values are kept.`);
1983
+ return;
1984
+ }
1985
+ if (!formatFits(typeof e.format === "string" ? e.format : "money", f.type))
1986
+ return this.fail(i, "field", refusedFormat(typeof e.format === "string" ? e.format : "a unit", f.type));
1987
+ const before = formatWords(f, this.doc.brand);
1988
+ for (const key of ["format", "unit"]) {
1989
+ if (e[key] === null)
1990
+ delete f[key];
1991
+ else if (e[key] !== undefined)
1992
+ f[key] = e[key];
1993
+ }
1994
+ const now = formatWords(f, this.doc.brand);
1995
+ this.said.push(`${e.kind}'s ${e.field} is said as ${now ?? "a plain number"}${before ? `, where it was ${before.replace(/ — .*/, "")}` : ""}; its values are kept.`);
1598
1996
  }
1599
1997
  /** A number's range (FR-114): a key given sets it, `null` clears it, one left out stays. */
1600
1998
  setRange(i, e) {
1601
1999
  const f = this.field(i, e.kind, e.field);
1602
2000
  if (!f)
1603
2001
  return;
1604
- if (f.type !== "number" && f.type !== "integer")
1605
- return this.fail(i, "field", `${e.field} is ${f.type === "integer" ? "an" : "a"} ${f.type}, not a number; a range belongs on a number or integer field`);
2002
+ if (f.type !== "number" && f.type !== "integer" && f.type !== "duration")
2003
+ return this.fail(i, "field", `${e.field} is ${f.type === "integer" ? "an" : "a"} ${f.type}, not a number; a range belongs on a number, integer or duration field`);
1606
2004
  const next = { ...f };
1607
2005
  for (const key of ["min", "max", "step"]) {
1608
2006
  if (e[key] === null)
@@ -1647,6 +2045,9 @@ class Editor {
1647
2045
  delete f.default;
1648
2046
  out.push("has no default now");
1649
2047
  }
2048
+ const held = this.listsHold(e.kind, remove);
2049
+ if (held.length > 0)
2050
+ out.push(`${listOf(held)} ${held.length === 1 ? "lets" : "let"} go of ${remove.length === 1 ? "it" : "them"}`);
1650
2051
  // An act that sets a dropped option cannot stand.
1651
2052
  for (const [name, act] of Object.entries(this.doc.acts ?? {})) {
1652
2053
  for (const t of setTargets(act, this.doc))
@@ -2025,7 +2426,7 @@ class Editor {
2025
2426
  rule.over = r.to;
2026
2427
  for (const rep of rule.repairs ?? []) {
2027
2428
  if (r.t === "kind")
2028
- rep.act = rep.act === `edit-${r.from}` ? `edit-${r.to}` : rep.act === `remove-${r.from}` ? `remove-${r.to}` : rep.act;
2429
+ rep.act = renamedAct(rep.act, r.from, r.to);
2029
2430
  const args = renamedArgs.get(rep.act);
2030
2431
  if (args && rep.args)
2031
2432
  for (const [a, b] of args)
@@ -2052,7 +2453,7 @@ class Editor {
2052
2453
  if (Array.isArray(g.kinds))
2053
2454
  g.kinds = g.kinds.map(swap);
2054
2455
  if (Array.isArray(g.mutations))
2055
- g.mutations = g.mutations.map((m) => (m === `edit-${r.from}` ? `edit-${r.to}` : m === `remove-${r.from}` ? `remove-${r.to}` : m));
2456
+ g.mutations = g.mutations.map((m) => renamedAct(m, r.from, r.to));
2056
2457
  }
2057
2458
  for (const s of doc.policy.sees ?? [])
2058
2459
  s.kinds = s.kinds.map(swap);
@@ -2115,6 +2516,9 @@ class Editor {
2115
2516
  dropMentions(r, worked = false) {
2116
2517
  const doc = this.doc;
2117
2518
  const gone = [];
2519
+ // A kind's list ordered or grouped by it lets that go (a stored field removed, a computed one no longer worked out).
2520
+ if (r.t === "field")
2521
+ gone.push(...this.listsFollow(r.kind, r.from, undefined));
2118
2522
  for (const [kind, spec] of Object.entries(doc.kinds)) {
2119
2523
  for (const key of ["label", "describe"]) {
2120
2524
  if (templateMentions(doc, spec[key], new Set([kind]), r)) {
@@ -2808,4 +3212,9 @@ export function renameIn(kinds, over, text, change) {
2808
3212
  return rewriteTemplate(doc, text.template, ctx, r);
2809
3213
  return undefined;
2810
3214
  }
3215
+ /** A derived act of a renamed kind, renamed with it: `archive-task` becomes `archive-chore`. Any other act as it was. */
3216
+ function renamedAct(act, from, to) {
3217
+ const derived = derivedActOf(act);
3218
+ return derived && derived.kind === from ? `${derived.act}-${to}` : act;
3219
+ }
2811
3220
  //# sourceMappingURL=edit.js.map