attachments.typ 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. // ==========================================
  2. // DOMAIN: ПРИЛОЖЕНИЯ
  3. // ==========================================
  4. #import "document.typ": fail
  5. // Тип label нужен для проверки параметра, но сам параметр с тем же именем
  6. // затеняет глобальный тип, поэтому тип фиксируется до объявления функции.
  7. #let label-type = type(<attachment-label-type-probe>)
  8. #let attachment(
  9. id,
  10. title,
  11. body,
  12. subtitle: none,
  13. number: auto,
  14. outlined: true,
  15. label: none,
  16. ) = {
  17. if type(id) != str or id.trim() == "" {
  18. fail("attachment.id", "нужна непустая строка")
  19. }
  20. if type(title) not in (str, content) {
  21. fail("attachment.title", "ожидались str или content")
  22. }
  23. if type(body) not in (content, function) {
  24. fail("attachment.body", "ожидались content или function")
  25. }
  26. if subtitle != none and type(subtitle) not in (str, content) {
  27. fail("attachment.subtitle", "ожидались none, str или content")
  28. }
  29. if label != none and type(label) != label-type {
  30. fail("attachment.label", "ожидались none или label")
  31. }
  32. (
  33. kind: "attachment",
  34. id: id,
  35. title: title,
  36. subtitle: subtitle,
  37. body: body,
  38. number: number,
  39. outlined: outlined,
  40. label: label,
  41. )
  42. }
  43. #let attachment-set(items: (), numbering: "arabic", start: 1) = {
  44. if type(items) != array {
  45. fail("attachments.items", "ожидался array")
  46. }
  47. if numbering not in ("arabic", "cyrillic", "none") {
  48. fail("attachments.numbering", "допустимы arabic, cyrillic, none")
  49. }
  50. if type(start) != int or start < 1 {
  51. fail("attachments.start", "нужно положительное целое число")
  52. }
  53. let seen = ()
  54. for item in items {
  55. if type(item) != dictionary or item.at("kind", default: none) != "attachment" {
  56. fail("attachments.items", "каждый элемент должен быть attachment")
  57. }
  58. if item.id in seen {
  59. fail("attachments.items", "повторяющийся id " + repr(item.id))
  60. }
  61. seen.push(item.id)
  62. }
  63. (
  64. kind: "attachment-set",
  65. items: items,
  66. numbering: numbering,
  67. start: start,
  68. )
  69. }
  70. #let validate-attachment-set(value) = {
  71. if type(value) == array {
  72. attachment-set(items: value)
  73. } else if type(value) != dictionary or value.at("kind", default: none) != "attachment-set" {
  74. fail("attachments", "ожидались array или attachment-set")
  75. } else {
  76. attachment-set(
  77. items: value.at("items", default: ()),
  78. numbering: value.at("numbering", default: "arabic"),
  79. start: value.at("start", default: 1),
  80. )
  81. }
  82. }