@agentshouse/mdmodel 0.1.0-c83456e1cebfb → 0.1.0-cabd61587647f

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 (295) hide show
  1. package/API.md +242 -181
  2. package/README.md +17 -18
  3. package/dist/blocks.d.ts.map +1 -1
  4. package/dist/blocks.js +33 -26
  5. package/dist/condition.d.ts +149 -0
  6. package/dist/condition.d.ts.map +1 -0
  7. package/dist/condition.js +500 -0
  8. package/dist/definition.d.ts +62 -24
  9. package/dist/definition.d.ts.map +1 -1
  10. package/dist/definition.js +703 -138
  11. package/dist/divide.d.ts.map +1 -1
  12. package/dist/divide.js +18 -8
  13. package/dist/document.d.ts +10 -2
  14. package/dist/document.d.ts.map +1 -1
  15. package/dist/document.js +370 -114
  16. package/dist/fields.d.ts +2 -0
  17. package/dist/fields.d.ts.map +1 -1
  18. package/dist/fields.js +7 -0
  19. package/dist/index.d.ts +14 -6
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +9 -4
  22. package/dist/links.d.ts +2 -0
  23. package/dist/links.d.ts.map +1 -1
  24. package/dist/links.js +23 -12
  25. package/dist/paths.d.ts +4 -0
  26. package/dist/paths.d.ts.map +1 -1
  27. package/dist/paths.js +110 -10
  28. package/dist/project.d.ts +1 -0
  29. package/dist/project.d.ts.map +1 -1
  30. package/dist/project.js +52 -30
  31. package/dist/references.d.ts +4 -0
  32. package/dist/references.d.ts.map +1 -0
  33. package/dist/references.js +25 -0
  34. package/dist/schema.d.ts +7 -6
  35. package/dist/schema.d.ts.map +1 -1
  36. package/dist/schema.js +157 -31
  37. package/dist/types.d.ts +43 -1
  38. package/dist/types.d.ts.map +1 -1
  39. package/dist/validate.d.ts +6 -1
  40. package/dist/validate.d.ts.map +1 -1
  41. package/dist/validate.js +167 -144
  42. package/dist/yaml.d.ts +8 -3
  43. package/dist/yaml.d.ts.map +1 -1
  44. package/dist/yaml.js +133 -43
  45. package/fixtures/README.md +49 -38
  46. package/fixtures/cases/absent-link-dangles/context.json +1 -0
  47. package/fixtures/cases/absent-link-dangles/expected.json +1 -0
  48. package/fixtures/cases/absent-link-dangles/library/item.md +8 -0
  49. package/fixtures/cases/absent-link-dangles/schema.yaml +6 -0
  50. package/fixtures/cases/absent-optional-field/context.json +1 -0
  51. package/fixtures/cases/absent-optional-field/expected.json +1 -0
  52. package/fixtures/cases/absent-optional-field/library/companies/acme.md +4 -0
  53. package/fixtures/cases/absent-optional-field/library/deals/lead.md +6 -0
  54. package/fixtures/cases/absent-optional-field/schema.yaml +56 -0
  55. package/fixtures/cases/absolute-link/context.json +1 -0
  56. package/fixtures/cases/{missing-binary-image → absolute-link}/expected.json +1 -1
  57. package/fixtures/cases/absolute-link/library/item.md +8 -0
  58. package/fixtures/cases/absolute-link/schema.yaml +6 -0
  59. package/fixtures/cases/attachment-reference-any-file/context.json +1 -0
  60. package/fixtures/cases/attachment-reference-any-file/expected.json +1 -0
  61. package/fixtures/cases/attachment-reference-any-file/library/companies/acme.md +4 -0
  62. package/fixtures/cases/attachment-reference-any-file/library/deals/renewal.md +15 -0
  63. package/fixtures/cases/attachment-reference-any-file/library/places/depot.md +4 -0
  64. package/fixtures/cases/attachment-reference-any-file/library/products/seats.md +4 -0
  65. package/fixtures/cases/attachment-reference-any-file/library/products/support.md +4 -0
  66. package/fixtures/cases/attachment-reference-any-file/schema.yaml +32 -0
  67. package/fixtures/cases/attachment-reference-dangles/context.json +1 -0
  68. package/fixtures/cases/attachment-reference-dangles/expected.json +1 -0
  69. package/fixtures/cases/attachment-reference-dangles/library/companies/acme.md +4 -0
  70. package/fixtures/cases/attachment-reference-dangles/library/deals/renewal.md +15 -0
  71. package/fixtures/cases/attachment-reference-dangles/library/places/depot.md +4 -0
  72. package/fixtures/cases/attachment-reference-dangles/library/products/seats.md +4 -0
  73. package/fixtures/cases/attachment-reference-dangles/library/products/support.md +4 -0
  74. package/fixtures/cases/attachment-reference-dangles/schema.yaml +32 -0
  75. package/fixtures/cases/attachment-reference-outside/context.json +1 -0
  76. package/fixtures/cases/attachment-reference-outside/expected.json +6 -0
  77. package/fixtures/cases/attachment-reference-outside/library/companies/acme.md +4 -0
  78. package/fixtures/cases/attachment-reference-outside/library/deals/renewal.md +15 -0
  79. package/fixtures/cases/attachment-reference-outside/library/places/depot.md +4 -0
  80. package/fixtures/cases/attachment-reference-outside/library/products/seats.md +4 -0
  81. package/fixtures/cases/attachment-reference-outside/library/products/support.md +4 -0
  82. package/fixtures/cases/attachment-reference-outside/schema.yaml +32 -0
  83. package/fixtures/cases/binary-any-reference/expected.json +1 -1
  84. package/fixtures/cases/binary-any-reference/schema.yaml +4 -4
  85. package/fixtures/cases/binary-document-collision/schema.yaml +1 -2
  86. package/fixtures/cases/binary-image-dangles/expected.json +1 -0
  87. package/fixtures/cases/binary-image-dangles/schema.yaml +1 -0
  88. package/fixtures/cases/binary-link-dangles/expected.json +1 -0
  89. package/fixtures/cases/binary-link-dangles/schema.yaml +1 -0
  90. package/fixtures/cases/binary-link-outside-collection/schema.yaml +1 -2
  91. package/fixtures/cases/binary-prototype-reference/expected.json +1 -1
  92. package/fixtures/cases/binary-prototype-reference/schema.yaml +4 -4
  93. package/fixtures/cases/binary-typed-reference/expected.json +1 -1
  94. package/fixtures/cases/binary-typed-reference/schema.yaml +5 -5
  95. package/fixtures/cases/boolean-field/context.json +1 -0
  96. package/fixtures/cases/boolean-field/expected.json +6 -0
  97. package/fixtures/cases/boolean-field/library/companies/acme.md +4 -0
  98. package/fixtures/cases/boolean-field/library/deals/renewal.md +31 -0
  99. package/fixtures/cases/boolean-field/schema.yaml +56 -0
  100. package/fixtures/cases/bracketed-link-definition/schema.yaml +6 -6
  101. package/fixtures/cases/closed-nested-object/context.json +1 -0
  102. package/fixtures/cases/closed-nested-object/expected.json +6 -0
  103. package/fixtures/cases/closed-nested-object/library/companies/acme.md +4 -0
  104. package/fixtures/cases/closed-nested-object/library/deals/renewal.md +32 -0
  105. package/fixtures/cases/closed-nested-object/schema.yaml +56 -0
  106. package/fixtures/cases/composed-root-reference/context.json +1 -0
  107. package/fixtures/cases/composed-root-reference/expected.json +6 -0
  108. package/fixtures/cases/composed-root-reference/library/a.md +5 -0
  109. package/fixtures/cases/composed-root-reference/schema.yaml +13 -0
  110. package/fixtures/cases/date-time-format/context.json +1 -0
  111. package/fixtures/cases/date-time-format/expected.json +6 -0
  112. package/fixtures/cases/date-time-format/library/companies/acme.md +4 -0
  113. package/fixtures/cases/date-time-format/library/deals/renewal.md +31 -0
  114. package/fixtures/cases/date-time-format/schema.yaml +56 -0
  115. package/fixtures/cases/declared-binary-links/schema.yaml +1 -2
  116. package/fixtures/cases/default-unfilled/context.json +1 -0
  117. package/fixtures/cases/default-unfilled/expected.json +6 -0
  118. package/fixtures/cases/default-unfilled/library/companies/acme.md +4 -0
  119. package/fixtures/cases/default-unfilled/library/deals/renewal.md +29 -0
  120. package/fixtures/cases/default-unfilled/schema.yaml +56 -0
  121. package/fixtures/cases/defs-pattern/context.json +1 -0
  122. package/fixtures/cases/defs-pattern/expected.json +6 -0
  123. package/fixtures/cases/defs-pattern/library/companies/acme.md +4 -0
  124. package/fixtures/cases/defs-pattern/library/deals/renewal.md +31 -0
  125. package/fixtures/cases/defs-pattern/schema.yaml +56 -0
  126. package/fixtures/cases/dependent-rule/context.json +1 -0
  127. package/fixtures/cases/dependent-rule/expected.json +6 -0
  128. package/fixtures/cases/dependent-rule/library/companies/acme.md +4 -0
  129. package/fixtures/cases/dependent-rule/library/deals/renewal.md +30 -0
  130. package/fixtures/cases/dependent-rule/schema.yaml +56 -0
  131. package/fixtures/cases/duplicate-link-definition/schema.yaml +6 -6
  132. package/fixtures/cases/email-format/context.json +1 -0
  133. package/fixtures/cases/email-format/expected.json +6 -0
  134. package/fixtures/cases/email-format/library/companies/acme.md +4 -0
  135. package/fixtures/cases/email-format/library/deals/renewal.md +31 -0
  136. package/fixtures/cases/email-format/schema.yaml +56 -0
  137. package/fixtures/cases/fenced-link-definition/schema.yaml +6 -6
  138. package/fixtures/cases/field-enum/expected.json +2 -2
  139. package/fixtures/cases/field-enum/schema.yaml +7 -7
  140. package/fixtures/cases/frontmatter-schema/schema.yaml +3 -4
  141. package/fixtures/cases/integer-field/context.json +1 -0
  142. package/fixtures/cases/integer-field/expected.json +6 -0
  143. package/fixtures/cases/integer-field/library/companies/acme.md +4 -0
  144. package/fixtures/cases/integer-field/library/deals/renewal.md +31 -0
  145. package/fixtures/cases/integer-field/schema.yaml +56 -0
  146. package/fixtures/cases/interrupted-link-definition/schema.yaml +1 -2
  147. package/fixtures/cases/json-schema-constructs/context.json +1 -0
  148. package/fixtures/cases/json-schema-constructs/expected.json +1 -0
  149. package/fixtures/cases/json-schema-constructs/library/companies/acme.md +4 -0
  150. package/fixtures/cases/json-schema-constructs/library/deals/renewal.md +31 -0
  151. package/fixtures/cases/json-schema-constructs/schema.yaml +56 -0
  152. package/fixtures/cases/list-of-objects-closed/context.json +1 -0
  153. package/fixtures/cases/list-of-objects-closed/expected.json +6 -0
  154. package/fixtures/cases/list-of-objects-closed/library/companies/acme.md +4 -0
  155. package/fixtures/cases/list-of-objects-closed/library/deals/renewal.md +32 -0
  156. package/fixtures/cases/list-of-objects-closed/schema.yaml +56 -0
  157. package/fixtures/cases/list-of-objects-item/context.json +1 -0
  158. package/fixtures/cases/list-of-objects-item/expected.json +6 -0
  159. package/fixtures/cases/list-of-objects-item/library/companies/acme.md +4 -0
  160. package/fixtures/cases/list-of-objects-item/library/deals/renewal.md +31 -0
  161. package/fixtures/cases/list-of-objects-item/schema.yaml +56 -0
  162. package/fixtures/cases/list-of-objects-reference/context.json +1 -0
  163. package/fixtures/cases/list-of-objects-reference/expected.json +6 -0
  164. package/fixtures/cases/list-of-objects-reference/library/companies/acme.md +4 -0
  165. package/fixtures/cases/list-of-objects-reference/library/deals/renewal.md +14 -0
  166. package/fixtures/cases/list-of-objects-reference/library/places/depot.md +4 -0
  167. package/fixtures/cases/list-of-objects-reference/library/products/seats.md +4 -0
  168. package/fixtures/cases/list-of-objects-reference/library/products/support.md +4 -0
  169. package/fixtures/cases/list-of-objects-reference/schema.yaml +32 -0
  170. package/fixtures/cases/list-size/context.json +1 -0
  171. package/fixtures/cases/list-size/expected.json +6 -0
  172. package/fixtures/cases/list-size/library/companies/acme.md +4 -0
  173. package/fixtures/cases/list-size/library/deals/renewal.md +31 -0
  174. package/fixtures/cases/list-size/schema.yaml +56 -0
  175. package/fixtures/cases/long-fence-link-definition/schema.yaml +1 -2
  176. package/fixtures/cases/malformed-definition/expected.json +2 -2
  177. package/fixtures/cases/malformed-definition/schema.yaml +3 -4
  178. package/fixtures/cases/member-document/schema.yaml +5 -5
  179. package/fixtures/cases/missing-required-field/expected.json +2 -2
  180. package/fixtures/cases/missing-required-field/schema.yaml +7 -7
  181. package/fixtures/cases/missing-section-item-kind/expected.json +2 -2
  182. package/fixtures/cases/missing-section-item-kind/schema.yaml +6 -6
  183. package/fixtures/cases/misspelled-key/context.json +1 -0
  184. package/fixtures/cases/misspelled-key/expected.json +6 -0
  185. package/fixtures/cases/misspelled-key/library/companies/acme.md +4 -0
  186. package/fixtures/cases/misspelled-key/library/deals/renewal.md +32 -0
  187. package/fixtures/cases/misspelled-key/schema.yaml +56 -0
  188. package/fixtures/cases/nested-defs/context.json +1 -0
  189. package/fixtures/cases/nested-defs/expected.json +6 -0
  190. package/fixtures/cases/nested-defs/library/deal.md +6 -0
  191. package/fixtures/cases/nested-defs/schema.yaml +11 -0
  192. package/fixtures/cases/nested-object-reference/context.json +1 -0
  193. package/fixtures/cases/nested-object-reference/expected.json +6 -0
  194. package/fixtures/cases/nested-object-reference/library/companies/acme.md +4 -0
  195. package/fixtures/cases/nested-object-reference/library/deals/renewal.md +14 -0
  196. package/fixtures/cases/nested-object-reference/library/places/depot.md +4 -0
  197. package/fixtures/cases/nested-object-reference/library/products/seats.md +4 -0
  198. package/fixtures/cases/nested-object-reference/library/products/support.md +4 -0
  199. package/fixtures/cases/nested-object-reference/schema.yaml +32 -0
  200. package/fixtures/cases/nested-reference/context.json +1 -0
  201. package/fixtures/cases/nested-reference/expected.json +1 -0
  202. package/fixtures/cases/nested-reference/library/companies/acme.md +4 -0
  203. package/fixtures/cases/nested-reference/library/deals/renewal.md +15 -0
  204. package/fixtures/cases/nested-reference/library/places/depot.md +4 -0
  205. package/fixtures/cases/nested-reference/library/products/seats.md +4 -0
  206. package/fixtures/cases/nested-reference/library/products/support.md +4 -0
  207. package/fixtures/cases/nested-reference/schema.yaml +32 -0
  208. package/fixtures/cases/nested-required-field/context.json +1 -0
  209. package/fixtures/cases/nested-required-field/expected.json +6 -0
  210. package/fixtures/cases/nested-required-field/library/companies/acme.md +4 -0
  211. package/fixtures/cases/nested-required-field/library/deals/renewal.md +30 -0
  212. package/fixtures/cases/nested-required-field/schema.yaml +56 -0
  213. package/fixtures/cases/null-refused/context.json +1 -0
  214. package/fixtures/cases/null-refused/expected.json +6 -0
  215. package/fixtures/cases/null-refused/library/companies/acme.md +4 -0
  216. package/fixtures/cases/null-refused/library/deals/renewal.md +31 -0
  217. package/fixtures/cases/null-refused/schema.yaml +56 -0
  218. package/fixtures/cases/numeric-range/context.json +1 -0
  219. package/fixtures/cases/numeric-range/expected.json +6 -0
  220. package/fixtures/cases/numeric-range/library/companies/acme.md +4 -0
  221. package/fixtures/cases/numeric-range/library/deals/renewal.md +31 -0
  222. package/fixtures/cases/numeric-range/schema.yaml +56 -0
  223. package/fixtures/cases/one-of-variant/context.json +1 -0
  224. package/fixtures/cases/one-of-variant/expected.json +6 -0
  225. package/fixtures/cases/one-of-variant/library/companies/acme.md +4 -0
  226. package/fixtures/cases/one-of-variant/library/deals/renewal.md +31 -0
  227. package/fixtures/cases/one-of-variant/schema.yaml +56 -0
  228. package/fixtures/cases/open-map-value/context.json +1 -0
  229. package/fixtures/cases/open-map-value/expected.json +6 -0
  230. package/fixtures/cases/open-map-value/library/companies/acme.md +4 -0
  231. package/fixtures/cases/open-map-value/library/deals/renewal.md +31 -0
  232. package/fixtures/cases/open-map-value/schema.yaml +56 -0
  233. package/fixtures/cases/other-room-reference/context.json +1 -0
  234. package/fixtures/cases/other-room-reference/expected.json +6 -0
  235. package/fixtures/cases/other-room-reference/library/companies/acme.md +4 -0
  236. package/fixtures/cases/other-room-reference/library/deals/renewal.md +14 -0
  237. package/fixtures/cases/other-room-reference/library/places/depot.md +4 -0
  238. package/fixtures/cases/other-room-reference/library/products/seats.md +4 -0
  239. package/fixtures/cases/other-room-reference/library/products/support.md +4 -0
  240. package/fixtures/cases/other-room-reference/schema.yaml +32 -0
  241. package/fixtures/cases/paragraph-link-definition/schema.yaml +1 -2
  242. package/fixtures/cases/prototype-field/expected.json +1 -1
  243. package/fixtures/cases/prototype-field/schema.yaml +6 -6
  244. package/fixtures/cases/quoted-link-definition/library/notes/draft.md +1 -1
  245. package/fixtures/cases/quoted-link-definition/schema.yaml +1 -2
  246. package/fixtures/cases/referenced-missing-file/schema.yaml +11 -10
  247. package/fixtures/cases/remote-ref/context.json +1 -0
  248. package/fixtures/cases/remote-ref/expected.json +5 -0
  249. package/fixtures/cases/remote-ref/schema.yaml +3 -0
  250. package/fixtures/cases/second-member-document/expected.json +2 -2
  251. package/fixtures/cases/second-member-document/schema.yaml +4 -5
  252. package/fixtures/cases/section-item-enum/schema.yaml +3 -4
  253. package/fixtures/cases/section-item-kind/schema.yaml +3 -4
  254. package/fixtures/cases/section-items/library/page.md +14 -0
  255. package/fixtures/cases/section-items/schema.yaml +10 -8
  256. package/fixtures/cases/section-reference-path/schema.yaml +3 -4
  257. package/fixtures/cases/section-reference-type/schema.yaml +3 -4
  258. package/fixtures/cases/shortcut-reference-link/library/item.md +1 -1
  259. package/fixtures/cases/shortcut-reference-link/schema.yaml +6 -6
  260. package/fixtures/cases/string-length/context.json +1 -0
  261. package/fixtures/cases/string-length/expected.json +6 -0
  262. package/fixtures/cases/string-length/library/companies/acme.md +4 -0
  263. package/fixtures/cases/string-length/library/deals/renewal.md +31 -0
  264. package/fixtures/cases/string-length/schema.yaml +56 -0
  265. package/fixtures/cases/structured-section/schema.yaml +7 -7
  266. package/fixtures/cases/submission-keys/schema.yaml +4 -4
  267. package/fixtures/cases/text-field-kind/expected.json +2 -2
  268. package/fixtures/cases/text-field-kind/schema.yaml +4 -4
  269. package/fixtures/cases/truncated-link-definition/library/notes/draft.md +1 -1
  270. package/fixtures/cases/truncated-link-definition/schema.yaml +1 -2
  271. package/fixtures/cases/types-folder-content/schema.yaml +4 -4
  272. package/fixtures/cases/undeclared-field/expected.json +1 -1
  273. package/fixtures/cases/undeclared-field/schema.yaml +6 -6
  274. package/fixtures/cases/unevaluated-items-closed/context.json +1 -0
  275. package/fixtures/cases/unevaluated-items-closed/expected.json +6 -0
  276. package/fixtures/cases/unevaluated-items-closed/library/trip.md +6 -0
  277. package/fixtures/cases/unevaluated-items-closed/schema.yaml +10 -0
  278. package/fixtures/cases/unknown-type/expected.json +1 -1
  279. package/fixtures/cases/unknown-type/schema.yaml +3 -4
  280. package/fixtures/cases/unlisted-reference-type/expected.json +2 -2
  281. package/fixtures/cases/unlisted-reference-type/schema.yaml +3 -4
  282. package/fixtures/cases/unresolved-link/library/item.md +1 -1
  283. package/fixtures/cases/unresolved-link/schema.yaml +6 -6
  284. package/fixtures/cases/valid-typed-document/schema.yaml +16 -15
  285. package/fixtures/cases/wide-item-fence-link/schema.yaml +1 -2
  286. package/fixtures/division.json +1 -1
  287. package/fixtures/projection.json +33 -1
  288. package/package.json +4 -2
  289. package/fixtures/cases/missing-binary-image/schema.yaml +0 -2
  290. package/fixtures/cases/missing-binary-link/expected.json +0 -5
  291. package/fixtures/cases/missing-binary-link/schema.yaml +0 -2
  292. /package/fixtures/cases/{missing-binary-image → binary-image-dangles}/context.json +0 -0
  293. /package/fixtures/cases/{missing-binary-image → binary-image-dangles}/library/notes/draft.md +0 -0
  294. /package/fixtures/cases/{missing-binary-link → binary-link-dangles}/context.json +0 -0
  295. /package/fixtures/cases/{missing-binary-link → binary-link-dangles}/library/notes/draft.md +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"divide.d.ts","sourceRoot":"","sources":["../src/divide.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAgB,MAAM,YAAY,CAAC;AA4WpF,wBAAgB,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,QAAQ,CAc3F"}
