@agentshouse/mdmodel 0.1.0-alpha.9 → 0.1.0-c83456e1cebfb

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 (202) hide show
  1. package/API.md +298 -0
  2. package/README.md +29 -186
  3. package/dist/blocks.d.ts +11 -0
  4. package/dist/blocks.d.ts.map +1 -0
  5. package/dist/blocks.js +62 -0
  6. package/dist/definition.d.ts +7 -3
  7. package/dist/definition.d.ts.map +1 -1
  8. package/dist/definition.js +143 -134
  9. package/dist/divide.d.ts +3 -0
  10. package/dist/divide.d.ts.map +1 -0
  11. package/dist/divide.js +310 -0
  12. package/dist/document.d.ts +2 -0
  13. package/dist/document.d.ts.map +1 -1
  14. package/dist/document.js +89 -120
  15. package/dist/fields.d.ts +4 -0
  16. package/dist/fields.d.ts.map +1 -0
  17. package/dist/fields.js +3 -0
  18. package/dist/index.d.ts +6 -2
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +4 -3
  21. package/dist/links.d.ts +1 -0
  22. package/dist/links.d.ts.map +1 -1
  23. package/dist/links.js +618 -224
  24. package/dist/paths.d.ts +2 -3
  25. package/dist/paths.d.ts.map +1 -1
  26. package/dist/paths.js +27 -37
  27. package/dist/profile.js +1 -3
  28. package/dist/project.d.ts +19 -1
  29. package/dist/project.d.ts.map +1 -1
  30. package/dist/project.js +75 -91
  31. package/dist/refuse.d.ts.map +1 -1
  32. package/dist/refuse.js +2 -10
  33. package/dist/schema.d.ts +2 -1
  34. package/dist/schema.d.ts.map +1 -1
  35. package/dist/schema.js +22 -33
  36. package/dist/sections.d.ts +2 -1
  37. package/dist/sections.d.ts.map +1 -1
  38. package/dist/sections.js +44 -66
  39. package/dist/types.d.ts +30 -2
  40. package/dist/types.d.ts.map +1 -1
  41. package/dist/types.js +1 -3
  42. package/dist/validate.d.ts +3 -2
  43. package/dist/validate.d.ts.map +1 -1
  44. package/dist/validate.js +145 -127
  45. package/dist/version.d.ts +1 -1
  46. package/dist/version.d.ts.map +1 -1
  47. package/dist/version.js +1 -3
  48. package/dist/yaml.d.ts +1 -0
  49. package/dist/yaml.d.ts.map +1 -1
  50. package/dist/yaml.js +195 -186
  51. package/fixtures/README.md +77 -53
  52. package/fixtures/cases/binary-any-reference/expected.json +0 -1
  53. package/fixtures/cases/binary-any-reference/schema.yaml +4 -0
  54. package/fixtures/cases/binary-document-collision/expected.json +1 -2
  55. package/fixtures/cases/binary-document-collision/schema.yaml +2 -0
  56. package/fixtures/cases/binary-link-outside-collection/expected.json +1 -2
  57. package/fixtures/cases/binary-link-outside-collection/schema.yaml +2 -0
  58. package/fixtures/cases/binary-prototype-reference/expected.json +0 -1
  59. package/fixtures/cases/binary-prototype-reference/schema.yaml +4 -0
  60. package/fixtures/cases/binary-typed-reference/expected.json +0 -1
  61. package/fixtures/cases/binary-typed-reference/schema.yaml +5 -0
  62. package/fixtures/cases/bracketed-link-definition/schema.yaml +6 -0
  63. package/fixtures/cases/declared-binary-links/schema.yaml +2 -0
  64. package/fixtures/cases/duplicate-link-definition/schema.yaml +6 -0
  65. package/fixtures/cases/fenced-link-definition/schema.yaml +6 -0
  66. package/fixtures/cases/field-enum/expected.json +1 -2
  67. package/fixtures/cases/field-enum/schema.yaml +7 -0
  68. package/fixtures/cases/frontmatter-schema/expected.json +5 -0
  69. package/fixtures/cases/frontmatter-schema/schema.yaml +6 -0
  70. package/fixtures/cases/interrupted-link-definition/schema.yaml +2 -0
  71. package/fixtures/cases/long-fence-link-definition/schema.yaml +2 -0
  72. package/fixtures/cases/malformed-definition/expected.json +2 -4
  73. package/fixtures/cases/malformed-definition/schema.yaml +4 -0
  74. package/fixtures/cases/member-document/context.json +1 -0
  75. package/fixtures/cases/member-document/library/people/ana.md +5 -0
  76. package/fixtures/cases/member-document/schema.yaml +5 -0
  77. package/fixtures/cases/missing-binary-image/expected.json +1 -2
  78. package/fixtures/cases/missing-binary-image/schema.yaml +2 -0
  79. package/fixtures/cases/missing-binary-link/expected.json +1 -2
  80. package/fixtures/cases/missing-binary-link/schema.yaml +2 -0
  81. package/fixtures/cases/missing-required-field/expected.json +1 -2
  82. package/fixtures/cases/missing-required-field/schema.yaml +7 -0
  83. package/fixtures/cases/missing-section-item-kind/expected.json +2 -4
  84. package/fixtures/cases/missing-section-item-kind/schema.yaml +6 -0
  85. package/fixtures/cases/paragraph-link-definition/schema.yaml +2 -0
  86. package/fixtures/cases/prototype-field/expected.json +1 -2
  87. package/fixtures/cases/prototype-field/schema.yaml +6 -0
  88. package/fixtures/cases/quoted-link-definition/expected.json +1 -2
  89. package/fixtures/cases/quoted-link-definition/schema.yaml +2 -0
  90. package/fixtures/cases/referenced-missing-file/expected.json +0 -1
  91. package/fixtures/cases/referenced-missing-file/schema.yaml +10 -0
  92. package/fixtures/cases/second-member-document/context.json +1 -0
  93. package/fixtures/cases/second-member-document/expected.json +5 -0
  94. package/fixtures/cases/second-member-document/schema.yaml +5 -0
  95. package/fixtures/cases/section-item-enum/context.json +1 -0
  96. package/fixtures/cases/section-item-enum/expected.json +6 -0
  97. package/fixtures/cases/section-item-enum/library/task.md +8 -0
  98. package/fixtures/cases/section-item-enum/schema.yaml +4 -0
  99. package/fixtures/cases/section-item-kind/context.json +1 -0
  100. package/fixtures/cases/section-item-kind/expected.json +6 -0
  101. package/fixtures/cases/section-item-kind/library/task.md +8 -0
  102. package/fixtures/cases/section-item-kind/schema.yaml +4 -0
  103. package/fixtures/cases/section-items/context.json +1 -0
  104. package/fixtures/cases/section-items/expected.json +1 -0
  105. package/fixtures/cases/section-items/library/other.md +3 -0
  106. package/fixtures/cases/section-items/library/page.md +28 -0
  107. package/fixtures/cases/section-items/schema.yaml +8 -0
  108. package/fixtures/cases/section-reference-path/context.json +1 -0
  109. package/fixtures/cases/section-reference-path/expected.json +6 -0
  110. package/fixtures/cases/section-reference-path/library/other.md +3 -0
  111. package/fixtures/cases/section-reference-path/library/page.md +7 -0
  112. package/fixtures/cases/section-reference-path/schema.yaml +4 -0
  113. package/fixtures/cases/section-reference-type/context.json +1 -0
  114. package/fixtures/cases/section-reference-type/expected.json +6 -0
  115. package/fixtures/cases/section-reference-type/library/note.md +1 -0
  116. package/fixtures/cases/section-reference-type/library/page.md +7 -0
  117. package/fixtures/cases/section-reference-type/schema.yaml +4 -0
  118. package/fixtures/cases/shortcut-reference-link/context.json +1 -0
  119. package/fixtures/cases/shortcut-reference-link/expected.json +5 -0
  120. package/fixtures/cases/shortcut-reference-link/library/item.md +10 -0
  121. package/fixtures/cases/shortcut-reference-link/schema.yaml +6 -0
  122. package/fixtures/cases/structured-section/expected.json +1 -2
  123. package/fixtures/cases/structured-section/schema.yaml +7 -0
  124. package/fixtures/cases/submission-keys/context.json +1 -0
  125. package/fixtures/cases/submission-keys/expected.json +1 -0
  126. package/fixtures/cases/submission-keys/library/notes/visitor.md +8 -0
  127. package/fixtures/cases/submission-keys/schema.yaml +4 -0
  128. package/fixtures/cases/text-field-kind/context.json +1 -0
  129. package/fixtures/cases/text-field-kind/expected.json +6 -0
  130. package/fixtures/cases/text-field-kind/library/page.md +4 -0
  131. package/fixtures/cases/text-field-kind/schema.yaml +4 -0
  132. package/fixtures/cases/truncated-link-definition/expected.json +1 -2
  133. package/fixtures/cases/truncated-link-definition/schema.yaml +2 -0
  134. package/fixtures/cases/types-folder-content/context.json +1 -0
  135. package/fixtures/cases/types-folder-content/expected.json +1 -0
  136. package/fixtures/cases/types-folder-content/library/types/task.md +4 -0
  137. package/fixtures/cases/types-folder-content/schema.yaml +4 -0
  138. package/fixtures/cases/unclosed-frontmatter/expected.json +1 -2
  139. package/fixtures/cases/undeclared-field/expected.json +1 -2
  140. package/fixtures/cases/undeclared-field/schema.yaml +6 -0
  141. package/fixtures/cases/unknown-type/context.json +1 -0
  142. package/fixtures/cases/unknown-type/expected.json +6 -0
  143. package/fixtures/cases/unknown-type/library/item.md +3 -0
  144. package/fixtures/cases/unknown-type/schema.yaml +4 -0
  145. package/fixtures/cases/unlisted-reference-type/context.json +1 -0
  146. package/fixtures/cases/unlisted-reference-type/expected.json +5 -0
  147. package/fixtures/cases/unlisted-reference-type/schema.yaml +4 -0
  148. package/fixtures/cases/unresolved-link/expected.json +1 -2
  149. package/fixtures/cases/unresolved-link/schema.yaml +6 -0
  150. package/fixtures/cases/valid-typed-document/schema.yaml +15 -0
  151. package/fixtures/cases/wide-item-fence-link/schema.yaml +2 -0
  152. package/fixtures/division.json +409 -0
  153. package/fixtures/projection.json +58 -21
  154. package/package.json +3 -12
  155. package/dist/definition.js.map +0 -1
  156. package/dist/document.js.map +0 -1
  157. package/dist/index.js.map +0 -1
  158. package/dist/links.js.map +0 -1
  159. package/dist/paths.js.map +0 -1
  160. package/dist/profile.js.map +0 -1
  161. package/dist/project.js.map +0 -1
  162. package/dist/refuse.js.map +0 -1
  163. package/dist/schema.js.map +0 -1
  164. package/dist/sections.js.map +0 -1
  165. package/dist/types.js.map +0 -1
  166. package/dist/validate.js.map +0 -1
  167. package/dist/version.js.map +0 -1
  168. package/dist/yaml.js.map +0 -1
  169. package/fixtures/cases/binary-any-reference/library/types/note.md +0 -5
  170. package/fixtures/cases/binary-document-collision/library/types/note.md +0 -3
  171. package/fixtures/cases/binary-link-outside-collection/library/types/note.md +0 -3
  172. package/fixtures/cases/binary-prototype-reference/library/types/note.md +0 -5
  173. package/fixtures/cases/binary-typed-reference/library/types/note.md +0 -5
  174. package/fixtures/cases/binary-typed-reference/library/types/person.md +0 -3
  175. package/fixtures/cases/bracketed-link-definition/library/types/task.md +0 -7
  176. package/fixtures/cases/declared-binary-links/library/types/note.md +0 -3
  177. package/fixtures/cases/duplicate-link-definition/library/types/task.md +0 -7
  178. package/fixtures/cases/fenced-link-definition/library/types/task.md +0 -7
  179. package/fixtures/cases/field-enum/library/types/task.md +0 -8
  180. package/fixtures/cases/interrupted-link-definition/library/types/note.md +0 -3
  181. package/fixtures/cases/long-fence-link-definition/library/types/note.md +0 -3
  182. package/fixtures/cases/malformed-definition/library/types/task.md +0 -5
  183. package/fixtures/cases/missing-binary-image/library/types/note.md +0 -3
  184. package/fixtures/cases/missing-binary-link/library/types/note.md +0 -3
  185. package/fixtures/cases/missing-required-field/library/types/task.md +0 -8
  186. package/fixtures/cases/missing-section-item-kind/library/types/task.md +0 -7
  187. package/fixtures/cases/paragraph-link-definition/library/types/note.md +0 -3
  188. package/fixtures/cases/prd-definition/library/types/task.md +0 -16
  189. package/fixtures/cases/prototype-field/library/types/task.md +0 -7
  190. package/fixtures/cases/quoted-link-definition/library/types/note.md +0 -3
  191. package/fixtures/cases/referenced-missing-file/library/types/person.md +0 -5
  192. package/fixtures/cases/referenced-missing-file/library/types/task.md +0 -8
  193. package/fixtures/cases/structured-section/library/types/task.md +0 -8
  194. package/fixtures/cases/truncated-link-definition/library/types/note.md +0 -3
  195. package/fixtures/cases/undeclared-field/library/types/task.md +0 -7
  196. package/fixtures/cases/unresolved-link/library/types/task.md +0 -7
  197. package/fixtures/cases/valid-typed-document/library/types/person.md +0 -5
  198. package/fixtures/cases/valid-typed-document/library/types/task.md +0 -13
  199. package/fixtures/cases/wide-item-fence-link/library/types/note.md +0 -3
  200. package/markdown-syntax-profile.md +0 -9
  201. /package/fixtures/cases/{prd-definition → frontmatter-schema}/context.json +0 -0
  202. /package/fixtures/cases/{prd-definition → member-document}/expected.json +0 -0
