@agentshouse/mdmodel 0.1.0-alpha.8 → 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 (205) hide show
  1. package/API.md +298 -0
  2. package/README.md +29 -172
  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 +15 -9
  7. package/dist/definition.d.ts.map +1 -1
  8. package/dist/definition.js +148 -133
  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 +83 -73
  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 +45 -67
  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 -122
  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 +196 -187
  51. package/fixtures/README.md +77 -52
  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/context.json +1 -0
  84. package/fixtures/cases/missing-section-item-kind/expected.json +5 -0
  85. package/fixtures/cases/missing-section-item-kind/schema.yaml +6 -0
  86. package/fixtures/cases/paragraph-link-definition/schema.yaml +2 -0
  87. package/fixtures/cases/prototype-field/context.json +1 -0
  88. package/fixtures/cases/prototype-field/expected.json +6 -0
  89. package/fixtures/cases/prototype-field/library/item.md +9 -0
  90. package/fixtures/cases/prototype-field/schema.yaml +6 -0
  91. package/fixtures/cases/quoted-link-definition/expected.json +1 -2
  92. package/fixtures/cases/quoted-link-definition/schema.yaml +2 -0
  93. package/fixtures/cases/referenced-missing-file/expected.json +0 -1
  94. package/fixtures/cases/referenced-missing-file/schema.yaml +10 -0
  95. package/fixtures/cases/second-member-document/context.json +1 -0
  96. package/fixtures/cases/second-member-document/expected.json +5 -0
  97. package/fixtures/cases/second-member-document/schema.yaml +5 -0
  98. package/fixtures/cases/section-item-enum/context.json +1 -0
  99. package/fixtures/cases/section-item-enum/expected.json +6 -0
  100. package/fixtures/cases/section-item-enum/library/task.md +8 -0
  101. package/fixtures/cases/section-item-enum/schema.yaml +4 -0
  102. package/fixtures/cases/section-item-kind/context.json +1 -0
  103. package/fixtures/cases/section-item-kind/expected.json +6 -0
  104. package/fixtures/cases/section-item-kind/library/task.md +8 -0
  105. package/fixtures/cases/section-item-kind/schema.yaml +4 -0
  106. package/fixtures/cases/section-items/context.json +1 -0
  107. package/fixtures/cases/section-items/expected.json +1 -0
  108. package/fixtures/cases/section-items/library/other.md +3 -0
  109. package/fixtures/cases/section-items/library/page.md +28 -0
  110. package/fixtures/cases/section-items/schema.yaml +8 -0
  111. package/fixtures/cases/section-reference-path/context.json +1 -0
  112. package/fixtures/cases/section-reference-path/expected.json +6 -0
  113. package/fixtures/cases/section-reference-path/library/other.md +3 -0
  114. package/fixtures/cases/section-reference-path/library/page.md +7 -0
  115. package/fixtures/cases/section-reference-path/schema.yaml +4 -0
  116. package/fixtures/cases/section-reference-type/context.json +1 -0
  117. package/fixtures/cases/section-reference-type/expected.json +6 -0
  118. package/fixtures/cases/section-reference-type/library/note.md +1 -0
  119. package/fixtures/cases/section-reference-type/library/page.md +7 -0
  120. package/fixtures/cases/section-reference-type/schema.yaml +4 -0
  121. package/fixtures/cases/shortcut-reference-link/context.json +1 -0
  122. package/fixtures/cases/shortcut-reference-link/expected.json +5 -0
  123. package/fixtures/cases/shortcut-reference-link/library/item.md +10 -0
  124. package/fixtures/cases/shortcut-reference-link/schema.yaml +6 -0
  125. package/fixtures/cases/structured-section/expected.json +1 -2
  126. package/fixtures/cases/structured-section/schema.yaml +7 -0
  127. package/fixtures/cases/submission-keys/context.json +1 -0
  128. package/fixtures/cases/submission-keys/expected.json +1 -0
  129. package/fixtures/cases/submission-keys/library/notes/visitor.md +8 -0
  130. package/fixtures/cases/submission-keys/schema.yaml +4 -0
  131. package/fixtures/cases/text-field-kind/context.json +1 -0
  132. package/fixtures/cases/text-field-kind/expected.json +6 -0
  133. package/fixtures/cases/text-field-kind/library/page.md +4 -0
  134. package/fixtures/cases/text-field-kind/schema.yaml +4 -0
  135. package/fixtures/cases/truncated-link-definition/expected.json +1 -2
  136. package/fixtures/cases/truncated-link-definition/schema.yaml +2 -0
  137. package/fixtures/cases/types-folder-content/context.json +1 -0
  138. package/fixtures/cases/types-folder-content/expected.json +1 -0
  139. package/fixtures/cases/types-folder-content/library/types/task.md +4 -0
  140. package/fixtures/cases/types-folder-content/schema.yaml +4 -0
  141. package/fixtures/cases/unclosed-frontmatter/expected.json +1 -2
  142. package/fixtures/cases/undeclared-field/context.json +1 -0
  143. package/fixtures/cases/undeclared-field/expected.json +6 -0
  144. package/fixtures/cases/undeclared-field/library/item.md +9 -0
  145. package/fixtures/cases/undeclared-field/schema.yaml +6 -0
  146. package/fixtures/cases/unknown-type/context.json +1 -0
  147. package/fixtures/cases/unknown-type/expected.json +6 -0
  148. package/fixtures/cases/unknown-type/library/item.md +3 -0
  149. package/fixtures/cases/unknown-type/schema.yaml +4 -0
  150. package/fixtures/cases/unlisted-reference-type/context.json +1 -0
  151. package/fixtures/cases/unlisted-reference-type/expected.json +5 -0
  152. package/fixtures/cases/unlisted-reference-type/schema.yaml +4 -0
  153. package/fixtures/cases/unresolved-link/expected.json +1 -2
  154. package/fixtures/cases/unresolved-link/schema.yaml +6 -0
  155. package/fixtures/cases/valid-typed-document/library/tasks/one.md +1 -0
  156. package/fixtures/cases/valid-typed-document/schema.yaml +15 -0
  157. package/fixtures/cases/wide-item-fence-link/schema.yaml +2 -0
  158. package/fixtures/division.json +409 -0
  159. package/fixtures/projection.json +77 -28
  160. package/package.json +3 -12
  161. package/dist/definition.js.map +0 -1
  162. package/dist/document.js.map +0 -1
  163. package/dist/index.js.map +0 -1
  164. package/dist/links.js.map +0 -1
  165. package/dist/paths.js.map +0 -1
  166. package/dist/profile.js.map +0 -1
  167. package/dist/project.js.map +0 -1
  168. package/dist/refuse.js.map +0 -1
  169. package/dist/schema.js.map +0 -1
  170. package/dist/sections.js.map +0 -1
  171. package/dist/types.js.map +0 -1
  172. package/dist/validate.js.map +0 -1
  173. package/dist/version.js.map +0 -1
  174. package/dist/yaml.js.map +0 -1
  175. package/fixtures/cases/binary-any-reference/library/types/note.md +0 -5
  176. package/fixtures/cases/binary-document-collision/library/types/note.md +0 -3
  177. package/fixtures/cases/binary-link-outside-collection/library/types/note.md +0 -3
  178. package/fixtures/cases/binary-prototype-reference/library/types/note.md +0 -5
  179. package/fixtures/cases/binary-typed-reference/library/types/note.md +0 -5
  180. package/fixtures/cases/binary-typed-reference/library/types/person.md +0 -3
  181. package/fixtures/cases/bracketed-link-definition/library/types/task.md +0 -7
  182. package/fixtures/cases/declared-binary-links/library/types/note.md +0 -3
  183. package/fixtures/cases/duplicate-link-definition/library/types/task.md +0 -7
  184. package/fixtures/cases/fenced-link-definition/library/types/task.md +0 -7
  185. package/fixtures/cases/field-enum/library/types/task.md +0 -8
  186. package/fixtures/cases/interrupted-link-definition/library/types/note.md +0 -3
  187. package/fixtures/cases/long-fence-link-definition/library/types/note.md +0 -3
  188. package/fixtures/cases/malformed-definition/library/types/task.md +0 -5
  189. package/fixtures/cases/missing-binary-image/library/types/note.md +0 -3
  190. package/fixtures/cases/missing-binary-link/library/types/note.md +0 -3
  191. package/fixtures/cases/missing-required-field/library/types/task.md +0 -8
  192. package/fixtures/cases/paragraph-link-definition/library/types/note.md +0 -3
  193. package/fixtures/cases/prd-definition/library/types/task.md +0 -15
  194. package/fixtures/cases/quoted-link-definition/library/types/note.md +0 -3
  195. package/fixtures/cases/referenced-missing-file/library/types/person.md +0 -5
  196. package/fixtures/cases/referenced-missing-file/library/types/task.md +0 -8
  197. package/fixtures/cases/structured-section/library/types/task.md +0 -8
  198. package/fixtures/cases/truncated-link-definition/library/types/note.md +0 -3
  199. package/fixtures/cases/unresolved-link/library/types/task.md +0 -7
  200. package/fixtures/cases/valid-typed-document/library/types/person.md +0 -5
  201. package/fixtures/cases/valid-typed-document/library/types/task.md +0 -12
  202. package/fixtures/cases/wide-item-fence-link/library/types/note.md +0 -3
  203. package/markdown-syntax-profile.md +0 -9
  204. /package/fixtures/cases/{prd-definition → frontmatter-schema}/context.json +0 -0
  205. /package/fixtures/cases/{prd-definition → member-document}/expected.json +0 -0
