@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.
- package/API.md +298 -0
- package/README.md +29 -172
- package/dist/blocks.d.ts +11 -0
- package/dist/blocks.d.ts.map +1 -0
- package/dist/blocks.js +62 -0
- package/dist/definition.d.ts +15 -9
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js +148 -133
- package/dist/divide.d.ts +3 -0
- package/dist/divide.d.ts.map +1 -0
- package/dist/divide.js +310 -0
- package/dist/document.d.ts +2 -0
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +89 -120
- package/dist/fields.d.ts +4 -0
- package/dist/fields.d.ts.map +1 -0
- package/dist/fields.js +3 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/links.d.ts +1 -0
- package/dist/links.d.ts.map +1 -1
- package/dist/links.js +618 -224
- package/dist/paths.d.ts +2 -3
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +27 -37
- package/dist/profile.js +1 -3
- package/dist/project.d.ts +19 -1
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +83 -73
- package/dist/refuse.d.ts.map +1 -1
- package/dist/refuse.js +2 -10
- package/dist/schema.d.ts +2 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +22 -33
- package/dist/sections.d.ts +2 -1
- package/dist/sections.d.ts.map +1 -1
- package/dist/sections.js +45 -67
- package/dist/types.d.ts +30 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -3
- package/dist/validate.d.ts +3 -2
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +145 -122
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -3
- package/dist/yaml.d.ts +1 -0
- package/dist/yaml.d.ts.map +1 -1
- package/dist/yaml.js +196 -187
- package/fixtures/README.md +77 -52
- package/fixtures/cases/binary-any-reference/expected.json +0 -1
- package/fixtures/cases/binary-any-reference/schema.yaml +4 -0
- package/fixtures/cases/binary-document-collision/expected.json +1 -2
- package/fixtures/cases/binary-document-collision/schema.yaml +2 -0
- package/fixtures/cases/binary-link-outside-collection/expected.json +1 -2
- package/fixtures/cases/binary-link-outside-collection/schema.yaml +2 -0
- package/fixtures/cases/binary-prototype-reference/expected.json +0 -1
- package/fixtures/cases/binary-prototype-reference/schema.yaml +4 -0
- package/fixtures/cases/binary-typed-reference/expected.json +0 -1
- package/fixtures/cases/binary-typed-reference/schema.yaml +5 -0
- package/fixtures/cases/bracketed-link-definition/schema.yaml +6 -0
- package/fixtures/cases/declared-binary-links/schema.yaml +2 -0
- package/fixtures/cases/duplicate-link-definition/schema.yaml +6 -0
- package/fixtures/cases/fenced-link-definition/schema.yaml +6 -0
- package/fixtures/cases/field-enum/expected.json +1 -2
- package/fixtures/cases/field-enum/schema.yaml +7 -0
- package/fixtures/cases/frontmatter-schema/expected.json +5 -0
- package/fixtures/cases/frontmatter-schema/schema.yaml +6 -0
- package/fixtures/cases/interrupted-link-definition/schema.yaml +2 -0
- package/fixtures/cases/long-fence-link-definition/schema.yaml +2 -0
- package/fixtures/cases/malformed-definition/expected.json +2 -4
- package/fixtures/cases/malformed-definition/schema.yaml +4 -0
- package/fixtures/cases/member-document/context.json +1 -0
- package/fixtures/cases/member-document/library/people/ana.md +5 -0
- package/fixtures/cases/member-document/schema.yaml +5 -0
- package/fixtures/cases/missing-binary-image/expected.json +1 -2
- package/fixtures/cases/missing-binary-image/schema.yaml +2 -0
- package/fixtures/cases/missing-binary-link/expected.json +1 -2
- package/fixtures/cases/missing-binary-link/schema.yaml +2 -0
- package/fixtures/cases/missing-required-field/expected.json +1 -2
- package/fixtures/cases/missing-required-field/schema.yaml +7 -0
- package/fixtures/cases/missing-section-item-kind/context.json +1 -0
- package/fixtures/cases/missing-section-item-kind/expected.json +5 -0
- package/fixtures/cases/missing-section-item-kind/schema.yaml +6 -0
- package/fixtures/cases/paragraph-link-definition/schema.yaml +2 -0
- package/fixtures/cases/prototype-field/context.json +1 -0
- package/fixtures/cases/prototype-field/expected.json +6 -0
- package/fixtures/cases/prototype-field/library/item.md +9 -0
- package/fixtures/cases/prototype-field/schema.yaml +6 -0
- package/fixtures/cases/quoted-link-definition/expected.json +1 -2
- package/fixtures/cases/quoted-link-definition/schema.yaml +2 -0
- package/fixtures/cases/referenced-missing-file/expected.json +0 -1
- package/fixtures/cases/referenced-missing-file/schema.yaml +10 -0
- package/fixtures/cases/second-member-document/context.json +1 -0
- package/fixtures/cases/second-member-document/expected.json +5 -0
- package/fixtures/cases/second-member-document/schema.yaml +5 -0
- package/fixtures/cases/section-item-enum/context.json +1 -0
- package/fixtures/cases/section-item-enum/expected.json +6 -0
- package/fixtures/cases/section-item-enum/library/task.md +8 -0
- package/fixtures/cases/section-item-enum/schema.yaml +4 -0
- package/fixtures/cases/section-item-kind/context.json +1 -0
- package/fixtures/cases/section-item-kind/expected.json +6 -0
- package/fixtures/cases/section-item-kind/library/task.md +8 -0
- package/fixtures/cases/section-item-kind/schema.yaml +4 -0
- package/fixtures/cases/section-items/context.json +1 -0
- package/fixtures/cases/section-items/expected.json +1 -0
- package/fixtures/cases/section-items/library/other.md +3 -0
- package/fixtures/cases/section-items/library/page.md +28 -0
- package/fixtures/cases/section-items/schema.yaml +8 -0
- package/fixtures/cases/section-reference-path/context.json +1 -0
- package/fixtures/cases/section-reference-path/expected.json +6 -0
- package/fixtures/cases/section-reference-path/library/other.md +3 -0
- package/fixtures/cases/section-reference-path/library/page.md +7 -0
- package/fixtures/cases/section-reference-path/schema.yaml +4 -0
- package/fixtures/cases/section-reference-type/context.json +1 -0
- package/fixtures/cases/section-reference-type/expected.json +6 -0
- package/fixtures/cases/section-reference-type/library/note.md +1 -0
- package/fixtures/cases/section-reference-type/library/page.md +7 -0
- package/fixtures/cases/section-reference-type/schema.yaml +4 -0
- package/fixtures/cases/shortcut-reference-link/context.json +1 -0
- package/fixtures/cases/shortcut-reference-link/expected.json +5 -0
- package/fixtures/cases/shortcut-reference-link/library/item.md +10 -0
- package/fixtures/cases/shortcut-reference-link/schema.yaml +6 -0
- package/fixtures/cases/structured-section/expected.json +1 -2
- package/fixtures/cases/structured-section/schema.yaml +7 -0
- package/fixtures/cases/submission-keys/context.json +1 -0
- package/fixtures/cases/submission-keys/expected.json +1 -0
- package/fixtures/cases/submission-keys/library/notes/visitor.md +8 -0
- package/fixtures/cases/submission-keys/schema.yaml +4 -0
- package/fixtures/cases/text-field-kind/context.json +1 -0
- package/fixtures/cases/text-field-kind/expected.json +6 -0
- package/fixtures/cases/text-field-kind/library/page.md +4 -0
- package/fixtures/cases/text-field-kind/schema.yaml +4 -0
- package/fixtures/cases/truncated-link-definition/expected.json +1 -2
- package/fixtures/cases/truncated-link-definition/schema.yaml +2 -0
- package/fixtures/cases/types-folder-content/context.json +1 -0
- package/fixtures/cases/types-folder-content/expected.json +1 -0
- package/fixtures/cases/types-folder-content/library/types/task.md +4 -0
- package/fixtures/cases/types-folder-content/schema.yaml +4 -0
- package/fixtures/cases/unclosed-frontmatter/expected.json +1 -2
- package/fixtures/cases/undeclared-field/context.json +1 -0
- package/fixtures/cases/undeclared-field/expected.json +6 -0
- package/fixtures/cases/undeclared-field/library/item.md +9 -0
- package/fixtures/cases/undeclared-field/schema.yaml +6 -0
- package/fixtures/cases/unknown-type/context.json +1 -0
- package/fixtures/cases/unknown-type/expected.json +6 -0
- package/fixtures/cases/unknown-type/library/item.md +3 -0
- package/fixtures/cases/unknown-type/schema.yaml +4 -0
- package/fixtures/cases/unlisted-reference-type/context.json +1 -0
- package/fixtures/cases/unlisted-reference-type/expected.json +5 -0
- package/fixtures/cases/unlisted-reference-type/schema.yaml +4 -0
- package/fixtures/cases/unresolved-link/expected.json +1 -2
- package/fixtures/cases/unresolved-link/schema.yaml +6 -0
- package/fixtures/cases/valid-typed-document/library/tasks/one.md +1 -0
- package/fixtures/cases/valid-typed-document/schema.yaml +15 -0
- package/fixtures/cases/wide-item-fence-link/schema.yaml +2 -0
- package/fixtures/division.json +409 -0
- package/fixtures/projection.json +77 -28
- package/package.json +3 -12
- package/dist/definition.js.map +0 -1
- package/dist/document.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/links.js.map +0 -1
- package/dist/paths.js.map +0 -1
- package/dist/profile.js.map +0 -1
- package/dist/project.js.map +0 -1
- package/dist/refuse.js.map +0 -1
- package/dist/schema.js.map +0 -1
- package/dist/sections.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/validate.js.map +0 -1
- package/dist/version.js.map +0 -1
- package/dist/yaml.js.map +0 -1
- package/fixtures/cases/binary-any-reference/library/types/note.md +0 -5
- package/fixtures/cases/binary-document-collision/library/types/note.md +0 -3
- package/fixtures/cases/binary-link-outside-collection/library/types/note.md +0 -3
- package/fixtures/cases/binary-prototype-reference/library/types/note.md +0 -5
- package/fixtures/cases/binary-typed-reference/library/types/note.md +0 -5
- package/fixtures/cases/binary-typed-reference/library/types/person.md +0 -3
- package/fixtures/cases/bracketed-link-definition/library/types/task.md +0 -7
- package/fixtures/cases/declared-binary-links/library/types/note.md +0 -3
- package/fixtures/cases/duplicate-link-definition/library/types/task.md +0 -7
- package/fixtures/cases/fenced-link-definition/library/types/task.md +0 -7
- package/fixtures/cases/field-enum/library/types/task.md +0 -8
- package/fixtures/cases/interrupted-link-definition/library/types/note.md +0 -3
- package/fixtures/cases/long-fence-link-definition/library/types/note.md +0 -3
- package/fixtures/cases/malformed-definition/library/types/task.md +0 -5
- package/fixtures/cases/missing-binary-image/library/types/note.md +0 -3
- package/fixtures/cases/missing-binary-link/library/types/note.md +0 -3
- package/fixtures/cases/missing-required-field/library/types/task.md +0 -8
- package/fixtures/cases/paragraph-link-definition/library/types/note.md +0 -3
- package/fixtures/cases/prd-definition/library/types/task.md +0 -15
- package/fixtures/cases/quoted-link-definition/library/types/note.md +0 -3
- package/fixtures/cases/referenced-missing-file/library/types/person.md +0 -5
- package/fixtures/cases/referenced-missing-file/library/types/task.md +0 -8
- package/fixtures/cases/structured-section/library/types/task.md +0 -8
- package/fixtures/cases/truncated-link-definition/library/types/note.md +0 -3
- package/fixtures/cases/unresolved-link/library/types/task.md +0 -7
- package/fixtures/cases/valid-typed-document/library/types/person.md +0 -5
- package/fixtures/cases/valid-typed-document/library/types/task.md +0 -12
- package/fixtures/cases/wide-item-fence-link/library/types/note.md +0 -3
- package/markdown-syntax-profile.md +0 -9
- /package/fixtures/cases/{prd-definition → frontmatter-schema}/context.json +0 -0
- /package/fixtures/cases/{prd-definition → member-document}/expected.json +0 -0
package/dist/definition.js
CHANGED
|
@@ -1,165 +1,180 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
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)
|
|
13
|
-
|
|
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)
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
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 === '
|
|
31
|
-
kind: '
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (kind === 'number')
|
|
35
|
-
kind: 'number',
|
|
36
|
-
|
|
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)
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
53
|
-
|
|
54
|
-
|
|
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(
|
|
44
|
+
return refuse('definition-field-kind', location);
|
|
60
45
|
}
|
|
61
46
|
function extraKeys(spec, allowed) {
|
|
62
|
-
return Object.keys(spec).some((key)
|
|
47
|
+
return Object.keys(spec).some((key) => !allowed.includes(key));
|
|
63
48
|
}
|
|
64
|
-
function
|
|
65
|
-
if (
|
|
66
|
-
|
|
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 =
|
|
100
|
-
'kind',
|
|
101
|
-
'
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
|
115
|
-
if (!isRecord(value) ||
|
|
116
|
-
return refuse(
|
|
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
|
|
120
|
-
'
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
for (const key of Object.keys(
|
|
135
|
-
if (key !== '
|
|
136
|
-
return refuse(
|
|
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
|
|
140
|
-
|
|
141
|
-
|
|
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(
|
|
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(
|
|
148
|
-
if ('rule' in 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(
|
|
154
|
-
if ('rule' in 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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
package/dist/divide.d.ts
ADDED
|
@@ -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
|
+
}
|
package/dist/document.d.ts
CHANGED
|
@@ -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
|
package/dist/document.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|