@@ -1,171 +1,180 @@
1
- import { typeNameFromPath } from './paths.js';
2
- import { refusal } from './refuse.js';
3
- function refuse(file, rule, location) {
4
- return location === undefined ? refusal(file, rule) : refusal(file, rule, {
5
- location
6
- });
1
+ import { jsValue, parseYamlMapping, YamlError } from './yaml.js';
2
+ function refuse(rule, location) {
3
+ return location === undefined ? { rule } : { rule, location };
7
4
  }
8
5
  function isRecord(value) {
9
6
  return value !== null && typeof value === 'object' && !Array.isArray(value);
10
7
  }
11
8
  function requiredFlag(value) {
12
- if (value === undefined) return false;
13
- if (typeof value === 'boolean') return value;
9
+ if (value === undefined)
10
+ return false;
11
+ if (typeof value === 'boolean')
12
+ return value;
14
13
  return undefined;
15
14
  }
16
15
  function stringList(value) {
17
- if (!Array.isArray(value) || value.length === 0) return undefined;
18
- if (!value.every((item)=>typeof item === 'string' && item !== '')) return undefined;
19
- return value;
16
+ if (!Array.isArray(value) || value.length === 0)
17
+ return undefined;
18
+ if (!value.every((item) => typeof item === 'string' && item !== ''))
19
+ return undefined;
20
+ return [...value];
20
21
  }
21
- const SCALAR_KINDS = new Set([
22
- 'text',
23
- 'string',
24
- 'number',
25
- 'date',
26
- 'enum',
27
- 'reference'
28
- ]);
29
- function parseScalar(file, location, spec, required) {
22
+ const SCALAR_KINDS = new Set(['text', 'string', 'number', 'date', 'enum', 'reference']);
23
+ function parseScalar(names, location, spec, required) {
30
24
  const kind = spec.kind;
31
- if (kind === 'text') return {
32
- kind: 'text',
33
- required
34
- };
35
- if (kind === 'string') return {
36
- kind: 'string',
37
- required
38
- };
39
- if (kind === 'number') return {
40
- kind: 'number',
41
- required
42
- };
43
- if (kind === 'date') return {
44
- kind: 'date',
45
- required
46
- };
25
+ if (kind === 'text')
26
+ return { kind: 'text', required };
27
+ if (kind === 'string')
28
+ return { kind: 'string', required };
29
+ if (kind === 'number')
30
+ return { kind: 'number', required };
31
+ if (kind === 'date')
32
+ return { kind: 'date', required };
47
33
  if (kind === 'enum') {
48
34
  const values = stringList(spec.values);
49
- if (values === undefined) return refuse(file, 'definition-enum-values', location);
50
- return {
51
- kind: 'enum',
52
- required,
53
- values
54
- };
35
+ if (values === undefined)
36
+ return refuse('definition-enum-values', location);
37
+ return { kind: 'enum', required, values };
55
38
  }
56
39
  if (kind === 'reference') {
57
- if (typeof spec.to !== 'string' || spec.to === '') return refuse(file, 'definition-reference-to', location);
58
- return {
59
- kind: 'reference',
60
- required,
61
- to: spec.to
62
- };
40
+ if (typeof spec.to !== 'string' || (spec.to !== 'any' && !names.has(spec.to)))
41
+ return refuse('definition-reference-to', location);
42
+ return { kind: 'reference', required, to: spec.to };
63
43
  }
64
- return refuse(file, 'definition-field-kind', location);
44
+ return refuse('definition-field-kind', location);
65
45
  }
66
46
  function extraKeys(spec, allowed) {
67
- return Object.keys(spec).some((key)=>!allowed.includes(key));
47
+ return Object.keys(spec).some((key) => !allowed.includes(key));
68
48
  }
69
- function parseList(file, location, spec, required, malformed) {
49
+ function parseList(names, location, spec, required, malformed) {
70
50
  if (typeof spec.of !== 'string' || !SCALAR_KINDS.has(spec.of)) {
71
- return refuse(file, 'definition-list-of', location);
51
+ return refuse('definition-list-of', location);
72
52
  }
73
- const allowed = spec.of === 'enum' ? [
74
- 'kind',
75
- 'required',
76
- 'of',
77
- 'values'
78
- ] : spec.of === 'reference' ? [
79
- 'kind',
80
- 'required',
81
- 'of',
82
- 'to'
83
- ] : [
84
- 'kind',
85
- 'required',
86
- 'of'
87
- ];
88
- if (extraKeys(spec, allowed)) return refuse(file, malformed, location);
89
- const inner = parseScalar(file, location, {
90
- ...spec,
91
- kind: spec.of
92
- }, false);
93
- if ('rule' in inner) return inner;
94
- return {
95
- kind: 'list',
96
- required,
97
- of: inner
98
- };
53
+ const allowed = spec.of === 'enum'
54
+ ? ['kind', 'required', 'of', 'values']
55
+ : spec.of === 'reference'
56
+ ? ['kind', 'required', 'of', 'to']
57
+ : ['kind', 'required', 'of'];
58
+ if (extraKeys(spec, allowed))
59
+ return refuse(malformed, location);
60
+ const inner = parseScalar(names, location, { ...spec, kind: spec.of }, false);
61
+ if ('rule' in inner)
62
+ return inner;
63
+ return { kind: 'list', required, of: inner };
99
64
  }
100
- function parseField(file, location, value) {
101
- if (!isRecord(value) || typeof value.kind !== 'string') return refuse(file, 'definition-field', location);
65
+ function parseField(names, location, value) {
66
+ if (!isRecord(value) || typeof value.kind !== 'string')
67
+ return refuse('definition-field', location);
102
68
  const required = requiredFlag(value.required);
103
- if (required === undefined) return refuse(file, 'definition-field', location);
104
- if (value.kind === 'list') return parseList(file, location, value, required, 'definition-field');
105
- const allowed = value.kind === 'enum' ? [
106
- 'kind',
107
- 'required',
108
- 'values'
109
- ] : value.kind === 'reference' ? [
110
- 'kind',
111
- 'required',
112
- 'to'
113
- ] : [
114
- 'kind',
115
- 'required'
116
- ];
117
- if (extraKeys(value, allowed)) return refuse(file, 'definition-field', location);
118
- return parseScalar(file, location, value, required);
69
+ if (required === undefined)
70
+ return refuse('definition-field', location);
71
+ if (value.kind === 'list')
72
+ return parseList(names, location, value, required, 'definition-field');
73
+ const allowed = value.kind === 'enum'
74
+ ? ['kind', 'required', 'values']
75
+ : value.kind === 'reference'
76
+ ? ['kind', 'required', 'to']
77
+ : ['kind', 'required'];
78
+ if (extraKeys(value, allowed))
79
+ return refuse('definition-field', location);
80
+ return parseScalar(names, location, value, required);
119
81
  }
120
- function parseSection(file, location, value) {
121
- if (!isRecord(value) || value.kind !== 'text' && value.kind !== 'list') {
122
- return refuse(file, 'definition-section-kind', location);
82
+ function parseSection(names, location, value) {
83
+ if (!isRecord(value) || (value.kind !== 'text' && value.kind !== 'list')) {
84
+ return refuse('definition-section-kind', location);
123
85
  }
124
86
  const required = requiredFlag(value.required);
125
- if (required === undefined) return refuse(file, 'definition-section', location);
126
- if (value.kind === 'list') return parseList(file, location, value, required, 'definition-section');
127
- if (extraKeys(value, [
128
- 'kind',
129
- 'required'
130
- ])) return refuse(file, 'definition-section', location);
131
- return {
132
- kind: 'text',
133
- required
134
- };
87
+ if (required === undefined)
88
+ return refuse('definition-section', location);
89
+ if (value.kind === 'list')
90
+ return parseList(names, location, value, required, 'definition-section');
91
+ if (extraKeys(value, ['kind', 'required']))
92
+ return refuse('definition-section', location);
93
+ return { kind: 'text', required };
135
94
  }
136
- export function readDefinition(file, document) {
137
- if (document.type !== 'definition') return refuse(file, 'definition-type');
138
- const name = typeNameFromPath(file);
139
- if (name === '') return refuse(file, 'definition-type');
140
- for (const key of Object.keys(document.fields)){
141
- if (key !== 'type' && key !== 'fields' && key !== 'sections') {
142
- return refuse(file, 'definition-shape', key);
95
+ function readType(names, name, value) {
96
+ const location = `types.${name}`;
97
+ if (!isRecord(value))
98
+ return refuse('definition-shape', location);
99
+ for (const key of Object.keys(value)) {
100
+ if (key !== 'fields' && key !== 'sections' && key !== 'member_document') {
101
+ return refuse('definition-shape', `${location}.${key}`);
143
102
  }
144
103
  }
145
- const fieldsValue = document.fields.fields;
146
- const sectionsValue = document.fields.sections;
147
- if (fieldsValue !== undefined && !isRecord(fieldsValue)) return refuse(file, 'definition-fields', 'fields');
104
+ const mark = value.member_document === undefined ? false : value.member_document;
105
+ if (typeof mark !== 'boolean')
106
+ return refuse('definition-shape', `${location}.member_document`);
107
+ const fieldsValue = value.fields;
108
+ const sectionsValue = value.sections;
109
+ if (fieldsValue !== undefined && !isRecord(fieldsValue))
110
+ return refuse('definition-fields', `${location}.fields`);
148
111
  if (sectionsValue !== undefined && !isRecord(sectionsValue)) {
149
- return refuse(file, 'definition-sections', 'sections');
112
+ return refuse('definition-sections', `${location}.sections`);
150
113
  }
151
114
  const fields = Object.create(null);
152
- for (const [fieldName, spec] of Object.entries(fieldsValue ?? {})){
153
- const parsed = parseField(file, fieldName, spec);
154
- if ('rule' in parsed) return parsed;
115
+ for (const [fieldName, spec] of Object.entries(fieldsValue ?? {})) {
116
+ const parsed = parseField(names, `${location}.fields.${fieldName}`, spec);
117
+ if ('rule' in parsed)
118
+ return parsed;
155
119
  fields[fieldName] = parsed;
156
120
  }
157
121
  const sections = Object.create(null);
158
- for (const [sectionName, spec] of Object.entries(sectionsValue ?? {})){
159
- const parsed = parseSection(file, sectionName, spec);
160
- if ('rule' in parsed) return parsed;
122
+ for (const [sectionName, spec] of Object.entries(sectionsValue ?? {})) {
123
+ const parsed = parseSection(names, `${location}.sections.${sectionName}`, spec);
124
+ if ('rule' in parsed)
125
+ return parsed;
161
126
  sections[sectionName] = parsed;
162
127
  }
163
- return {
164
- name,
165
- file,
166
- fields,
167
- sections
168
- };
128
+ return { name, memberDocument: mark, fields, sections };
129
+ }
130
+ function freezeSpec(spec) {
131
+ if (spec.kind === 'list')
132
+ freezeSpec(spec.of);
133
+ if (spec.kind === 'enum')
134
+ Object.freeze(spec.values);
135
+ Object.freeze(spec);
136
+ }
137
+ function lineAt(text, offset) {
138
+ return text.slice(0, offset).split(/\r\n|\r|\n/).length;
139
+ }
140
+ export function readSchema(text) {
141
+ let root;
142
+ try {
143
+ root = jsValue(parseYamlMapping(text, 0, text.length));
144
+ }
145
+ catch (error) {
146
+ if (error instanceof YamlError)
147
+ return refuse('schema-yaml', `line ${lineAt(text, error.offset)}`);
148
+ throw error;
149
+ }
150
+ const schema = root;
151
+ for (const key of Object.keys(schema)) {
152
+ if (key !== 'types')
153
+ return refuse('schema-shape', key);
154
+ }
155
+ if (!isRecord(schema.types))
156
+ return refuse('schema-shape', 'types');
157
+ const names = new Set(Object.keys(schema.types));
158
+ if (names.has(''))
159
+ return refuse('schema-shape', 'types');
160
+ const types = Object.create(null);
161
+ let marked = false;
162
+ for (const [name, value] of Object.entries(schema.types)) {
163
+ const definition = readType(names, name, value);
164
+ if ('rule' in definition)
165
+ return definition;
166
+ if (definition.memberDocument) {
167
+ if (marked)
168
+ return refuse('schema-member-document', `types.${name}.member_document`);
169
+ marked = true;
170
+ }
171
+ for (const spec of Object.values(definition.fields))
172
+ freezeSpec(spec);
173
+ for (const spec of Object.values(definition.sections))
174
+ freezeSpec(spec);
175
+ Object.freeze(definition.fields);
176
+ Object.freeze(definition.sections);
177
+ types[name] = Object.freeze(definition);
178
+ }
179
+ return Object.freeze({ types: Object.freeze(types) });
169
180
  }
170
-
171
- //# sourceMappingURL=definition.js.map
@@ -0,0 +1,3 @@
1
+ import type { Division, DivisionContext, Document } from './types.js';
2
+ export declare function divide(document: Document, file: string, context: DivisionContext): Division;
3
+ //# sourceMappingURL=divide.d.ts.map
@@ -0,0 +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"}
package/dist/divide.js ADDED
@@ -0,0 +1,310 @@
1
+ import { blockRanges, headingLines } from './blocks.js';
2
+ import { projectionInput, rangeText } from './project.js';
3
+ import { refusal } from './refuse.js';
4
+ const SMALLEST_BUDGET = 2;
5
+ function node(draft) {
6
+ return {
7
+ start: draft.start,
8
+ end: draft.end,
9
+ bodyStart: draft.bodyStart,
10
+ heading: draft.heading,
11
+ children: draft.children.map(node),
12
+ };
13
+ }
14
+ function forest(state, range) {
15
+ const content = state.content;
16
+ const headings = headingLines(content, range.start, range.end);
17
+ const roots = [];
18
+ const open = [];
19
+ const first = headings[0]?.start ?? range.end;
20
+ if (first > range.start) {
21
+ roots.push({
22
+ level: 0,
23
+ start: range.start,
24
+ end: first,
25
+ bodyStart: range.start,
26
+ heading: '',
27
+ children: [],
28
+ });
29
+ }
30
+ for (const heading of headings) {
31
+ while ((open[open.length - 1]?.level ?? 0) >= heading.level) {
32
+ open.pop().end = heading.start;
33
+ }
34
+ const draft = {
35
+ level: heading.level,
36
+ start: heading.start,
37
+ end: range.end,
38
+ bodyStart: heading.next,
39
+ heading: `${textOf(state, { start: heading.start, end: heading.textEnd })}\n\n`,
40
+ children: [],
41
+ };
42
+ (open[open.length - 1]?.children ?? roots).push(draft);
43
+ open.push(draft);
44
+ }
45
+ return roots.map(node);
46
+ }
47
+ function isSpace(character) {
48
+ return character === ' ' || character === '\t' || character === '\n' || character === '\r';
49
+ }
50
+ const TERMINATORS = new Set(['.', '!', '?', '…', '。', '!', '?']);
51
+ function isTerminator(character) {
52
+ return TERMINATORS.has(character);
53
+ }
54
+ const CLOSERS = new Set(['"', "'", ')', ']', '»', '”']);
55
+ function isCloser(character) {
56
+ return CLOSERS.has(character);
57
+ }
58
+ function sentenceBounds(text) {
59
+ const bounds = [0];
60
+ let i = 0;
61
+ while (i < text.length) {
62
+ if (!isTerminator(text[i])) {
63
+ i += 1;
64
+ continue;
65
+ }
66
+ let after = i + 1;
67
+ while (after < text.length && isCloser(text[after]))
68
+ after += 1;
69
+ if (after >= text.length || !isSpace(text[after])) {
70
+ i = after + 1;
71
+ continue;
72
+ }
73
+ while (after < text.length && isSpace(text[after]))
74
+ after += 1;
75
+ if (after < text.length)
76
+ bounds.push(after);
77
+ i = after;
78
+ }
79
+ bounds.push(text.length);
80
+ return bounds;
81
+ }
82
+ function isTrailingSurrogate(text, index) {
83
+ const code = text.charCodeAt(index);
84
+ return code >= 0xdc00 && code <= 0xdfff;
85
+ }
86
+ function characterLength(text, index) {
87
+ return isTrailingSurrogate(text, index + 1) ? 2 : 1;
88
+ }
89
+ function boundOf(cutting, from, to, budget) {
90
+ const limit = from + budget;
91
+ if (limit >= to)
92
+ return to;
93
+ for (let index = limit; index > from + 1; index -= 1) {
94
+ if (isSpace(cutting.text[index]))
95
+ return index;
96
+ }
97
+ const inside = cutting.masks.find((mask) => limit > mask.start && limit < mask.end);
98
+ if (inside !== undefined)
99
+ return inside.start > from ? inside.start : Math.min(inside.end, to);
100
+ return isTrailingSurrogate(cutting.text, limit) ? limit - 1 : limit;
101
+ }
102
+ function utf8Size(code) {
103
+ if (code < 0x80)
104
+ return 1;
105
+ if (code < 0x800)
106
+ return 2;
107
+ if (code < 0x10000)
108
+ return 3;
109
+ return 4;
110
+ }
111
+ function byteBounds(content, spans) {
112
+ const marks = [...new Set(spans.flatMap((span) => [span.start, span.end]))].sort((left, right) => left - right);
113
+ const bytes = new Map();
114
+ let index = 0;
115
+ let count = 0;
116
+ for (const mark of marks) {
117
+ while (index < mark) {
118
+ const code = content.codePointAt(index);
119
+ count += utf8Size(code);
120
+ index += code > 0xffff ? 2 : 1;
121
+ }
122
+ bytes.set(mark, count);
123
+ }
124
+ return spans.map((span) => ({
125
+ ...span,
126
+ start: bytes.get(span.start),
127
+ end: bytes.get(span.end),
128
+ }));
129
+ }
130
+ function textOf(state, extent) {
131
+ return rangeText(state.content, extent, state.edits);
132
+ }
133
+ function sourceCutting(state, extent) {
134
+ let text = state.content.slice(extent.start, extent.end);
135
+ const masks = [];
136
+ for (const edit of state.edits) {
137
+ if (edit.start < extent.start || edit.end > extent.end)
138
+ 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 });
143
+ }
144
+ return {
145
+ text,
146
+ masks,
147
+ piece: (from, to) => {
148
+ const cut = { start: extent.start + from, end: extent.start + to };
149
+ return { ...cut, text: textOf(state, cut) };
150
+ },
151
+ };
152
+ }
153
+ function valueCutting(value) {
154
+ return {
155
+ text: value.text,
156
+ masks: [],
157
+ piece: (from, to) => ({ start: value.start, end: value.end, text: value.text.slice(from, to) }),
158
+ };
159
+ }
160
+ function prefixOf(state, body) {
161
+ if (body.emitted === 0 || body.heading.length >= state.budget)
162
+ return '';
163
+ return body.heading;
164
+ }
165
+ function available(state, body) {
166
+ return state.budget - prefixOf(state, body).length;
167
+ }
168
+ function emit(state, body, piece, bare = false) {
169
+ if (piece.text.trim() === '')
170
+ return;
171
+ const text = (bare ? '' : prefixOf(state, body)) + piece.text;
172
+ state.spans.push({ start: piece.start, end: piece.end, text });
173
+ body.emitted += 1;
174
+ }
175
+ function merge(run) {
176
+ return {
177
+ start: Math.min(...run.map((unit) => unit.start)),
178
+ end: Math.max(...run.map((unit) => unit.end)),
179
+ text: run.map((unit) => unit.text).join(''),
180
+ };
181
+ }
182
+ function divideUnits(state, body, units) {
183
+ let run = [];
184
+ let length = 0;
185
+ const flush = () => {
186
+ if (run.length === 0)
187
+ return;
188
+ emit(state, body, merge(run));
189
+ run = [];
190
+ length = 0;
191
+ };
192
+ for (const unit of units) {
193
+ if (run.length > 0 && length + unit.text.length > available(state, body))
194
+ flush();
195
+ if (unit.text.length > available(state, body)) {
196
+ flush();
197
+ unit.descend();
198
+ continue;
199
+ }
200
+ run.push(unit);
201
+ length += unit.text.length;
202
+ }
203
+ flush();
204
+ }
205
+ function divideBound(state, body, cutting, range) {
206
+ let start = range.start;
207
+ while (start < range.end) {
208
+ const bare = available(state, body) < characterLength(cutting.text, start);
209
+ const room = bare ? state.budget : available(state, body);
210
+ const stop = boundOf(cutting, start, range.end, room);
211
+ const piece = cutting.piece(start, stop);
212
+ if (cutting.masks.length === 0 || piece.text.length <= room) {
213
+ emit(state, body, piece, bare);
214
+ }
215
+ else {
216
+ divideBound(state, body, valueCutting(piece), { start: 0, end: piece.text.length });
217
+ }
218
+ start = stop;
219
+ }
220
+ }
221
+ function divideSentences(state, body, cutting) {
222
+ const cut = cutting.piece;
223
+ const bounds = sentenceBounds(cutting.text);
224
+ let index = 0;
225
+ while (index + 1 < bounds.length) {
226
+ const alone = { start: bounds[index], end: bounds[index + 1] };
227
+ if (cut(alone.start, alone.end).text.length > available(state, body)) {
228
+ divideBound(state, body, cutting, alone);
229
+ index += 1;
230
+ continue;
231
+ }
232
+ const carried = bounds[Math.max(index - 1, 0)];
233
+ const from = cut(carried, alone.end).text.length <= available(state, body) ? carried : alone.start;
234
+ let last = index;
235
+ while (last + 2 < bounds.length &&
236
+ cut(from, bounds[last + 2]).text.length <= available(state, body)) {
237
+ last += 1;
238
+ }
239
+ emit(state, body, cut(from, bounds[last + 1]));
240
+ index = last + 1;
241
+ }
242
+ }
243
+ function blockUnit(state, body, block) {
244
+ return {
245
+ start: block.start,
246
+ end: block.end,
247
+ text: textOf(state, block),
248
+ descend: () => divideSentences(state, body, sourceCutting(state, block)),
249
+ };
250
+ }
251
+ function valueUnit(state, body, value) {
252
+ return {
253
+ start: value.start,
254
+ end: value.end,
255
+ text: value.text,
256
+ descend: () => divideSentences(state, body, valueCutting(value)),
257
+ };
258
+ }
259
+ function nodeUnit(state, subject) {
260
+ return {
261
+ start: subject.start,
262
+ end: subject.end,
263
+ text: textOf(state, subject),
264
+ descend: () => divideNode(state, subject),
265
+ };
266
+ }
267
+ function ownBlocks(subject, end, blocks) {
268
+ const first = blocks[0];
269
+ return first === undefined
270
+ ? [{ start: subject.start, end }]
271
+ : [{ start: subject.start, end: first.end }, ...blocks.slice(1)];
272
+ }
273
+ function divideNode(state, subject) {
274
+ const end = subject.children[0]?.start ?? subject.end;
275
+ const blocks = blockRanges(state.content, subject.bodyStart, end);
276
+ const children = { heading: '', emitted: 0 };
277
+ if (blocks.length === 0 && subject.children.length > 0) {
278
+ const [first, ...rest] = subject.children;
279
+ const led = [{ ...first, start: subject.start }, ...rest];
280
+ divideUnits(state, children, led.map((child) => nodeUnit(state, child)));
281
+ return;
282
+ }
283
+ const body = { heading: subject.heading, emitted: 0 };
284
+ const own = ownBlocks(subject, end, blocks);
285
+ divideUnits(state, body, own.map((block) => blockUnit(state, body, block)));
286
+ divideUnits(state, children, subject.children.map((child) => nodeUnit(state, child)));
287
+ }
288
+ function divideInput(state, input) {
289
+ const body = { heading: '', emitted: 0 };
290
+ divideUnits(state, body, [
291
+ ...input.values.map((value) => valueUnit(state, body, value)),
292
+ ...input.ranges.flatMap((range) => forest(state, range).map((subject) => nodeUnit(state, subject))),
293
+ ]);
294
+ }
295
+ export function divide(document, file, context) {
296
+ if (!Number.isInteger(context.budget) || context.budget < SMALLEST_BUDGET) {
297
+ return { ok: false, refusal: refusal(file, 'division-budget') };
298
+ }
299
+ const result = projectionInput(document, file, context);
300
+ if (!result.ok)
301
+ return { ok: false, refusal: result.refusal };
302
+ const state = {
303
+ content: document.content,
304
+ edits: result.input.edits,
305
+ budget: context.budget,
306
+ spans: [],
307
+ };
308
+ divideInput(state, result.input);
309
+ return { ok: true, spans: byteBounds(document.content, state.spans) };
310
+ }
@@ -1,6 +1,8 @@
1
1
  import type { ApplyResult, Change, Document, Link, ParseResult } from './types.js';
2
+ import { type YamlMap } from './yaml.js';
2
3
  export declare function parse(content: string, file?: string): ParseResult;
3
4
  export declare function links(document: Document, file: string): readonly Link[];
4
5
  export declare function apply(document: Document, change: Change): ApplyResult;
5
6
  export declare function serialize(document: Document): string;
7
+ export declare function frontmatter(document: Document): YamlMap | null;
6
8
  //# 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;AAsDnF,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,WAAW,CAkD7D;AAyGD,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"}
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"}