@@ -1,165 +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
- 'string',
23
- 'number',
24
- 'date',
25
- 'enum',
26
- 'reference'
27
- ]);
28
- 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) {
29
24
  const kind = spec.kind;
30
- if (kind === 'string') return {
31
- kind: 'string',
32
- required
33
- };
34
- if (kind === 'number') return {
35
- kind: 'number',
36
- required
37
- };
38
- if (kind === 'date') return {
39
- kind: 'date',
40
- required
41
- };
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 };
42
33
  if (kind === 'enum') {
43
34
  const values = stringList(spec.values);
44
- if (values === undefined) return refuse(file, 'definition-enum-values', location);
45
- return {
46
- kind: 'enum',
47
- required,
48
- values
49
- };
35
+ if (values === undefined)
36
+ return refuse('definition-enum-values', location);
37
+ return { kind: 'enum', required, values };
50
38
  }
51
39
  if (kind === 'reference') {
52
- if (typeof spec.to !== 'string' || spec.to === '') return refuse(file, 'definition-reference-to', location);
53
- return {
54
- kind: 'reference',
55
- required,
56
- to: spec.to
57
- };
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 };
58
43
  }
59
- return refuse(file, 'definition-field-kind', location);
44
+ return refuse('definition-field-kind', location);
60
45
  }