1
+ {"version":3,"file":"divide.d.ts","sourceRoot":"","sources":["../src/divide.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAgB,MAAM,YAAY,CAAC;AAwXpF,wBAAgB,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,QAAQ,CAc3F"}
package/dist/divide.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { blockRanges, headingLines } from './blocks.js';
2
- import { projectionInput, rangeText } from './project.js';
2
+ import { firstEditFrom, projectionInput, rangeText, } from './project.js';
3
3
  import { refusal } from './refuse.js';
4
4
  const SMALLEST_BUDGET = 2;
5
5
  function node(draft) {
@@ -131,16 +131,26 @@ function textOf(state, extent) {
131
131
  return rangeText(state.content, extent, state.edits);
132
132
  }
133
133
  function sourceCutting(state, extent) {
134
- let text = state.content.slice(extent.start, extent.end);
134
+ const source = state.content.slice(extent.start, extent.end);
135
135
  const masks = [];
136
- for (const edit of state.edits) {
137
- if (edit.start < extent.start || edit.end > extent.end)
136
+ for (let index = firstEditFrom(state.edits, extent.start); index < state.edits.length; index += 1) {
137
+ const edit = state.edits[index];
138
+ if (edit.start > extent.end)
139
+ break;
140
+ if (edit.end > extent.end)
138
141
  continue;
139
- const from = edit.start - extent.start;
140
- const to = edit.end - extent.start;
141
- text = `${text.slice(0, from)}${'x'.repeat(to - from)}${text.slice(to)}`;
142
- masks.push({ start: from, end: to });
142
+ masks.push({ start: edit.start - extent.start, end: edit.end - extent.start });
143
143
  }
144
+ let text = '';
145
+ let cursor = 0;
146
+ for (const mask of masks) {
147
+ if (mask.end <= cursor)
148
+ continue;
149
+ const from = Math.max(mask.start, cursor);
150
+ text += `${source.slice(cursor, from)}${'x'.repeat(mask.end - from)}`;
151
+ cursor = mask.end;
152
+ }
153
+ text += source.slice(cursor);
144
154
  return {
145
155
  text,
146
156
  masks,
@@ -1,8 +1,16 @@
1
- import type { ApplyResult, Change, Document, Link, ParseResult } from './types.js';
1
+ import { type Definition } from './definition.js';
2
+ import type { ApplyResult, BodyResult, FrontmatterResult, Change, Document, Link, LinkOccurrence, ParseResult } from './types.js';
2
3
  import { type YamlMap } from './yaml.js';
4
+ export declare function parseFrontmatter(content: string, file?: string): FrontmatterResult;
3
5
  export declare function parse(content: string, file?: string): ParseResult;
6
+ export declare function relativize(document: Document, file: string, handle: string, definition?: Definition): ApplyResult;
7
+ export declare function relativizeBody(body: string, file: string, handle: string): BodyResult;
8
+ export declare function relinkBody(body: string, file: string, moves: ReadonlyMap<string, string>): BodyResult;
4
9
  export declare function links(document: Document, file: string): readonly Link[];
5
- export declare function apply(document: Document, change: Change): ApplyResult;
10
+ export declare function linkOccurrences(document: Document, file: string): readonly LinkOccurrence[];
11
+ export declare function bodyLinks(body: string, file: string): readonly Link[];
12
+ export declare function apply(document: Document, changes: readonly Change[]): ApplyResult;
6
13
  export declare function serialize(document: Document): string;
14
+ export declare function fieldStart(document: Document, pointer: string): number | undefined;
7
15
  export declare function frontmatter(document: Document): YamlMap | null;
8
16
  //# sourceMappingURL=document.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACnF,OAAO,EAYL,KAAK,OAAO,EACb,MAAM,WAAW,CAAC;AAwCnB,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,WAAW,CAkD7D;AAkHD,wBAAgB,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,IAAI,EAAE,CAWvE;AAED,wBAAgB,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAarE;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAEpD;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,IAAI,CAE9D"}
1
+ {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMhF,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,cAAc,EACd,WAAW,EAEZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAcL,KAAK,OAAO,EAEb,MAAM,WAAW,CAAC;AAmEnB,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,iBAAiB,CAW9E;AAED,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,WAAW,CAgB7D;AAmED,wBAAgB,UAAU,CACxB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,UAAU,GACtB,WAAW,CAoBb;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CASrF;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC,UAAU,CAeZ;AAuBD,wBAAgB,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,IAAI,EAAE,CAEvE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,cAAc,EAAE,CAG3F;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,IAAI,EAAE,CAErE;AA4LD,wBAAgB,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,WAAW,CA4CjF;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAEpD;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGlF;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,IAAI,CAE9D"}
package/dist/document.js CHANGED
@@ -1,8 +1,10 @@
1
+ import { ARRAY_INDEX, pointerSegments } from './definition.js';
1
2
  import { hrefOccurrences } from './links.js';
2
- import { retarget, target } from './paths.js';
3
+ import { destinationPath, relative, retarget, SHELL_ROOMS, shellTarget, target } from './paths.js';
4
+ import { references } from './references.js';
3
5
  import { headingSpans, sectionsRecord } from './sections.js';
4
6
  import { refusal } from './refuse.js';
5
- import { bodyStartAfterYaml, bodyStartOf, equalValue, extractFrontmatter, jsValue, lineEnding, mapEntry, parseYamlMapping, serializeJs, serializeKey, YamlError, } from './yaml.js';
7
+ import { bodyStartAfterYaml, bodyStartOf, equalValue, extractFrontmatter, frontmatterValue, jsValue, lineEnding, mapEntry, parseYamlMapping, serializeJs, serializeKey, YamlError, } from './yaml.js';
6
8
  const internals = new WeakMap();
7
9
  function refuse(file, rule, location) {
8
10
  return location === undefined ? refusal(file, rule) : refusal(file, rule, { location });
@@ -26,19 +28,10 @@ function declaredType(fields) {
26
28
  return undefined;
27
29
  return value;
28
30
  }
29
- export function parse(content, file = '') {
31
+ function opened(content, file) {
30
32
  const fence = extractFrontmatter(content);
31
- if (fence.kind === 'none') {
32
- const spans = headingSpans(content, 0);
33
- return {
34
- ok: true,
35
- document: freezeDocument(content, undefined, {}, content.slice(0, spans[0]?.headingStart), sectionsRecord(spans, content), {
36
- root: null,
37
- yamlEnd: 0,
38
- bodyStart: 0,
39
- }),
40
- };
41
- }
33
+ if (fence.kind === 'none')
34
+ return { ok: true, root: null, fields: {}, yamlEnd: 0 };
42
35
  if (fence.kind === 'unclosed')
43
36
  return { ok: false, refusal: refuse(file, 'frontmatter-fence') };
44
37
  try {
@@ -47,17 +40,7 @@ export function parse(content, file = '') {
47
40
  if (fields === null || typeof fields !== 'object' || Array.isArray(fields)) {
48
41
  return { ok: false, refusal: refuse(file, 'frontmatter-fence') };
49
42
  }
50
- const bodyStart = bodyStartAfterYaml(content, fence.yamlEnd);
51
- const spans = headingSpans(content, bodyStart);
52
- const record = fields;
53
- return {
54
- ok: true,
55
- document: freezeDocument(content, declaredType(record), record, content.slice(bodyStart, spans[0]?.headingStart), sectionsRecord(spans, content), {
56
- root,
57
- yamlEnd: fence.yamlEnd,
58
- bodyStart,
59
- }),
60
- };
43
+ return { ok: true, root, fields: fields, yamlEnd: fence.yamlEnd };
61
44
  }
62
45
  catch (error) {
63
46
  if (error instanceof YamlError)
@@ -65,63 +48,29 @@ export function parse(content, file = '') {
65
48
  throw error;
66
49
  }
67
50
  }
68
- function splice(content, start, end, insert) {
69
- return content.slice(0, start) + insert + content.slice(end);
70
- }
71
- function applyField(document, name, value, prior) {
72
- const internal = internals.get(document);
73
- if (internal === undefined || internal.root === null) {
74
- return { outcome: 'refuse', refusal: refuse('', 'frontmatter-fence', name) };
75
- }
76
- if (!equalValue(document.fields[name], prior)) {
77
- return { outcome: 'stale', document };
78
- }
79
- let nextContent;
80
- const existing = mapEntry(internal.root, name);
81
- if (existing !== undefined) {
82
- nextContent = splice(document.content, existing.value.start, existing.value.end, serializeJs(value));
83
- }
84
- else if (document.content[internal.root.start] === '{') {
85
- nextContent = splice(document.content, internal.root.end - 1, internal.root.end - 1, `${internal.root.entries.length === 0 ? '' : ', '}${serializeKey(name)}: ${serializeJs(value)}`);
86
- }
87
- else {
88
- const nl = lineEnding(document.content);
89
- const lineStart = document.content.lastIndexOf('\n', internal.root.start - 1) + 1;
90
- const indent = document.content.slice(lineStart, internal.root.start);
91
- const line = `${indent}${serializeKey(name)}: ${serializeJs(value)}${nl}`;
92
- const before = document.content.slice(0, internal.yamlEnd);
93
- const prefix = before.endsWith('\n') || before.endsWith('\r\n') ? '' : nl;
94
- nextContent = splice(document.content, internal.yamlEnd, internal.yamlEnd, `${prefix}${line}`);
95
- }
96
- const parsed = parse(nextContent);
97
- if (!parsed.ok)
98
- return { outcome: 'refuse', refusal: parsed.refusal };
99
- return { outcome: 'applied', document: parsed.document };
51
+ export function parseFrontmatter(content, file = '') {
52
+ const read = opened(content, file);
53
+ if (!read.ok)
54
+ return read;
55
+ return {
56
+ ok: true,
57
+ frontmatter: Object.freeze({
58
+ content,
59
+ type: declaredType(read.fields),
60
+ fields: Object.freeze(read.fields),
61
+ }),
62
+ };
100
63
  }
101
- function applySection(document, name, value, prior) {
102
- const internal = internals.get(document);
103
- if (internal === undefined)
104
- return { outcome: 'refuse', refusal: refuse('', 'required-section', name) };
105
- const spans = headingSpans(document.content, internal.bodyStart);
106
- const span = spans.find((item) => item.name === name);
107
- if (span === undefined)
108
- return { outcome: 'refuse', refusal: refuse('', 'required-section', name) };
109
- const current = document.content.slice(span.bodyStart, span.bodyEnd);
110
- if (current !== prior)
111
- return { outcome: 'stale', document };
112
- const parsed = parse(splice(document.content, span.bodyStart, span.bodyEnd, value));
113
- if (!parsed.ok)
114
- return { outcome: 'refuse', refusal: parsed.refusal };
115
- return { outcome: 'applied', document: parsed.document };
116
- }
117
- function applyPreamble(document, value, prior) {
118
- if (document.preamble !== prior)
119
- return { outcome: 'stale', document };
120
- const start = bodyStartOf(document.content);
121
- const parsed = parse(splice(document.content, start, start + document.preamble.length, value));
122
- if (!parsed.ok)
123
- return { outcome: 'refuse', refusal: parsed.refusal };
124
- return { outcome: 'applied', document: parsed.document };
64
+ export function parse(content, file = '') {
65
+ const read = opened(content, file);
66
+ if (!read.ok)
67
+ return read;
68
+ const bodyStart = read.root === null ? 0 : bodyStartAfterYaml(content, read.yamlEnd);
69
+ const spans = headingSpans(content, bodyStart);
70
+ return {
71
+ ok: true,
72
+ document: freezeDocument(content, declaredType(read.fields), read.fields, content.slice(bodyStart, spans[0]?.headingStart), sectionsRecord(spans, content), { root: read.root, yamlEnd: read.yamlEnd, bodyStart }),
73
+ };
125
74
  }
126
75
  function fitsBare(to) {
127
76
  if (to === '' || to.startsWith('<'))
@@ -150,62 +99,369 @@ function destinationText(to, bracketed) {
150
99
  return `<${to}>`;
151
100
  return null;
152
101
  }
153
- function applyLink(document, href, to) {
154
- const content = document.content;
155
- const bodyStart = bodyStartOf(content);
156
- const matches = hrefOccurrences(content.slice(bodyStart)).filter((occurrence) => occurrence.href === href);
157
- if (matches.length === 0)
158
- return { outcome: 'stale', document };
159
- const written = retarget(href, to);
102
+ function shellRelinked(body, file, handle) {
103
+ const occurrences = hrefOccurrences(body);
104
+ const written = new Map();
105
+ for (const href of new Set(occurrences.map((occurrence) => occurrence.href))) {
106
+ const path = shellTarget(href, handle);
107
+ if (path === null)
108
+ continue;
109
+ const to = retarget(href, relative(file, path));
110
+ if (destinationText(to, false) === null)
111
+ return refuse('', 'unwritable-link', to);
112
+ written.set(href, to);
113
+ }
114
+ let rewritten = '';
115
+ let cursor = 0;
116
+ for (const match of occurrences) {
117
+ const to = written.get(match.href);
118
+ if (to === undefined)
119
+ continue;
120
+ rewritten += body.slice(cursor, match.start) + destinationText(to, match.bracketed);
121
+ cursor = match.end;
122
+ }
123
+ return rewritten + body.slice(cursor);
124
+ }
125
+ function nodeAt(root, pointer, entryOf = mapEntry) {
126
+ let node = root;
127
+ for (const key of pointerSegments(pointer)) {
128
+ if (node?.kind === 'map')
129
+ node = entryOf(node, key)?.value;
130
+ else if (node?.kind === 'seq' && ARRAY_INDEX.test(key))
131
+ node = node.items[Number(key)];
132
+ else
133
+ return undefined;
134
+ }
135
+ return node;
136
+ }
137
+ function scalarText(source, value) {
138
+ if (source === "'")
139
+ return `'${value.replaceAll("'", "''")}'`;
140
+ if (source === '"')
141
+ return JSON.stringify(value);
142
+ return serializeJs(value);
143
+ }
144
+ export function relativize(document, file, handle, definition) {
145
+ const changes = [];
146
+ for (const { pointer, value } of definition === undefined
147
+ ? []
148
+ : references(document, definition)) {
149
+ const path = shellTarget(value, handle);
150
+ if (path !== null)
151
+ changes.push({
152
+ kind: 'reference',
153
+ pointer,
154
+ value: retarget(value, relative(file, path)),
155
+ prior: value,
156
+ });
157
+ }
158
+ const body = document.content.slice(bodyStartOf(document.content));
159
+ for (const href of new Set(hrefOccurrences(body).map((occurrence) => occurrence.href))) {
160
+ const path = shellTarget(href, handle);
161
+ if (path !== null)
162
+ changes.push({ kind: 'link', href, to: relative(file, path) });
163
+ }
164
+ return apply(document, changes);
165
+ }
166
+ export function relativizeBody(body, file, handle) {
167
+ const relinkedBody = shellRelinked(body, file, handle);
168
+ if (typeof relinkedBody !== 'string')
169
+ return { outcome: 'refuse', refusal: relinkedBody };
170
+ const elsewhere = hrefOccurrences(relinkedBody).find(({ href }) => destinationPath(href)?.startsWith(SHELL_ROOMS) === true);
171
+ if (elsewhere !== undefined)
172
+ return { outcome: 'refuse', refusal: refuse(file, 'unresolved-link', elsewhere.href) };
173
+ return { outcome: 'applied', body: relinkedBody };
174
+ }
175
+ export function relinkBody(body, file, moves) {
160
176
  let rewritten = '';
161
177
  let cursor = 0;
162
- for (const match of matches) {
178
+ for (const match of hrefOccurrences(body)) {
179
+ const from = target(file, match.href);
180
+ const to = from === null ? undefined : moves.get(from);
181
+ if (to === undefined)
182
+ continue;
183
+ const written = retarget(match.href, relative(file, to));
163
184
  const text = destinationText(written, match.bracketed);
164
185
  if (text === null)
165
- return { outcome: 'refuse', refusal: refuse('', 'unwritable-link', written) };
166
- rewritten += content.slice(cursor, bodyStart + match.start);
167
- rewritten += text;
168
- cursor = bodyStart + match.end;
186
+ return { outcome: 'refuse', refusal: refuse(file, 'unwritable-link', written) };
187
+ rewritten += body.slice(cursor, match.start) + text;
188
+ cursor = match.end;
169
189
  }
170
- const parsed = parse(rewritten + content.slice(cursor));
171
- if (!parsed.ok)
172
- return { outcome: 'refuse', refusal: parsed.refusal };
173
- return { outcome: 'applied', document: parsed.document };
190
+ return { outcome: 'applied', body: rewritten + body.slice(cursor) };
174
191
  }
175
- export function links(document, file) {
192
+ function occurrencesIn(text, file, offset) {
193
+ const found = [];
194
+ for (const occurrence of hrefOccurrences(text)) {
195
+ const resolved = target(file, occurrence.href);
196
+ if (resolved !== null)
197
+ found.push({ href: occurrence.href, target: resolved, start: offset + occurrence.start });
198
+ }
199
+ return found;
200
+ }
201
+ function linksIn(text, file) {
176
202
  const found = [];
177
203
  const seen = new Set();
178
- for (const occurrence of hrefOccurrences(document.content.slice(bodyStartOf(document.content)))) {
204
+ for (const occurrence of occurrencesIn(text, file, 0)) {
179
205
  if (seen.has(occurrence.href))
180
206
  continue;
181
- const resolved = target(file, occurrence.href);
182
- if (resolved === null)
183
- continue;
184
207
  seen.add(occurrence.href);
185
- found.push({ href: occurrence.href, target: resolved });
208
+ found.push({ href: occurrence.href, target: occurrence.target });
186
209
  }
187
210
  return found;
188
211
  }
189
- export function apply(document, change) {
212
+ export function links(document, file) {
213
+ return linksIn(document.content.slice(bodyStartOf(document.content)), file);
214
+ }
215
+ export function linkOccurrences(document, file) {
216
+ const bodyStart = bodyStartOf(document.content);
217
+ return occurrencesIn(document.content.slice(bodyStart), file, bodyStart);
218
+ }
219
+ export function bodyLinks(body, file) {
220
+ return linksIn(body, file);
221
+ }
222
+ function internalOf(document) {
223
+ const held = internals.get(document);
224
+ if (held !== undefined)
225
+ return held;
226
+ const read = opened(document.content, '');
227
+ if (!read.ok)
228
+ return read.refusal;
229
+ return {
230
+ root: read.root,
231
+ yamlEnd: read.yamlEnd,
232
+ bodyStart: read.root === null ? 0 : bodyStartAfterYaml(document.content, read.yamlEnd),
233
+ };
234
+ }
235
+ function partOf(change) {
236
+ if (change.kind === 'field' || change.kind === 'section')
237
+ return `${change.kind} ${change.name}`;
190
238
  if (change.kind === 'link')
191
- return applyLink(document, change.href, change.to);
192
- if (change.kind === 'preamble')
193
- return applyPreamble(document, change.value, change.prior);
194
- try {
239
+ return `link ${change.href}`;
240
+ if (change.kind === 'reference')
241
+ return `reference ${change.pointer}`;
242
+ return 'preamble';
243
+ }
244
+ function planner(document, internal) {
245
+ const content = document.content;
246
+ const keyed = new Map();
247
+ let spans;
248
+ let occurrences;
249
+ let ending;
250
+ let added = 0;
251
+ const entryOf = (map, key) => {
252
+ let index = keyed.get(map);
253
+ if (index === undefined) {
254
+ index = new Map();
255
+ for (const entry of map.entries)
256
+ if (!index.has(entry.key))
257
+ index.set(entry.key, entry);
258
+ keyed.set(map, index);
259
+ }
260
+ return index.get(key);
261
+ };
262
+ const field = (name, value, prior, at) => {
263
+ const root = internal.root;
264
+ if (root === null)
265
+ return refuse('', 'frontmatter-fence', name);
266
+ if (!equalValue(document.fields[name], prior))
267
+ return 'stale';
268
+ if (!frontmatterValue(value))
269
+ return refuse('', 'frontmatter-fence', name);
270
+ const existing = entryOf(root, name);
271
+ if (existing !== undefined) {
272
+ const held = existing.value;
273
+ const inline = held.start > existing.after && !/[\r\n]/.test(content.slice(existing.after, held.start));
274
+ return inline
275
+ ? [{ start: held.start, end: held.end, text: serializeJs(value), at }]
276
+ : [{ start: existing.after, end: held.end, text: ` ${serializeJs(value)}`, at }];
277
+ }
278
+ const entry = `${serializeKey(name)}: ${serializeJs(value)}`;
279
+ added += 1;
280
+ if (content[root.start] === '{') {
281
+ const separator = root.entries.length === 0 && added === 1 ? '' : ', ';
282
+ return [{ start: root.end - 1, end: root.end - 1, text: `${separator}${entry}`, at }];
283
+ }
284
+ const lineStart = content.lastIndexOf('\n', root.start - 1) + 1;
285
+ ending ??= lineEnding(content);
286
+ const line = `${content.slice(lineStart, root.start)}${entry}${ending}`;
287
+ return [{ start: internal.yamlEnd, end: internal.yamlEnd, text: line, at, entry: true }];
288
+ };
289
+ const section = (name, value, prior, at) => {
290
+ if (spans === undefined) {
291
+ spans = new Map();
292
+ for (const span of headingSpans(content, internal.bodyStart))
293
+ if (!spans.has(span.name))
294
+ spans.set(span.name, span);
295
+ }
296
+ const span = spans.get(name);
297
+ if (span === undefined)
298
+ return refuse('', 'required-section', name);
299
+ if (content.slice(span.bodyStart, span.bodyEnd) !== prior)
300
+ return 'stale';
301
+ return [{ start: span.bodyStart, end: span.bodyEnd, text: value, at }];
302
+ };
303
+ const link = (href, to, at) => {
304
+ if (occurrences === undefined) {
305
+ occurrences = new Map();
306
+ for (const occurrence of hrefOccurrences(content.slice(internal.bodyStart))) {
307
+ const same = occurrences.get(occurrence.href);
308
+ if (same === undefined)
309
+ occurrences.set(occurrence.href, [occurrence]);
310
+ else
311
+ same.push(occurrence);
312
+ }
313
+ }
314
+ const found = occurrences.get(href);
315
+ if (found === undefined)
316
+ return 'stale';
317
+ const written = retarget(href, to);
318
+ if (destinationText(written, false) === null)
319
+ return refuse('', 'unwritable-link', written);
320
+ return found.map((occurrence) => ({
321
+ start: internal.bodyStart + occurrence.start,
322
+ end: internal.bodyStart + occurrence.end,
323
+ text: destinationText(written, occurrence.bracketed),
324
+ at,
325
+ }));
326
+ };
327
+ const reference = (pointer, value, prior, at) => {
328
+ const node = internal.root === null ? undefined : nodeAt(internal.root, pointer, entryOf);
329
+ if (node?.kind !== 'scalar' || node.value !== prior)
330
+ return 'stale';
331
+ return [
332
+ { start: node.start, end: node.end, text: scalarText(content[node.start], value), at },
333
+ ];
334
+ };
335
+ return (change, at) => {
195
336
  if (change.kind === 'field')
196
- return applyField(document, change.name, change.value, change.prior);
197
- return applySection(document, change.name, change.value, change.prior);
337
+ return field(change.name, change.value, change.prior, at);
338
+ if (change.kind === 'section')
339
+ return section(change.name, change.value, change.prior, at);
340
+ if (change.kind === 'link')
341
+ return link(change.href, change.to, at);
342
+ if (change.kind === 'reference')
343
+ return reference(change.pointer, change.value, change.prior, at);
344
+ if (document.preamble !== change.prior)
345
+ return 'stale';
346
+ const start = internal.bodyStart;
347
+ return [{ start, end: start + document.preamble.length, text: change.value, at }];
348
+ };
349
+ }
350
+ function overlapping(edits, stale) {
351
+ let reach = -1;
352
+ let owner = -1;
353
+ for (const edit of edits) {
354
+ if (edit.start < reach)
355
+ stale.add(Math.max(edit.at, owner));
356
+ if (edit.end > reach) {
357
+ reach = edit.end;
358
+ owner = edit.at;
359
+ }
198
360
  }
199
- catch (error) {
200
- if (error instanceof YamlError) {
201
- return { outcome: 'refuse', refusal: refuse('', 'frontmatter-fence', change.name) };
361
+ }
362
+ function firstHeadings(content, bodyStart) {
363
+ const first = new Map();
364
+ for (const span of headingSpans(content, bodyStart)) {
365
+ if (!first.has(span.name))
366
+ first.set(span.name, span.headingStart);
367
+ }
368
+ return first;
369
+ }
370
+ function hidden(before, bodyStart, after, shifts) {
371
+ const placed = firstHeadings(after, bodyStartOf(after));
372
+ let shift = 0;
373
+ let index = 0;
374
+ for (const [name, at] of firstHeadings(before, bodyStart)) {
375
+ while (index < shifts.length && shifts[index][0] <= at) {
376
+ shift += shifts[index][1];
377
+ index += 1;
202
378
  }
203
- throw error;
379
+ if (placed.get(name) !== at + shift)
380
+ return name;
381
+ }
382
+ return undefined;
383
+ }
384
+ function spliced(source, edits) {
385
+ const shifts = [];
386
+ const pieces = [];
387
+ let cursor = 0;
388
+ let entered = false;
389
+ let ended = false;
390
+ for (const edit of edits) {
391
+ const kept = source.slice(cursor, edit.start);
392
+ pieces.push(kept);
393
+ if (kept !== '')
394
+ ended = kept.endsWith('\n');
395
+ let text = edit.text;
396
+ if (edit.entry === true && !entered) {
397
+ entered = true;
398
+ if (!ended)
399
+ text = `${lineEnding(source)}${text}`;
400
+ }
401
+ pieces.push(text);
402
+ if (text !== '')
403
+ ended = text.endsWith('\n');
404
+ shifts.push([edit.start, text.length - (edit.end - edit.start)]);
405
+ cursor = edit.end;
406
+ }
407
+ pieces.push(source.slice(cursor));
408
+ return { content: pieces.join(''), shifts };
409
+ }
410
+ export function apply(document, changes) {
411
+ const internal = internalOf(document);
412
+ if (!('bodyStart' in internal))
413
+ return { outcome: 'refuse', refusal: internal };
414
+ const plan = planner(document, internal);
415
+ const edits = [];
416
+ const stale = new Set();
417
+ const named = new Set();
418
+ for (const [at, change] of changes.entries()) {
419
+ const planned = plan(change, at);
420
+ if (planned === 'stale') {
421
+ stale.add(at);
422
+ continue;
423
+ }
424
+ if (!Array.isArray(planned))
425
+ return { outcome: 'refuse', refusal: planned };
426
+ const part = partOf(change);
427
+ if (named.has(part)) {
428
+ stale.add(at);
429
+ continue;
430
+ }
431
+ named.add(part);
432
+ for (const edit of planned)
433
+ edits.push(edit);
434
+ }
435
+ edits.sort((left, right) => left.start - right.start || left.end - right.end || left.at - right.at);
436
+ overlapping(edits, stale);
437
+ if (stale.size > 0)
438
+ return { outcome: 'stale', document, stale: [...stale].sort((left, right) => left - right) };
439
+ const source = document.content;
440
+ const { content } = spliced(source, edits);
441
+ if (content === source)
442
+ return { outcome: 'applied', document };
443
+ const replaced = edits.filter((edit) => {
444
+ const kind = changes[edit.at].kind;
445
+ return kind === 'section' || kind === 'preamble';
446
+ });
447
+ if (replaced.length > 0) {
448
+ const checked = spliced(source, replaced);
449
+ const name = hidden(source, internal.bodyStart, checked.content, checked.shifts);
450
+ if (name !== undefined)
451
+ return { outcome: 'refuse', refusal: refuse('', 'overlapping-section', name) };
204
452
  }
453
+ const parsed = parse(content);
454
+ if (!parsed.ok)
455
+ return { outcome: 'refuse', refusal: parsed.refusal };
456
+ return { outcome: 'applied', document: parsed.document };
205
457
  }
206
458
  export function serialize(document) {
207
459
  return document.content;
208
460
  }
461
+ export function fieldStart(document, pointer) {
462
+ const root = internals.get(document)?.root;
463
+ return root === null || root === undefined ? undefined : nodeAt(root, pointer)?.start;
464
+ }
209
465
  export function frontmatter(document) {
210
466
  return internals.get(document)?.root ?? null;
211
467
  }
package/dist/fields.d.ts CHANGED
@@ -1,4 +1,6 @@
1
+ export declare const TYPE_FIELD = "type";
1
2
  export declare const MEMBER_FIELD = "member";
2
3
  export declare const SITE_FIELD = "site";
3
4
  export declare const RECEIVED_FIELD = "received";
5
+ export declare const HOUSE_FIELDS: readonly string[];
4
6
  //# sourceMappingURL=fields.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../src/fields.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,WAAW,CAAC;AAErC,eAAO,MAAM,UAAU,SAAS,CAAC;AAEjC,eAAO,MAAM,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../src/fields.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,SAAS,CAAC;AAEjC,eAAO,MAAM,YAAY,WAAW,CAAC;AAErC,eAAO,MAAM,UAAU,SAAS,CAAC;AAEjC,eAAO,MAAM,cAAc,aAAa,CAAC;AAEzC,eAAO,MAAM,YAAY,EAAE,SAAS,MAAM,EAKzC,CAAC"}
package/dist/fields.js CHANGED
@@ -1,3 +1,10 @@
1
+ export const TYPE_FIELD = 'type';
1
2
  export const MEMBER_FIELD = 'member';
2
3
  export const SITE_FIELD = 'site';
3
4
  export const RECEIVED_FIELD = 'received';
5
+ export const HOUSE_FIELDS = [
6
+ TYPE_FIELD,
7
+ SITE_FIELD,
8
+ RECEIVED_FIELD,
9
+ MEMBER_FIELD,
10
+ ];