@agentshouse/mdmodel 0.1.0-alpha.2 → 0.1.0-alpha.4
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/README.md +60 -6
- package/dist/document.d.ts +2 -1
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +71 -1
- package/dist/document.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/links.d.ts +7 -1
- package/dist/links.d.ts.map +1 -1
- package/dist/links.js +259 -48
- package/dist/links.js.map +1 -1
- package/dist/paths.d.ts +1 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +5 -0
- package/dist/paths.js.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/validate.d.ts +2 -2
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +12 -8
- package/dist/validate.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/yaml.d.ts +1 -0
- package/dist/yaml.d.ts.map +1 -1
- package/dist/yaml.js +5 -3
- package/dist/yaml.js.map +1 -1
- package/fixtures/README.md +12 -4
- package/fixtures/cases/any-without-type/context.json +1 -0
- package/fixtures/cases/binary-any-reference/context.json +5 -0
- package/fixtures/cases/binary-any-reference/expected.json +7 -0
- package/fixtures/cases/binary-any-reference/library/notes/draft.md +6 -0
- package/fixtures/cases/binary-any-reference/library/types/note.md +5 -0
- package/fixtures/cases/binary-document-collision/context.json +5 -0
- package/fixtures/cases/binary-document-collision/expected.json +6 -0
- package/fixtures/cases/binary-document-collision/library/notes/draft.md +3 -0
- package/fixtures/cases/binary-document-collision/library/types/note.md +3 -0
- package/fixtures/cases/binary-link-outside-collection/context.json +6 -0
- package/fixtures/cases/binary-link-outside-collection/expected.json +6 -0
- package/fixtures/cases/binary-link-outside-collection/library/notes/draft.md +5 -0
- package/fixtures/cases/binary-link-outside-collection/library/types/note.md +3 -0
- package/fixtures/cases/binary-prototype-reference/context.json +1 -0
- package/fixtures/cases/binary-prototype-reference/expected.json +7 -0
- package/fixtures/cases/binary-prototype-reference/library/notes/draft.md +6 -0
- package/fixtures/cases/binary-prototype-reference/library/types/note.md +5 -0
- package/fixtures/cases/binary-typed-reference/context.json +5 -0
- package/fixtures/cases/binary-typed-reference/expected.json +7 -0
- package/fixtures/cases/binary-typed-reference/library/notes/draft.md +6 -0
- package/fixtures/cases/binary-typed-reference/library/types/note.md +5 -0
- package/fixtures/cases/binary-typed-reference/library/types/person.md +3 -0
- package/fixtures/cases/bracketed-link-definition/context.json +1 -0
- package/fixtures/cases/bracketed-link-definition/expected.json +1 -0
- package/fixtures/cases/bracketed-link-definition/library/item.md +10 -0
- package/fixtures/cases/bracketed-link-definition/library/types/task.md +7 -0
- package/fixtures/cases/declared-binary-links/context.json +6 -0
- package/fixtures/cases/declared-binary-links/expected.json +1 -0
- package/fixtures/cases/declared-binary-links/library/notes/draft.md +7 -0
- package/fixtures/cases/declared-binary-links/library/types/note.md +3 -0
- package/fixtures/cases/duplicate-link-definition/context.json +1 -0
- package/fixtures/cases/duplicate-link-definition/expected.json +1 -0
- package/fixtures/cases/duplicate-link-definition/library/item.md +11 -0
- package/fixtures/cases/duplicate-link-definition/library/types/task.md +7 -0
- package/fixtures/cases/fenced-link-definition/context.json +1 -0
- package/fixtures/cases/fenced-link-definition/expected.json +1 -0
- package/fixtures/cases/fenced-link-definition/library/item.md +12 -0
- package/fixtures/cases/fenced-link-definition/library/types/task.md +7 -0
- package/fixtures/cases/field-enum/context.json +1 -0
- package/fixtures/cases/interrupted-link-definition/context.json +1 -0
- package/fixtures/cases/interrupted-link-definition/expected.json +1 -0
- package/fixtures/cases/interrupted-link-definition/library/notes/draft.md +8 -0
- package/fixtures/cases/interrupted-link-definition/library/types/note.md +3 -0
- package/fixtures/cases/long-fence-link-definition/context.json +1 -0
- package/fixtures/cases/long-fence-link-definition/expected.json +1 -0
- package/fixtures/cases/long-fence-link-definition/library/notes/draft.md +9 -0
- package/fixtures/cases/long-fence-link-definition/library/types/note.md +3 -0
- package/fixtures/cases/malformed-definition/context.json +1 -0
- package/fixtures/cases/missing-binary-image/context.json +6 -0
- package/fixtures/cases/missing-binary-image/expected.json +6 -0
- package/fixtures/cases/missing-binary-image/library/notes/draft.md +5 -0
- package/fixtures/cases/missing-binary-image/library/types/note.md +3 -0
- package/fixtures/cases/missing-binary-link/context.json +6 -0
- package/fixtures/cases/missing-binary-link/expected.json +6 -0
- package/fixtures/cases/missing-binary-link/library/notes/draft.md +5 -0
- package/fixtures/cases/missing-binary-link/library/types/note.md +3 -0
- package/fixtures/cases/missing-required-field/context.json +1 -0
- package/fixtures/cases/paragraph-link-definition/context.json +5 -0
- package/fixtures/cases/paragraph-link-definition/expected.json +1 -0
- package/fixtures/cases/paragraph-link-definition/library/notes/draft.md +10 -0
- package/fixtures/cases/paragraph-link-definition/library/types/note.md +3 -0
- package/fixtures/cases/prd-definition/context.json +1 -0
- package/fixtures/cases/quoted-link-definition/context.json +1 -0
- package/fixtures/cases/quoted-link-definition/expected.json +6 -0
- package/fixtures/cases/quoted-link-definition/library/notes/draft.md +7 -0
- package/fixtures/cases/quoted-link-definition/library/types/note.md +3 -0
- package/fixtures/cases/referenced-missing-file/context.json +1 -0
- package/fixtures/cases/structured-section/context.json +1 -0
- package/fixtures/cases/truncated-link-definition/context.json +1 -0
- package/fixtures/cases/truncated-link-definition/expected.json +6 -0
- package/fixtures/cases/truncated-link-definition/library/notes/draft.md +7 -0
- package/fixtures/cases/truncated-link-definition/library/notes/other.md +5 -0
- package/fixtures/cases/truncated-link-definition/library/types/note.md +3 -0
- package/fixtures/cases/unclosed-frontmatter/context.json +1 -0
- package/fixtures/cases/unresolved-link/context.json +1 -0
- package/fixtures/cases/valid-typed-document/context.json +1 -0
- package/fixtures/cases/wide-item-fence-link/context.json +1 -0
- package/fixtures/cases/wide-item-fence-link/expected.json +1 -0
- package/fixtures/cases/wide-item-fence-link/library/notes/draft.md +7 -0
- package/fixtures/cases/wide-item-fence-link/library/types/note.md +3 -0
- package/package.json +1 -1
package/dist/links.js
CHANGED
|
@@ -1,17 +1,127 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
const TAB_STOP = 4;
|
|
2
|
+
const CLOSING_FENCE_INDENT = 3;
|
|
3
|
+
const HEADING = /^#{1,6}(?:[ \t]|$)/;
|
|
4
|
+
const BREAK = /^(?:(?:\*[ \t]*){3,}|(?:-[ \t]*){3,}|(?:_[ \t]*){3,})$/;
|
|
5
|
+
const SETEXT = /^(?:=+|-+)[ \t]*$/;
|
|
6
|
+
const LABEL = /^\[((?:[^\\\]\n]|\\.)+)\]:[ \t]*/;
|
|
7
|
+
const DESTINATION = /^(?:(<[^<>\n\r]*>)|([^\s<][^\s]*))/d;
|
|
8
|
+
const TITLE = /^(?:"[^"\n]*"|'[^'\n]*'|\([^()\n]*\))[ \t]*$/;
|
|
9
|
+
function endOfLine(text, from) {
|
|
10
|
+
const nl = text.indexOf('\n', from);
|
|
11
|
+
return nl === -1 ? text.length : nl;
|
|
5
12
|
}
|
|
6
|
-
function
|
|
13
|
+
function afterLine(text, end) {
|
|
14
|
+
return end < text.length ? end + 1 : text.length;
|
|
15
|
+
}
|
|
16
|
+
function itemMarker(text, index, end) {
|
|
7
17
|
let i = index;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
const bullet = text[i];
|
|
19
|
+
if (bullet === '-' || bullet === '*' || bullet === '+') i += 1;
|
|
20
|
+
else {
|
|
21
|
+
let digits = 0;
|
|
22
|
+
while(digits < 9 && i + digits < end && text[i + digits] >= '0' && text[i + digits] <= '9')digits += 1;
|
|
23
|
+
const delimiter = text[i + digits];
|
|
24
|
+
if (digits === 0 || delimiter !== '.' && delimiter !== ')') return null;
|
|
25
|
+
i += digits + 1;
|
|
26
|
+
}
|
|
27
|
+
if (i >= end) return i;
|
|
28
|
+
if (text[i] !== ' ' && text[i] !== '\t') return null;
|
|
29
|
+
return i + 1;
|
|
30
|
+
}
|
|
31
|
+
function readLine(text, start, end) {
|
|
32
|
+
let i = start;
|
|
33
|
+
let depth = 0;
|
|
34
|
+
let item = false;
|
|
35
|
+
let inner = start;
|
|
36
|
+
for(;;){
|
|
37
|
+
let spaces = 0;
|
|
38
|
+
while(spaces < 3 && i < end && text[i] === ' '){
|
|
39
|
+
i += 1;
|
|
40
|
+
spaces += 1;
|
|
41
|
+
}
|
|
42
|
+
if (i < end && text[i] === '>') {
|
|
43
|
+
depth += 1;
|
|
44
|
+
i += 1;
|
|
45
|
+
if (i < end && text[i] === ' ') i += 1;
|
|
46
|
+
inner = i;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const after = i < end ? itemMarker(text, i, end) : null;
|
|
50
|
+
if (after === null) break;
|
|
51
|
+
item = true;
|
|
52
|
+
i = after;
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
start,
|
|
56
|
+
end,
|
|
57
|
+
content: i,
|
|
58
|
+
depth,
|
|
59
|
+
item,
|
|
60
|
+
inner
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function widthOf(text, from, to) {
|
|
64
|
+
let width = 0;
|
|
65
|
+
for(let i = from; i < to; i += 1)width += text[i] === '\t' ? TAB_STOP - width % TAB_STOP : 1;
|
|
66
|
+
return width;
|
|
67
|
+
}
|
|
68
|
+
function afterIndent(text, line) {
|
|
69
|
+
let i = line.inner;
|
|
70
|
+
while(i < line.end && (text[i] === ' ' || text[i] === '\t'))i += 1;
|
|
71
|
+
return i;
|
|
72
|
+
}
|
|
73
|
+
function indentWidth(text, line) {
|
|
74
|
+
return widthOf(text, line.inner, afterIndent(text, line));
|
|
75
|
+
}
|
|
76
|
+
function lineText(text, line) {
|
|
77
|
+
const raw = text.slice(line.content, line.end);
|
|
78
|
+
return raw.endsWith('\r') ? raw.slice(0, -1) : raw;
|
|
79
|
+
}
|
|
80
|
+
function fenceRun(text, at, end) {
|
|
81
|
+
const char = text[at];
|
|
82
|
+
if (char !== '`' && char !== '~') return null;
|
|
83
|
+
let length = 0;
|
|
84
|
+
while(at + length < end && text[at + length] === char)length += 1;
|
|
85
|
+
return length < 3 ? null : {
|
|
86
|
+
char,
|
|
87
|
+
length
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function fenceAt(text, line) {
|
|
91
|
+
const run = fenceRun(text, line.content, line.end);
|
|
92
|
+
if (run === null) return null;
|
|
93
|
+
return {
|
|
94
|
+
char: run.char,
|
|
95
|
+
length: run.length,
|
|
96
|
+
depth: line.depth,
|
|
97
|
+
column: line.item ? widthOf(text, line.inner, line.content) : 0,
|
|
98
|
+
item: line.item
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function closesFence(text, line, open) {
|
|
102
|
+
if (line.depth !== open.depth || line.item) return false;
|
|
103
|
+
const indent = indentWidth(text, line);
|
|
104
|
+
if (indent < open.column || indent > open.column + CLOSING_FENCE_INDENT) return false;
|
|
105
|
+
const at = afterIndent(text, line);
|
|
106
|
+
const run = fenceRun(text, at, line.end);
|
|
107
|
+
if (run === null || run.char !== open.char || run.length < open.length) return false;
|
|
108
|
+
return text.slice(at + run.length, line.end).trim() === '';
|
|
109
|
+
}
|
|
110
|
+
function leavesContainer(text, line, open) {
|
|
111
|
+
if (line.depth < open.depth) return true;
|
|
112
|
+
if (!open.item || lineText(text, line).trim() === '') return false;
|
|
113
|
+
return indentWidth(text, line) < open.column;
|
|
114
|
+
}
|
|
115
|
+
function fenceSpan(text, line, open) {
|
|
116
|
+
let cursor = afterLine(text, line.end);
|
|
117
|
+
while(cursor < text.length){
|
|
118
|
+
const end = endOfLine(text, cursor);
|
|
119
|
+
const next = readLine(text, cursor, end);
|
|
120
|
+
if (leavesContainer(text, next, open)) return cursor;
|
|
121
|
+
if (closesFence(text, next, open)) return afterLine(text, end);
|
|
122
|
+
cursor = afterLine(text, end);
|
|
123
|
+
}
|
|
124
|
+
return text.length;
|
|
15
125
|
}
|
|
16
126
|
function skipInlineCode(text, index) {
|
|
17
127
|
let ticks = 0;
|
|
@@ -40,11 +150,16 @@ function skipTitle(text, start) {
|
|
|
40
150
|
}
|
|
41
151
|
function destination(text, start) {
|
|
42
152
|
let i = skipLinkSpace(text, start + 1);
|
|
43
|
-
let
|
|
153
|
+
let occurrence;
|
|
44
154
|
if (text[i] === '<') {
|
|
45
155
|
const close = text.indexOf('>', i + 1);
|
|
46
156
|
if (close === -1) return null;
|
|
47
|
-
|
|
157
|
+
occurrence = {
|
|
158
|
+
href: text.slice(i + 1, close),
|
|
159
|
+
start: i,
|
|
160
|
+
end: close + 1,
|
|
161
|
+
bracketed: true
|
|
162
|
+
};
|
|
48
163
|
i = close + 1;
|
|
49
164
|
} else {
|
|
50
165
|
const from = i;
|
|
@@ -59,7 +174,12 @@ function destination(text, start) {
|
|
|
59
174
|
}
|
|
60
175
|
i += 1;
|
|
61
176
|
}
|
|
62
|
-
|
|
177
|
+
occurrence = {
|
|
178
|
+
href: text.slice(from, i),
|
|
179
|
+
start: from,
|
|
180
|
+
end: i,
|
|
181
|
+
bracketed: false
|
|
182
|
+
};
|
|
63
183
|
}
|
|
64
184
|
i = skipLinkSpace(text, i);
|
|
65
185
|
const afterTitle = skipTitle(text, i);
|
|
@@ -67,76 +187,167 @@ function destination(text, start) {
|
|
|
67
187
|
i = skipLinkSpace(text, afterTitle);
|
|
68
188
|
if (text[i] !== ')') return null;
|
|
69
189
|
return {
|
|
70
|
-
|
|
190
|
+
occurrence,
|
|
71
191
|
end: i + 1
|
|
72
192
|
};
|
|
73
193
|
}
|
|
74
|
-
function
|
|
75
|
-
let i =
|
|
194
|
+
function labelEnd(text, start) {
|
|
195
|
+
let i = start;
|
|
76
196
|
let depth = 1;
|
|
77
197
|
while(i < text.length && depth > 0){
|
|
78
198
|
const ch = text[i];
|
|
199
|
+
if (ch === '\\') {
|
|
200
|
+
i += 2;
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
79
203
|
if (ch === '[') depth += 1;
|
|
80
204
|
else if (ch === ']') depth -= 1;
|
|
81
|
-
else if (ch === '\n' || ch === '\r') return
|
|
205
|
+
else if (ch === '\n' || ch === '\r') return -1;
|
|
82
206
|
i += 1;
|
|
83
207
|
}
|
|
84
|
-
|
|
85
|
-
|
|
208
|
+
return depth === 0 ? i : -1;
|
|
209
|
+
}
|
|
210
|
+
function takeLink(text, index, found, defs) {
|
|
211
|
+
const end = labelEnd(text, index + 1);
|
|
212
|
+
if (end === -1) return index + 1;
|
|
213
|
+
const label = text.slice(index + 1, end - 1);
|
|
214
|
+
let i = end;
|
|
86
215
|
if (text[i] === '(') {
|
|
87
216
|
const dest = destination(text, i);
|
|
88
217
|
if (dest === null) return index + 1;
|
|
89
|
-
|
|
218
|
+
found.push(dest.occurrence);
|
|
90
219
|
return dest.end;
|
|
91
220
|
}
|
|
92
221
|
if (text[i] === '[') {
|
|
93
|
-
const close = text
|
|
222
|
+
const close = labelEnd(text, i + 1);
|
|
94
223
|
if (close === -1) return index + 1;
|
|
95
|
-
const id = (text.slice(i + 1, close) || label).trim().toLowerCase();
|
|
96
|
-
const
|
|
97
|
-
if (
|
|
98
|
-
return close
|
|
224
|
+
const id = (text.slice(i + 1, close - 1) || label).trim().toLowerCase();
|
|
225
|
+
const defined = defs.get(id);
|
|
226
|
+
if (defined !== undefined) found.push(defined);
|
|
227
|
+
return close;
|
|
99
228
|
}
|
|
100
229
|
return i;
|
|
101
230
|
}
|
|
102
|
-
function
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
231
|
+
function definitionDestination(text, from, to) {
|
|
232
|
+
let i = from;
|
|
233
|
+
while(i < to && (text[i] === ' ' || text[i] === '\t'))i += 1;
|
|
234
|
+
const match = DESTINATION.exec(text.slice(i, to));
|
|
235
|
+
if (match === null) return null;
|
|
236
|
+
const bracketed = match[1];
|
|
237
|
+
const span = match.indices?.[1] ?? match.indices?.[2];
|
|
238
|
+
const href = bracketed === undefined ? match[2] : bracketed.slice(1, -1);
|
|
239
|
+
if (href === undefined || span === undefined) return null;
|
|
240
|
+
return {
|
|
241
|
+
href,
|
|
242
|
+
start: i + span[0],
|
|
243
|
+
end: i + span[1],
|
|
244
|
+
bracketed: bracketed !== undefined
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
function definitionAt(text, line) {
|
|
248
|
+
const head = LABEL.exec(lineText(text, line));
|
|
249
|
+
if (head === null) return null;
|
|
250
|
+
const id = head[1]?.trim().toLowerCase();
|
|
251
|
+
if (id === undefined || id === '') return null;
|
|
252
|
+
const from = line.content + head[0].length;
|
|
253
|
+
let occurrence = definitionDestination(text, from, line.end);
|
|
254
|
+
let next = afterLine(text, line.end);
|
|
255
|
+
if (occurrence === null) {
|
|
256
|
+
if (text.slice(from, line.end).trim() !== '' || next >= text.length) return null;
|
|
257
|
+
const end = endOfLine(text, next);
|
|
258
|
+
occurrence = definitionDestination(text, readLine(text, next, end).content, end);
|
|
259
|
+
if (occurrence === null) return null;
|
|
260
|
+
next = afterLine(text, end);
|
|
261
|
+
}
|
|
262
|
+
if (next < text.length) {
|
|
263
|
+
const end = endOfLine(text, next);
|
|
264
|
+
if (TITLE.test(lineText(text, readLine(text, next, end)))) next = afterLine(text, end);
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
id,
|
|
268
|
+
occurrence,
|
|
269
|
+
next
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
function endsBlock(content) {
|
|
273
|
+
return HEADING.test(content) || BREAK.test(content) || SETEXT.test(content);
|
|
274
|
+
}
|
|
275
|
+
function scanBlocks(text) {
|
|
276
|
+
const fences = [];
|
|
277
|
+
const definitions = new Map();
|
|
278
|
+
let paragraph = false;
|
|
279
|
+
let depth = 0;
|
|
280
|
+
let i = 0;
|
|
281
|
+
while(i < text.length){
|
|
282
|
+
const line = readLine(text, i, endOfLine(text, i));
|
|
283
|
+
if (line.depth !== depth || line.item) paragraph = false;
|
|
284
|
+
depth = line.depth;
|
|
285
|
+
const open = fenceAt(text, line);
|
|
286
|
+
if (open !== null) {
|
|
287
|
+
const stop = fenceSpan(text, line, open);
|
|
288
|
+
fences.push([
|
|
289
|
+
i,
|
|
290
|
+
stop
|
|
291
|
+
]);
|
|
292
|
+
paragraph = false;
|
|
293
|
+
i = stop;
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
const content = lineText(text, line);
|
|
297
|
+
if (content.trim() === '') {
|
|
298
|
+
paragraph = false;
|
|
299
|
+
i = afterLine(text, line.end);
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const definition = paragraph ? null : definitionAt(text, line);
|
|
303
|
+
if (definition !== null) {
|
|
304
|
+
if (!definitions.has(definition.id)) definitions.set(definition.id, definition.occurrence);
|
|
305
|
+
i = definition.next;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
paragraph = !endsBlock(content);
|
|
309
|
+
i = afterLine(text, line.end);
|
|
109
310
|
}
|
|
110
|
-
return
|
|
311
|
+
return {
|
|
312
|
+
fences,
|
|
313
|
+
definitions
|
|
314
|
+
};
|
|
111
315
|
}
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
316
|
+
function fenceEndAt(spans, index) {
|
|
317
|
+
for (const [start, end] of spans){
|
|
318
|
+
if (index >= start && index < end) return end;
|
|
319
|
+
}
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
export function hrefOccurrences(body) {
|
|
323
|
+
const { fences, definitions } = scanBlocks(body);
|
|
324
|
+
const found = [];
|
|
115
325
|
let i = 0;
|
|
116
326
|
while(i < body.length){
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
i = skipFence(body, i);
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
327
|
+
const fenceEnd = fenceEndAt(fences, i);
|
|
328
|
+
if (fenceEnd !== undefined) {
|
|
329
|
+
i = fenceEnd;
|
|
330
|
+
continue;
|
|
124
331
|
}
|
|
125
332
|
if (body[i] === '`') {
|
|
126
333
|
i = skipInlineCode(body, i);
|
|
127
334
|
continue;
|
|
128
335
|
}
|
|
129
336
|
if (body[i] === '!' && body[i + 1] === '[') {
|
|
130
|
-
i = takeLink(body, i + 1,
|
|
337
|
+
i = takeLink(body, i + 1, found, definitions);
|
|
131
338
|
continue;
|
|
132
339
|
}
|
|
133
340
|
if (body[i] === '[') {
|
|
134
|
-
i = takeLink(body, i,
|
|
341
|
+
i = takeLink(body, i, found, definitions);
|
|
135
342
|
continue;
|
|
136
343
|
}
|
|
137
344
|
i += 1;
|
|
138
345
|
}
|
|
139
|
-
|
|
346
|
+
const byStart = new Map();
|
|
347
|
+
for (const occurrence of found)byStart.set(occurrence.start, occurrence);
|
|
348
|
+
return [
|
|
349
|
+
...byStart.values()
|
|
350
|
+
].sort((left, right)=>left.start - right.start);
|
|
140
351
|
}
|
|
141
352
|
|
|
142
353
|
//# sourceMappingURL=links.js.map
|
package/dist/links.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/workspace/packages/mdmodel/src/links.ts"],"sourcesContent":["function atLineStart(text: string, index: number): boolean {\n if (index === 0) return true;\n const prev = text[index - 1];\n return prev === '\\n' || prev === '\\r';\n}\n\nfunction skipFence(text: string, index: number): number {\n let i = index;\n while (i < text.length && (text[i] === ' ' || text[i] === '\\t')) i += 1;\n const marker = text.startsWith('```', i) ? '```' : text.startsWith('~~~', i) ? '~~~' : null;\n if (marker === null) return index + 1;\n i += marker.length;\n const close = text.indexOf(marker, i);\n if (close === -1) return text.length;\n return close + marker.length;\n}\n\nfunction skipInlineCode(text: string, index: number): number {\n let ticks = 0;\n while (text[index + ticks] === '`') ticks += 1;\n const close = text.indexOf('`'.repeat(ticks), index + ticks);\n if (close === -1) return text.length;\n return close + ticks;\n}\n\nfunction skipLinkSpace(text: string, start: number): number {\n let i = start;\n while (text[i] === ' ' || text[i] === '\\t') i += 1;\n return i;\n}\n\nfunction skipTitle(text: string, start: number): number | null {\n const open = text[start];\n if (open !== '\"' && open !== \"'\" && open !== '(') return start;\n const close = open === '(' ? ')' : open;\n let i = start + 1;\n while (i < text.length) {\n const ch = text[i]!;\n if (ch === close) return i + 1;\n if (ch === '\\n' || ch === '\\r') return null;\n i += 1;\n }\n return null;\n}\n\nfunction destination(text: string, start: number): { href: string; end: number } | null {\n let i = skipLinkSpace(text, start + 1);\n let href: string;\n if (text[i] === '<') {\n const close = text.indexOf('>', i + 1);\n if (close === -1) return null;\n href = text.slice(i + 1, close);\n i = close + 1;\n } else {\n const from = i;\n let depth = 0;\n while (i < text.length) {\n const ch = text[i]!;\n if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r') break;\n if (ch === '(') depth += 1;\n else if (ch === ')') {\n if (depth === 0) break;\n depth -= 1;\n }\n i += 1;\n }\n href = text.slice(from, i);\n }\n i = skipLinkSpace(text, i);\n const afterTitle = skipTitle(text, i);\n if (afterTitle === null) return null;\n i = skipLinkSpace(text, afterTitle);\n if (text[i] !== ')') return null;\n return { href, end: i + 1 };\n}\n\nfunction takeLink(text: string, index: number, hrefs: string[], defs: Map<string, string>): number {\n let i = index + 1;\n let depth = 1;\n while (i < text.length && depth > 0) {\n const ch = text[i]!;\n if (ch === '[') depth += 1;\n else if (ch === ']') depth -= 1;\n else if (ch === '\\n' || ch === '\\r') return index + 1;\n i += 1;\n }\n if (depth !== 0) return index + 1;\n const label = text.slice(index + 1, i - 1);\n if (text[i] === '(') {\n const dest = destination(text, i);\n if (dest === null) return index + 1;\n hrefs.push(dest.href);\n return dest.end;\n }\n if (text[i] === '[') {\n const close = text.indexOf(']', i + 1);\n if (close === -1) return index + 1;\n const id = (text.slice(i + 1, close) || label).trim().toLowerCase();\n const href = defs.get(id);\n if (href !== undefined) hrefs.push(href);\n return close + 1;\n }\n return i;\n}\n\nfunction collectDefinitions(text: string): Map<string, string> {\n const defs = new Map<string, string>();\n const pattern = /^ {0,3}\\[([^\\]]+)\\]:[ \\t]+<?([^\\s>]+)>?/gm;\n for (const match of text.matchAll(pattern)) {\n const id = match[1]?.trim().toLowerCase();\n const href = match[2];\n if (id !== undefined && href !== undefined) defs.set(id, href);\n }\n return defs;\n}\n\nexport function extractRelativeHrefs(body: string): string[] {\n const defs = collectDefinitions(body);\n const hrefs: string[] = [];\n let i = 0;\n while (i < body.length) {\n if (atLineStart(body, i) || (i > 0 && (body[i - 1] === '\\n' || body[i - 1] === '\\r'))) {\n let j = i;\n while (body[j] === ' ' && j - i < 3) j += 1;\n if (body.startsWith('```', j) || body.startsWith('~~~', j)) {\n i = skipFence(body, i);\n continue;\n }\n }\n if (body[i] === '`') {\n i = skipInlineCode(body, i);\n continue;\n }\n if (body[i] === '!' && body[i + 1] === '[') {\n i = takeLink(body, i + 1, hrefs, defs);\n continue;\n }\n if (body[i] === '[') {\n i = takeLink(body, i, hrefs, defs);\n continue;\n }\n i += 1;\n }\n return hrefs;\n}\n"],"names":["atLineStart","text","index","prev","skipFence","i","length","marker","startsWith","close","indexOf","skipInlineCode","ticks","repeat","skipLinkSpace","start","skipTitle","open","ch","destination","href","slice","from","depth","afterTitle","end","takeLink","hrefs","defs","label","dest","push","id","trim","toLowerCase","get","undefined","collectDefinitions","Map","pattern","match","matchAll","set","extractRelativeHrefs","body","j"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/workspace/packages/mdmodel/src/links.ts"],"sourcesContent":["type Fence = {\n readonly char: string;\n readonly length: number;\n readonly depth: number;\n readonly column: number;\n readonly item: boolean;\n};\n\ntype Line = {\n readonly start: number;\n readonly end: number;\n readonly content: number;\n readonly depth: number;\n readonly item: boolean;\n readonly inner: number;\n};\n\nconst TAB_STOP = 4;\nconst CLOSING_FENCE_INDENT = 3;\n\nconst HEADING = /^#{1,6}(?:[ \\t]|$)/;\nconst BREAK = /^(?:(?:\\*[ \\t]*){3,}|(?:-[ \\t]*){3,}|(?:_[ \\t]*){3,})$/;\nconst SETEXT = /^(?:=+|-+)[ \\t]*$/;\nconst LABEL = /^\\[((?:[^\\\\\\]\\n]|\\\\.)+)\\]:[ \\t]*/;\nconst DESTINATION = /^(?:(<[^<>\\n\\r]*>)|([^\\s<][^\\s]*))/d;\nconst TITLE = /^(?:\"[^\"\\n]*\"|'[^'\\n]*'|\\([^()\\n]*\\))[ \\t]*$/;\n\nfunction endOfLine(text: string, from: number): number {\n const nl = text.indexOf('\\n', from);\n return nl === -1 ? text.length : nl;\n}\n\nfunction afterLine(text: string, end: number): number {\n return end < text.length ? end + 1 : text.length;\n}\n\nfunction itemMarker(text: string, index: number, end: number): number | null {\n let i = index;\n const bullet = text[i];\n if (bullet === '-' || bullet === '*' || bullet === '+') i += 1;\n else {\n let digits = 0;\n while (digits < 9 && i + digits < end && text[i + digits]! >= '0' && text[i + digits]! <= '9')\n digits += 1;\n const delimiter = text[i + digits];\n if (digits === 0 || (delimiter !== '.' && delimiter !== ')')) return null;\n i += digits + 1;\n }\n if (i >= end) return i;\n if (text[i] !== ' ' && text[i] !== '\\t') return null;\n return i + 1;\n}\n\nfunction readLine(text: string, start: number, end: number): Line {\n let i = start;\n let depth = 0;\n let item = false;\n let inner = start;\n for (;;) {\n let spaces = 0;\n while (spaces < 3 && i < end && text[i] === ' ') {\n i += 1;\n spaces += 1;\n }\n if (i < end && text[i] === '>') {\n depth += 1;\n i += 1;\n if (i < end && text[i] === ' ') i += 1;\n inner = i;\n continue;\n }\n const after = i < end ? itemMarker(text, i, end) : null;\n if (after === null) break;\n item = true;\n i = after;\n }\n return { start, end, content: i, depth, item, inner };\n}\n\nfunction widthOf(text: string, from: number, to: number): number {\n let width = 0;\n for (let i = from; i < to; i += 1) width += text[i] === '\\t' ? TAB_STOP - (width % TAB_STOP) : 1;\n return width;\n}\n\nfunction afterIndent(text: string, line: Line): number {\n let i = line.inner;\n while (i < line.end && (text[i] === ' ' || text[i] === '\\t')) i += 1;\n return i;\n}\n\nfunction indentWidth(text: string, line: Line): number {\n return widthOf(text, line.inner, afterIndent(text, line));\n}\n\nfunction lineText(text: string, line: Line): string {\n const raw = text.slice(line.content, line.end);\n return raw.endsWith('\\r') ? raw.slice(0, -1) : raw;\n}\n\nfunction fenceRun(\n text: string,\n at: number,\n end: number,\n): { readonly char: string; readonly length: number } | null {\n const char = text[at];\n if (char !== '`' && char !== '~') return null;\n let length = 0;\n while (at + length < end && text[at + length] === char) length += 1;\n return length < 3 ? null : { char, length };\n}\n\nfunction fenceAt(text: string, line: Line): Fence | null {\n const run = fenceRun(text, line.content, line.end);\n if (run === null) return null;\n return {\n char: run.char,\n length: run.length,\n depth: line.depth,\n column: line.item ? widthOf(text, line.inner, line.content) : 0,\n item: line.item,\n };\n}\n\nfunction closesFence(text: string, line: Line, open: Fence): boolean {\n if (line.depth !== open.depth || line.item) return false;\n const indent = indentWidth(text, line);\n if (indent < open.column || indent > open.column + CLOSING_FENCE_INDENT) return false;\n const at = afterIndent(text, line);\n const run = fenceRun(text, at, line.end);\n if (run === null || run.char !== open.char || run.length < open.length) return false;\n return text.slice(at + run.length, line.end).trim() === '';\n}\n\nfunction leavesContainer(text: string, line: Line, open: Fence): boolean {\n if (line.depth < open.depth) return true;\n if (!open.item || lineText(text, line).trim() === '') return false;\n return indentWidth(text, line) < open.column;\n}\n\nfunction fenceSpan(text: string, line: Line, open: Fence): number {\n let cursor = afterLine(text, line.end);\n while (cursor < text.length) {\n const end = endOfLine(text, cursor);\n const next = readLine(text, cursor, end);\n if (leavesContainer(text, next, open)) return cursor;\n if (closesFence(text, next, open)) return afterLine(text, end);\n cursor = afterLine(text, end);\n }\n return text.length;\n}\n\nfunction skipInlineCode(text: string, index: number): number {\n let ticks = 0;\n while (text[index + ticks] === '`') ticks += 1;\n const close = text.indexOf('`'.repeat(ticks), index + ticks);\n if (close === -1) return text.length;\n return close + ticks;\n}\n\nfunction skipLinkSpace(text: string, start: number): number {\n let i = start;\n while (text[i] === ' ' || text[i] === '\\t') i += 1;\n return i;\n}\n\nfunction skipTitle(text: string, start: number): number | null {\n const open = text[start];\n if (open !== '\"' && open !== \"'\" && open !== '(') return start;\n const close = open === '(' ? ')' : open;\n let i = start + 1;\n while (i < text.length) {\n const ch = text[i]!;\n if (ch === close) return i + 1;\n if (ch === '\\n' || ch === '\\r') return null;\n i += 1;\n }\n return null;\n}\n\nfunction destination(\n text: string,\n start: number,\n): { occurrence: HrefOccurrence; end: number } | null {\n let i = skipLinkSpace(text, start + 1);\n let occurrence: HrefOccurrence;\n if (text[i] === '<') {\n const close = text.indexOf('>', i + 1);\n if (close === -1) return null;\n occurrence = { href: text.slice(i + 1, close), start: i, end: close + 1, bracketed: true };\n i = close + 1;\n } else {\n const from = i;\n let depth = 0;\n while (i < text.length) {\n const ch = text[i]!;\n if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r') break;\n if (ch === '(') depth += 1;\n else if (ch === ')') {\n if (depth === 0) break;\n depth -= 1;\n }\n i += 1;\n }\n occurrence = { href: text.slice(from, i), start: from, end: i, bracketed: false };\n }\n i = skipLinkSpace(text, i);\n const afterTitle = skipTitle(text, i);\n if (afterTitle === null) return null;\n i = skipLinkSpace(text, afterTitle);\n if (text[i] !== ')') return null;\n return { occurrence, end: i + 1 };\n}\n\nfunction labelEnd(text: string, start: number): number {\n let i = start;\n let depth = 1;\n while (i < text.length && depth > 0) {\n const ch = text[i]!;\n if (ch === '\\\\') {\n i += 2;\n continue;\n }\n if (ch === '[') depth += 1;\n else if (ch === ']') depth -= 1;\n else if (ch === '\\n' || ch === '\\r') return -1;\n i += 1;\n }\n return depth === 0 ? i : -1;\n}\n\nfunction takeLink(\n text: string,\n index: number,\n found: HrefOccurrence[],\n defs: ReadonlyMap<string, HrefOccurrence>,\n): number {\n const end = labelEnd(text, index + 1);\n if (end === -1) return index + 1;\n const label = text.slice(index + 1, end - 1);\n let i = end;\n if (text[i] === '(') {\n const dest = destination(text, i);\n if (dest === null) return index + 1;\n found.push(dest.occurrence);\n return dest.end;\n }\n if (text[i] === '[') {\n const close = labelEnd(text, i + 1);\n if (close === -1) return index + 1;\n const id = (text.slice(i + 1, close - 1) || label).trim().toLowerCase();\n const defined = defs.get(id);\n if (defined !== undefined) found.push(defined);\n return close;\n }\n return i;\n}\n\nfunction definitionDestination(text: string, from: number, to: number): HrefOccurrence | null {\n let i = from;\n while (i < to && (text[i] === ' ' || text[i] === '\\t')) i += 1;\n const match = DESTINATION.exec(text.slice(i, to));\n if (match === null) return null;\n const bracketed = match[1];\n const span = match.indices?.[1] ?? match.indices?.[2];\n const href = bracketed === undefined ? match[2] : bracketed.slice(1, -1);\n if (href === undefined || span === undefined) return null;\n return { href, start: i + span[0], end: i + span[1], bracketed: bracketed !== undefined };\n}\n\nfunction definitionAt(\n text: string,\n line: Line,\n): { id: string; occurrence: HrefOccurrence; next: number } | null {\n const head = LABEL.exec(lineText(text, line));\n if (head === null) return null;\n const id = head[1]?.trim().toLowerCase();\n if (id === undefined || id === '') return null;\n const from = line.content + head[0].length;\n let occurrence = definitionDestination(text, from, line.end);\n let next = afterLine(text, line.end);\n if (occurrence === null) {\n if (text.slice(from, line.end).trim() !== '' || next >= text.length) return null;\n const end = endOfLine(text, next);\n occurrence = definitionDestination(text, readLine(text, next, end).content, end);\n if (occurrence === null) return null;\n next = afterLine(text, end);\n }\n if (next < text.length) {\n const end = endOfLine(text, next);\n if (TITLE.test(lineText(text, readLine(text, next, end)))) next = afterLine(text, end);\n }\n return { id, occurrence, next };\n}\n\nfunction endsBlock(content: string): boolean {\n return HEADING.test(content) || BREAK.test(content) || SETEXT.test(content);\n}\n\nfunction scanBlocks(text: string): {\n readonly fences: readonly (readonly [number, number])[];\n readonly definitions: ReadonlyMap<string, HrefOccurrence>;\n} {\n const fences: [number, number][] = [];\n const definitions = new Map<string, HrefOccurrence>();\n let paragraph = false;\n let depth = 0;\n let i = 0;\n while (i < text.length) {\n const line = readLine(text, i, endOfLine(text, i));\n if (line.depth !== depth || line.item) paragraph = false;\n depth = line.depth;\n const open = fenceAt(text, line);\n if (open !== null) {\n const stop = fenceSpan(text, line, open);\n fences.push([i, stop]);\n paragraph = false;\n i = stop;\n continue;\n }\n const content = lineText(text, line);\n if (content.trim() === '') {\n paragraph = false;\n i = afterLine(text, line.end);\n continue;\n }\n const definition = paragraph ? null : definitionAt(text, line);\n if (definition !== null) {\n if (!definitions.has(definition.id)) definitions.set(definition.id, definition.occurrence);\n i = definition.next;\n continue;\n }\n paragraph = !endsBlock(content);\n i = afterLine(text, line.end);\n }\n return { fences, definitions };\n}\n\nfunction fenceEndAt(\n spans: readonly (readonly [number, number])[],\n index: number,\n): number | undefined {\n for (const [start, end] of spans) {\n if (index >= start && index < end) return end;\n }\n return undefined;\n}\n\nexport type HrefOccurrence = {\n readonly href: string;\n readonly start: number;\n readonly end: number;\n readonly bracketed: boolean;\n};\n\nexport function hrefOccurrences(body: string): readonly HrefOccurrence[] {\n const { fences, definitions } = scanBlocks(body);\n const found: HrefOccurrence[] = [];\n let i = 0;\n while (i < body.length) {\n const fenceEnd = fenceEndAt(fences, i);\n if (fenceEnd !== undefined) {\n i = fenceEnd;\n continue;\n }\n if (body[i] === '`') {\n i = skipInlineCode(body, i);\n continue;\n }\n if (body[i] === '!' && body[i + 1] === '[') {\n i = takeLink(body, i + 1, found, definitions);\n continue;\n }\n if (body[i] === '[') {\n i = takeLink(body, i, found, definitions);\n continue;\n }\n i += 1;\n }\n const byStart = new Map<number, HrefOccurrence>();\n for (const occurrence of found) byStart.set(occurrence.start, occurrence);\n return [...byStart.values()].sort((left, right) => left.start - right.start);\n}\n"],"names":["TAB_STOP","CLOSING_FENCE_INDENT","HEADING","BREAK","SETEXT","LABEL","DESTINATION","TITLE","endOfLine","text","from","nl","indexOf","length","afterLine","end","itemMarker","index","i","bullet","digits","delimiter","readLine","start","depth","item","inner","spaces","after","content","widthOf","to","width","afterIndent","line","indentWidth","lineText","raw","slice","endsWith","fenceRun","at","char","fenceAt","run","column","closesFence","open","indent","trim","leavesContainer","fenceSpan","cursor","next","skipInlineCode","ticks","close","repeat","skipLinkSpace","skipTitle","ch","destination","occurrence","href","bracketed","afterTitle","labelEnd","takeLink","found","defs","label","dest","push","id","toLowerCase","defined","get","undefined","definitionDestination","match","exec","span","indices","definitionAt","head","test","endsBlock","scanBlocks","fences","definitions","Map","paragraph","stop","definition","has","set","fenceEndAt","spans","hrefOccurrences","body","fenceEnd","byStart","values","sort","left","right"],"mappings":"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"}
|
package/dist/paths.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export declare function join(base: string, relative: string): string;
|
|
|
3
3
|
export declare function normalize(path: string): string | null;
|
|
4
4
|
export declare function isTypesPath(path: string): boolean;
|
|
5
5
|
export declare function typeNameFromPath(path: string): string;
|
|
6
|
+
export declare function hrefSuffix(href: string): string;
|
|
6
7
|
export declare function classifyHref(from: string, href: string): {
|
|
7
8
|
kind: 'skip';
|
|
8
9
|
} | {
|
package/dist/paths.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG5C;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYrD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAUzE"}
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG5C;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYrD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAUzE"}
|
package/dist/paths.js
CHANGED
|
@@ -26,6 +26,11 @@ export function typeNameFromPath(path) {
|
|
|
26
26
|
const base = path.slice(path.lastIndexOf('/') + 1);
|
|
27
27
|
return base.endsWith('.md') ? base.slice(0, -3) : base;
|
|
28
28
|
}
|
|
29
|
+
export function hrefSuffix(href) {
|
|
30
|
+
const trimmed = href.trim();
|
|
31
|
+
const match = /[?#]/.exec(trimmed);
|
|
32
|
+
return match === null ? '' : trimmed.slice(match.index);
|
|
33
|
+
}
|
|
29
34
|
export function classifyHref(from, href) {
|
|
30
35
|
const trimmed = href.trim();
|
|
31
36
|
if (trimmed === '' || trimmed.startsWith('#')) return {
|
package/dist/paths.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/workspace/packages/mdmodel/src/paths.ts"],"sourcesContent":["export function dirname(path: string): string {\n const index = path.lastIndexOf('/');\n return index === -1 ? '' : path.slice(0, index);\n}\n\nexport function join(base: string, relative: string): string {\n if (base === '') return relative;\n return `${base}/${relative}`;\n}\n\nexport function normalize(path: string): string | null {\n const parts: string[] = [];\n for (const part of path.split('/')) {\n if (part === '' || part === '.') continue;\n if (part === '..') {\n if (parts.length === 0) return null;\n parts.pop();\n continue;\n }\n parts.push(part);\n }\n return parts.join('/');\n}\n\nexport function isTypesPath(path: string): boolean {\n return path === 'types' || path.startsWith('types/');\n}\n\nexport function typeNameFromPath(path: string): string {\n const base = path.slice(path.lastIndexOf('/') + 1);\n return base.endsWith('.md') ? base.slice(0, -3) : base;\n}\n\nexport function classifyHref(\n from: string,\n href: string,\n): { kind: 'skip' } | { kind: 'path'; path: string } | { kind: 'invalid' } {\n const trimmed = href.trim();\n if (trimmed === '' || trimmed.startsWith('#')) return { kind: 'skip' };\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) return { kind: 'skip' };\n if (trimmed.startsWith('/')) return { kind: 'invalid' };\n const bare = trimmed.replace(/[?#].*$/, '');\n if (bare === '') return { kind: 'skip' };\n const resolved = normalize(join(dirname(from), bare));\n if (resolved === null || resolved === '') return { kind: 'invalid' };\n return { kind: 'path', path: resolved };\n}\n"],"names":["dirname","path","index","lastIndexOf","slice","join","base","relative","normalize","parts","part","split","length","pop","push","isTypesPath","startsWith","typeNameFromPath","endsWith","
|
|
1
|
+
{"version":3,"sources":["/workspace/packages/mdmodel/src/paths.ts"],"sourcesContent":["export function dirname(path: string): string {\n const index = path.lastIndexOf('/');\n return index === -1 ? '' : path.slice(0, index);\n}\n\nexport function join(base: string, relative: string): string {\n if (base === '') return relative;\n return `${base}/${relative}`;\n}\n\nexport function normalize(path: string): string | null {\n const parts: string[] = [];\n for (const part of path.split('/')) {\n if (part === '' || part === '.') continue;\n if (part === '..') {\n if (parts.length === 0) return null;\n parts.pop();\n continue;\n }\n parts.push(part);\n }\n return parts.join('/');\n}\n\nexport function isTypesPath(path: string): boolean {\n return path === 'types' || path.startsWith('types/');\n}\n\nexport function typeNameFromPath(path: string): string {\n const base = path.slice(path.lastIndexOf('/') + 1);\n return base.endsWith('.md') ? base.slice(0, -3) : base;\n}\n\nexport function hrefSuffix(href: string): string {\n const trimmed = href.trim();\n const match = /[?#]/.exec(trimmed);\n return match === null ? '' : trimmed.slice(match.index);\n}\n\nexport function classifyHref(\n from: string,\n href: string,\n): { kind: 'skip' } | { kind: 'path'; path: string } | { kind: 'invalid' } {\n const trimmed = href.trim();\n if (trimmed === '' || trimmed.startsWith('#')) return { kind: 'skip' };\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) return { kind: 'skip' };\n if (trimmed.startsWith('/')) return { kind: 'invalid' };\n const bare = trimmed.replace(/[?#].*$/, '');\n if (bare === '') return { kind: 'skip' };\n const resolved = normalize(join(dirname(from), bare));\n if (resolved === null || resolved === '') return { kind: 'invalid' };\n return { kind: 'path', path: resolved };\n}\n"],"names":["dirname","path","index","lastIndexOf","slice","join","base","relative","normalize","parts","part","split","length","pop","push","isTypesPath","startsWith","typeNameFromPath","endsWith","hrefSuffix","href","trimmed","trim","match","exec","classifyHref","from","kind","test","bare","replace","resolved"],"mappings":"AAAA,OAAO,SAASA,QAAQC,IAAY;IAClC,MAAMC,QAAQD,KAAKE,WAAW,CAAC;IAC/B,OAAOD,UAAU,CAAC,IAAI,KAAKD,KAAKG,KAAK,CAAC,GAAGF;AAC3C;AAEA,OAAO,SAASG,KAAKC,IAAY,EAAEC,QAAgB;IACjD,IAAID,SAAS,IAAI,OAAOC;IACxB,OAAO,GAAGD,KAAK,CAAC,EAAEC,UAAU;AAC9B;AAEA,OAAO,SAASC,UAAUP,IAAY;IACpC,MAAMQ,QAAkB,EAAE;IAC1B,KAAK,MAAMC,QAAQT,KAAKU,KAAK,CAAC,KAAM;QAClC,IAAID,SAAS,MAAMA,SAAS,KAAK;QACjC,IAAIA,SAAS,MAAM;YACjB,IAAID,MAAMG,MAAM,KAAK,GAAG,OAAO;YAC/BH,MAAMI,GAAG;YACT;QACF;QACAJ,MAAMK,IAAI,CAACJ;IACb;IACA,OAAOD,MAAMJ,IAAI,CAAC;AACpB;AAEA,OAAO,SAASU,YAAYd,IAAY;IACtC,OAAOA,SAAS,WAAWA,KAAKe,UAAU,CAAC;AAC7C;AAEA,OAAO,SAASC,iBAAiBhB,IAAY;IAC3C,MAAMK,OAAOL,KAAKG,KAAK,CAACH,KAAKE,WAAW,CAAC,OAAO;IAChD,OAAOG,KAAKY,QAAQ,CAAC,SAASZ,KAAKF,KAAK,CAAC,GAAG,CAAC,KAAKE;AACpD;AAEA,OAAO,SAASa,WAAWC,IAAY;IACrC,MAAMC,UAAUD,KAAKE,IAAI;IACzB,MAAMC,QAAQ,OAAOC,IAAI,CAACH;IAC1B,OAAOE,UAAU,OAAO,KAAKF,QAAQjB,KAAK,CAACmB,MAAMrB,KAAK;AACxD;AAEA,OAAO,SAASuB,aACdC,IAAY,EACZN,IAAY;IAEZ,MAAMC,UAAUD,KAAKE,IAAI;IACzB,IAAID,YAAY,MAAMA,QAAQL,UAAU,CAAC,MAAM,OAAO;QAAEW,MAAM;IAAO;IACrE,IAAI,4BAA4BC,IAAI,CAACP,UAAU,OAAO;QAAEM,MAAM;IAAO;IACrE,IAAIN,QAAQL,UAAU,CAAC,MAAM,OAAO;QAAEW,MAAM;IAAU;IACtD,MAAME,OAAOR,QAAQS,OAAO,CAAC,WAAW;IACxC,IAAID,SAAS,IAAI,OAAO;QAAEF,MAAM;IAAO;IACvC,MAAMI,WAAWvB,UAAUH,KAAKL,QAAQ0B,OAAOG;IAC/C,IAAIE,aAAa,QAAQA,aAAa,IAAI,OAAO;QAAEJ,MAAM;IAAU;IACnE,OAAO;QAAEA,MAAM;QAAQ1B,MAAM8B;IAAS;AACxC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export type Library = Readonly<Record<string, string>>;
|
|
2
|
+
export type ValidationContext = {
|
|
3
|
+
readonly binaryTargets: readonly string[];
|
|
4
|
+
};
|
|
2
5
|
export type Document = {
|
|
3
6
|
readonly content: string;
|
|
4
7
|
readonly type: string | undefined;
|
|
@@ -24,6 +27,10 @@ export type ParseResult = {
|
|
|
24
27
|
readonly ok: false;
|
|
25
28
|
readonly refusal: Refusal;
|
|
26
29
|
};
|
|
30
|
+
export type Link = {
|
|
31
|
+
readonly href: string;
|
|
32
|
+
readonly target: string;
|
|
33
|
+
};
|
|
27
34
|
export type Change = {
|
|
28
35
|
readonly kind: 'field';
|
|
29
36
|
readonly name: string;
|
|
@@ -34,6 +41,10 @@ export type Change = {
|
|
|
34
41
|
readonly name: string;
|
|
35
42
|
readonly value: string;
|
|
36
43
|
readonly prior: string;
|
|
44
|
+
} | {
|
|
45
|
+
readonly kind: 'link';
|
|
46
|
+
readonly href: string;
|
|
47
|
+
readonly to: string;
|
|
37
48
|
};
|
|
38
49
|
export type ApplyResult = {
|
|
39
50
|
readonly outcome: 'applied';
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEvD,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,GAC9B,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,GAAG,OAAO,CAAC,CAAC;AAE/C,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,MAAM,GACd;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEN,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEvD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,GAC9B,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,GAAG,OAAO,CAAC,CAAC;AAE/C,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,IAAI,GAAG;IACjB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,MAAM,GACd;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB,CAAC;AAEN,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/workspace/packages/mdmodel/src/types.ts"],"sourcesContent":["export type Library = Readonly<Record<string, string>>;\n\nexport type Document = {\n readonly content: string;\n readonly type: string | undefined;\n readonly fields: Readonly<Record<string, unknown>>;\n readonly sections: Readonly<Record<string, string>>;\n};\n\nexport type Refusal = {\n readonly file: string;\n readonly rule: string;\n readonly version: string;\n readonly location?: string;\n readonly referrers?: readonly string[];\n};\n\nexport type Validation =\n | { readonly verdict: 'accept' }\n | ({ readonly verdict: 'refuse' } & Refusal);\n\nexport type ParseResult =\n | { readonly ok: true; readonly document: Document }\n | { readonly ok: false; readonly refusal: Refusal };\n\nexport type Change =\n | {\n readonly kind: 'field';\n readonly name: string;\n readonly value: unknown;\n readonly prior: unknown;\n }\n | {\n readonly kind: 'section';\n readonly name: string;\n readonly value: string;\n readonly prior: string;\n };\n\nexport type ApplyResult =\n | { readonly outcome: 'applied'; readonly document: Document }\n | { readonly outcome: 'stale'; readonly document: Document }\n | { readonly outcome: 'refuse'; readonly refusal: Refusal };\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["/workspace/packages/mdmodel/src/types.ts"],"sourcesContent":["export type Library = Readonly<Record<string, string>>;\n\nexport type ValidationContext = {\n readonly binaryTargets: readonly string[];\n};\n\nexport type Document = {\n readonly content: string;\n readonly type: string | undefined;\n readonly fields: Readonly<Record<string, unknown>>;\n readonly sections: Readonly<Record<string, string>>;\n};\n\nexport type Refusal = {\n readonly file: string;\n readonly rule: string;\n readonly version: string;\n readonly location?: string;\n readonly referrers?: readonly string[];\n};\n\nexport type Validation =\n | { readonly verdict: 'accept' }\n | ({ readonly verdict: 'refuse' } & Refusal);\n\nexport type ParseResult =\n | { readonly ok: true; readonly document: Document }\n | { readonly ok: false; readonly refusal: Refusal };\n\nexport type Link = {\n readonly href: string;\n readonly target: string;\n};\n\nexport type Change =\n | {\n readonly kind: 'field';\n readonly name: string;\n readonly value: unknown;\n readonly prior: unknown;\n }\n | {\n readonly kind: 'section';\n readonly name: string;\n readonly value: string;\n readonly prior: string;\n }\n | {\n readonly kind: 'link';\n readonly href: string;\n readonly to: string;\n };\n\nexport type ApplyResult =\n | { readonly outcome: 'applied'; readonly document: Document }\n | { readonly outcome: 'stale'; readonly document: Document }\n | { readonly outcome: 'refuse'; readonly refusal: Refusal };\n"],"names":[],"mappings":"AAqDA,WAG8D"}
|
package/dist/validate.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { Library, Validation } from './types.js';
|
|
2
|
-
export declare function validate(library: Library): Validation;
|
|
1
|
+
import type { Library, Validation, ValidationContext } from './types.js';
|
|
2
|
+
export declare function validate(library: Library, context?: ValidationContext): Validation;
|
|
3
3
|
//# sourceMappingURL=validate.d.ts.map
|
package/dist/validate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAY,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAY,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAuCnF,wBAAgB,QAAQ,CACtB,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,iBAAyC,GACjD,UAAU,CAkHZ"}
|
package/dist/validate.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readDefinition } from './definition.js';
|
|
2
2
|
import { parse } from './document.js';
|
|
3
|
-
import {
|
|
3
|
+
import { hrefOccurrences } from './links.js';
|
|
4
4
|
import { classifyHref, isTypesPath } from './paths.js';
|
|
5
5
|
import { refusal } from './refuse.js';
|
|
6
6
|
import { parseListSection } from './sections.js';
|
|
@@ -38,10 +38,14 @@ function declaredTypeOf(content) {
|
|
|
38
38
|
if (!parsed.ok) return undefined;
|
|
39
39
|
return parsed.document.type ?? 'any';
|
|
40
40
|
}
|
|
41
|
-
export function validate(library
|
|
41
|
+
export function validate(library, context = {
|
|
42
|
+
binaryTargets: []
|
|
43
|
+
}) {
|
|
44
|
+
const binaryTargets = new Set(context.binaryTargets);
|
|
42
45
|
const files = Object.keys(library).sort();
|
|
43
46
|
const documents = new Map();
|
|
44
47
|
for (const file of files){
|
|
48
|
+
if (binaryTargets.has(file)) return refuse(file, 'binary-target-document');
|
|
45
49
|
const parsed = parse(library[file], file);
|
|
46
50
|
documents.set(file, parsed);
|
|
47
51
|
if (!parsed.ok) return {
|
|
@@ -114,10 +118,10 @@ export function validate(library) {
|
|
|
114
118
|
if (expected === null) continue;
|
|
115
119
|
for (const target of targets){
|
|
116
120
|
const resolved = classifyHref(file, target);
|
|
117
|
-
if (resolved.kind !== 'path') return refuse(file, 'unresolved-reference', {
|
|
121
|
+
if (resolved.kind !== 'path' || binaryTargets.has(resolved.path)) return refuse(file, 'unresolved-reference', {
|
|
118
122
|
location: name
|
|
119
123
|
});
|
|
120
|
-
if (!(resolved.path
|
|
124
|
+
if (!documents.has(resolved.path)) continue;
|
|
121
125
|
const targetType = declaredTypeOf(library[resolved.path]);
|
|
122
126
|
if (targetType !== expected) return refuse(file, 'unresolved-reference', {
|
|
123
127
|
location: name
|
|
@@ -125,10 +129,10 @@ export function validate(library) {
|
|
|
125
129
|
}
|
|
126
130
|
}
|
|
127
131
|
const body = bodyAfterFrontmatter(library[file]);
|
|
128
|
-
for (const
|
|
129
|
-
const resolved = classifyHref(file, href);
|
|
132
|
+
for (const occurrence of hrefOccurrences(body)){
|
|
133
|
+
const resolved = classifyHref(file, occurrence.href);
|
|
130
134
|
if (resolved.kind === 'skip') continue;
|
|
131
|
-
if (resolved.kind === 'invalid' || !(resolved.path
|
|
135
|
+
if (resolved.kind === 'invalid' || !documents.has(resolved.path) && !binaryTargets.has(resolved.path)) {
|
|
132
136
|
return refuse(file, 'unresolved-link');
|
|
133
137
|
}
|
|
134
138
|
}
|
|
@@ -147,7 +151,7 @@ export function validate(library) {
|
|
|
147
151
|
for (const target of referenceTargets(spec, parsed.document.fields[name])){
|
|
148
152
|
const resolved = classifyHref(file, target);
|
|
149
153
|
if (resolved.kind !== 'path') continue;
|
|
150
|
-
if (resolved.path
|
|
154
|
+
if (documents.has(resolved.path)) continue;
|
|
151
155
|
const referrers = missing.get(resolved.path) ?? [];
|
|
152
156
|
referrers.push(file);
|
|
153
157
|
missing.set(resolved.path, referrers);
|