61
46
  function extraKeys(spec, allowed) {
62
- return Object.keys(spec).some((key)=>!allowed.includes(key));
47
+ return Object.keys(spec).some((key) => !allowed.includes(key));
63
48
  }
64
- function parseField(file, location, value) {
65
- if (!isRecord(value) || typeof value.kind !== 'string') return refuse(file, 'definition-field', location);
66
- const required = requiredFlag(value.required);
67
- if (required === undefined) return refuse(file, 'definition-field', location);
68
- if (value.kind === 'list') {
69
- if (typeof value.of !== 'string' || !SCALAR_KINDS.has(value.of)) {
70
- return refuse(file, 'definition-list-of', location);
71
- }
72
- const allowed = value.of === 'enum' ? [
73
- 'kind',
74
- 'required',
75
- 'of',
76
- 'values'
77
- ] : value.of === 'reference' ? [
78
- 'kind',
79
- 'required',
80
- 'of',
81
- 'to'
82
- ] : [
83
- 'kind',
84
- 'required',
85
- 'of'
86
- ];
87
- if (extraKeys(value, allowed)) return refuse(file, 'definition-field', location);
88
- const inner = parseScalar(file, location, {
89
- ...value,
90
- kind: value.of
91
- }, false);
92
- if ('rule' in inner) return inner;
93
- return {
94
- kind: 'list',
95
- required,
96
- of: inner
97
- };
49
+ function parseList(names, location, spec, required, malformed) {
50
+ if (typeof spec.of !== 'string' || !SCALAR_KINDS.has(spec.of)) {
51
+ return refuse('definition-list-of', location);
98
52
  }
99
- const allowed = value.kind === 'enum' ? [
100
- 'kind',
101
- 'required',
102
- 'values'
103
- ] : value.kind === 'reference' ? [
104
- 'kind',
105
- 'required',
106
- 'to'
107
- ] : [
108
- 'kind',
109
- 'required'
110
- ];
111
- if (extraKeys(value, allowed)) return refuse(file, 'definition-field', location);
112
- return parseScalar(file, location, value, required);
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 };
113
64
  }
114
- function parseSection(file, location, value) {
115
- if (!isRecord(value) || value.kind !== 'text' && value.kind !== 'list') {
116
- return refuse(file, 'definition-section-kind', location);
117
- }
65
+ function parseField(names, location, value) {
66
+ if (!isRecord(value) || typeof value.kind !== 'string')
67
+ return refuse('definition-field', location);
118
68
  const required = requiredFlag(value.required);
119
- if (required === undefined || extraKeys(value, [
120
- 'kind',
121
- 'required'
122
- ])) {
123
- return refuse(file, 'definition-section', location);
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);
81
+ }
82
+ function parseSection(names, location, value) {
83
+ if (!isRecord(value) || (value.kind !== 'text' && value.kind !== 'list')) {
84
+ return refuse('definition-section-kind', location);
124
85
  }
125
- return {
126
- kind: value.kind,
127
- required
128
- };
86
+ const required = requiredFlag(value.required);
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 };
129
94
  }
130
- export function readDefinition(file, document) {
131
- if (document.type !== 'definition') return refuse(file, 'definition-type');
132
- const name = typeNameFromPath(file);
133
- if (name === '') return refuse(file, 'definition-type');
134
- for (const key of Object.keys(document.fields)){
135
- if (key !== 'type' && key !== 'fields' && key !== 'sections') {
136
- 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}`);
137
102
  }
138
103
  }
139
- const fieldsValue = document.fields.fields;
140
- const sectionsValue = document.fields.sections;
141
- 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`);
142
111
  if (sectionsValue !== undefined && !isRecord(sectionsValue)) {
143
- return refuse(file, 'definition-sections', 'sections');
112
+ return refuse('definition-sections', `${location}.sections`);
144
113
  }
145
- const fields = {};
146
- for (const [fieldName, spec] of Object.entries(fieldsValue ?? {})){
147
- const parsed = parseField(file, fieldName, spec);
148
- if ('rule' in parsed) return parsed;
114
+ const fields = Object.create(null);
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;
149
119
  fields[fieldName] = parsed;
150
120
  }
151
- const sections = {};
152
- for (const [sectionName, spec] of Object.entries(sectionsValue ?? {})){
153
- const parsed = parseSection(file, sectionName, spec);
154
- if ('rule' in parsed) return parsed;
121
+ const sections = Object.create(null);
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;
155
126
  sections[sectionName] = parsed;
156
127
  }
157
- return {
158
- name,
159
- file,
160
- fields,
161
- sections
162
- };
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) });
163
180
  }
164
-
165
- //# 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"}