@concordance-wiki/inference 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +15 -0
  3. package/dist/combine/confidence.d.ts +16 -0
  4. package/dist/combine/confidence.d.ts.map +1 -0
  5. package/dist/combine/confidence.js +24 -0
  6. package/dist/combine/confidence.js.map +1 -0
  7. package/dist/combine/links.d.ts +15 -0
  8. package/dist/combine/links.d.ts.map +1 -0
  9. package/dist/combine/links.js +0 -0
  10. package/dist/combine/links.js.map +1 -0
  11. package/dist/display/neighbourhood.d.ts +15 -0
  12. package/dist/display/neighbourhood.d.ts.map +1 -0
  13. package/dist/display/neighbourhood.js +83 -0
  14. package/dist/display/neighbourhood.js.map +1 -0
  15. package/dist/display/options.d.ts +5 -0
  16. package/dist/display/options.d.ts.map +1 -0
  17. package/dist/display/options.js +6 -0
  18. package/dist/display/options.js.map +1 -0
  19. package/dist/display/serialize.d.ts +7 -0
  20. package/dist/display/serialize.d.ts.map +1 -0
  21. package/dist/display/serialize.js +13 -0
  22. package/dist/display/serialize.js.map +1 -0
  23. package/dist/display/types.d.ts +44 -0
  24. package/dist/display/types.d.ts.map +1 -0
  25. package/dist/display/types.js +2 -0
  26. package/dist/display/types.js.map +1 -0
  27. package/dist/duplicates/content.d.ts +29 -0
  28. package/dist/duplicates/content.d.ts.map +1 -0
  29. package/dist/duplicates/content.js +42 -0
  30. package/dist/duplicates/content.js.map +1 -0
  31. package/dist/duplicates/lsh.d.ts +8 -0
  32. package/dist/duplicates/lsh.d.ts.map +1 -0
  33. package/dist/duplicates/lsh.js +38 -0
  34. package/dist/duplicates/lsh.js.map +1 -0
  35. package/dist/duplicates/minhash.d.ts +11 -0
  36. package/dist/duplicates/minhash.d.ts.map +1 -0
  37. package/dist/duplicates/minhash.js +51 -0
  38. package/dist/duplicates/minhash.js.map +1 -0
  39. package/dist/duplicates/options.d.ts +6 -0
  40. package/dist/duplicates/options.d.ts.map +1 -0
  41. package/dist/duplicates/options.js +23 -0
  42. package/dist/duplicates/options.js.map +1 -0
  43. package/dist/duplicates/resolve.d.ts +13 -0
  44. package/dist/duplicates/resolve.d.ts.map +1 -0
  45. package/dist/duplicates/resolve.js +257 -0
  46. package/dist/duplicates/resolve.js.map +1 -0
  47. package/dist/duplicates/score.d.ts +22 -0
  48. package/dist/duplicates/score.d.ts.map +1 -0
  49. package/dist/duplicates/score.js +190 -0
  50. package/dist/duplicates/score.js.map +1 -0
  51. package/dist/duplicates/shingles.d.ts +15 -0
  52. package/dist/duplicates/shingles.d.ts.map +1 -0
  53. package/dist/duplicates/shingles.js +35 -0
  54. package/dist/duplicates/shingles.js.map +1 -0
  55. package/dist/duplicates/similarity.d.ts +23 -0
  56. package/dist/duplicates/similarity.d.ts.map +1 -0
  57. package/dist/duplicates/similarity.js +86 -0
  58. package/dist/duplicates/similarity.js.map +1 -0
  59. package/dist/duplicates/types.d.ts +97 -0
  60. package/dist/duplicates/types.d.ts.map +1 -0
  61. package/dist/duplicates/types.js +2 -0
  62. package/dist/duplicates/types.js.map +1 -0
  63. package/dist/explicit/links.d.ts +30 -0
  64. package/dist/explicit/links.d.ts.map +1 -0
  65. package/dist/explicit/links.js +173 -0
  66. package/dist/explicit/links.js.map +1 -0
  67. package/dist/explicit/types.d.ts +35 -0
  68. package/dist/explicit/types.d.ts.map +1 -0
  69. package/dist/explicit/types.js +2 -0
  70. package/dist/explicit/types.js.map +1 -0
  71. package/dist/frontmatter/links.d.ts +21 -0
  72. package/dist/frontmatter/links.d.ts.map +1 -0
  73. package/dist/frontmatter/links.js +131 -0
  74. package/dist/frontmatter/links.js.map +1 -0
  75. package/dist/frontmatter/resolve.d.ts +32 -0
  76. package/dist/frontmatter/resolve.d.ts.map +1 -0
  77. package/dist/frontmatter/resolve.js +62 -0
  78. package/dist/frontmatter/resolve.js.map +1 -0
  79. package/dist/index.d.ts +26 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +19 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/mentions/links.d.ts +43 -0
  84. package/dist/mentions/links.d.ts.map +1 -0
  85. package/dist/mentions/links.js +106 -0
  86. package/dist/mentions/links.js.map +1 -0
  87. package/dist/mentions/sections.d.ts +17 -0
  88. package/dist/mentions/sections.d.ts.map +1 -0
  89. package/dist/mentions/sections.js +26 -0
  90. package/dist/mentions/sections.js.map +1 -0
  91. package/dist/neighbourhood/accumulate.d.ts +11 -0
  92. package/dist/neighbourhood/accumulate.d.ts.map +1 -0
  93. package/dist/neighbourhood/accumulate.js +73 -0
  94. package/dist/neighbourhood/accumulate.js.map +1 -0
  95. package/dist/neighbourhood/links.d.ts +13 -0
  96. package/dist/neighbourhood/links.d.ts.map +1 -0
  97. package/dist/neighbourhood/links.js +35 -0
  98. package/dist/neighbourhood/links.js.map +1 -0
  99. package/dist/neighbourhood/options.d.ts +5 -0
  100. package/dist/neighbourhood/options.d.ts.map +1 -0
  101. package/dist/neighbourhood/options.js +6 -0
  102. package/dist/neighbourhood/options.js.map +1 -0
  103. package/dist/neighbourhood/order.d.ts +5 -0
  104. package/dist/neighbourhood/order.d.ts.map +1 -0
  105. package/dist/neighbourhood/order.js +9 -0
  106. package/dist/neighbourhood/order.js.map +1 -0
  107. package/dist/neighbourhood/serialize.d.ts +4 -0
  108. package/dist/neighbourhood/serialize.d.ts.map +1 -0
  109. package/dist/neighbourhood/serialize.js +10 -0
  110. package/dist/neighbourhood/serialize.js.map +1 -0
  111. package/dist/neighbourhood/types.d.ts +24 -0
  112. package/dist/neighbourhood/types.d.ts.map +1 -0
  113. package/dist/neighbourhood/types.js +2 -0
  114. package/dist/neighbourhood/types.js.map +1 -0
  115. package/dist/operations/index.d.ts +30 -0
  116. package/dist/operations/index.d.ts.map +1 -0
  117. package/dist/operations/index.js +118 -0
  118. package/dist/operations/index.js.map +1 -0
  119. package/dist/operations/match.d.ts +64 -0
  120. package/dist/operations/match.d.ts.map +1 -0
  121. package/dist/operations/match.js +251 -0
  122. package/dist/operations/match.js.map +1 -0
  123. package/dist/operations/merge.d.ts +14 -0
  124. package/dist/operations/merge.d.ts.map +1 -0
  125. package/dist/operations/merge.js +60 -0
  126. package/dist/operations/merge.js.map +1 -0
  127. package/dist/relations/index.d.ts +3 -0
  128. package/dist/relations/index.d.ts.map +1 -0
  129. package/dist/relations/index.js +3 -0
  130. package/dist/relations/index.js.map +1 -0
  131. package/dist/relations/labels.d.ts +14 -0
  132. package/dist/relations/labels.d.ts.map +1 -0
  133. package/dist/relations/labels.js +22 -0
  134. package/dist/relations/labels.js.map +1 -0
  135. package/dist/relations/type.d.ts +40 -0
  136. package/dist/relations/type.d.ts.map +1 -0
  137. package/dist/relations/type.js +161 -0
  138. package/dist/relations/type.js.map +1 -0
  139. package/package.json +46 -0
@@ -0,0 +1,86 @@
1
+ const combiningMarks = /\p{M}+/gu;
2
+ const separators = /[^\p{L}\p{N}]+/gu;
3
+ /** The form base names and titles are compared on: lowercase, accents stripped, punctuation folded to spaces. */
4
+ export function comparisonKey(text) {
5
+ return text
6
+ .normalize("NFD")
7
+ .replace(combiningMarks, "")
8
+ .toLowerCase()
9
+ .replace(separators, " ")
10
+ .trim();
11
+ }
12
+ // Code units rather than code points: base names are compared by the thousands and the keys are already folded.
13
+ function jaro(a, b) {
14
+ const window = Math.max(0, Math.floor(Math.max(a.length, b.length) / 2) - 1);
15
+ const matchedA = new Uint8Array(a.length);
16
+ const matchedB = new Uint8Array(b.length);
17
+ let matches = 0;
18
+ for (let index = 0; index < a.length; index++) {
19
+ const code = a.charCodeAt(index);
20
+ const end = Math.min(index + window + 1, b.length);
21
+ for (let other = Math.max(0, index - window); other < end; other++) {
22
+ if (matchedB[other] === 1 || b.charCodeAt(other) !== code)
23
+ continue;
24
+ matchedA[index] = 1;
25
+ matchedB[other] = 1;
26
+ matches++;
27
+ break;
28
+ }
29
+ }
30
+ if (matches === 0)
31
+ return 0;
32
+ let transpositions = 0;
33
+ let other = 0;
34
+ for (let index = 0; index < a.length; index++) {
35
+ if (matchedA[index] !== 1)
36
+ continue;
37
+ while (matchedB[other] !== 1)
38
+ other++;
39
+ if (a.charCodeAt(index) !== b.charCodeAt(other))
40
+ transpositions++;
41
+ other++;
42
+ }
43
+ return (matches / a.length + matches / b.length + (matches - transpositions / 2) / matches) / 3;
44
+ }
45
+ /** Jaro similarity with the Winkler bonus for a common prefix of up to four characters. */
46
+ export function jaroWinkler(a, b) {
47
+ const similarity = jaro(a, b);
48
+ let prefix = 0;
49
+ // Past the end of either string the code unit is NaN, which never compares equal.
50
+ while (prefix < 4 && a.charCodeAt(prefix) === b.charCodeAt(prefix))
51
+ prefix++;
52
+ return similarity + prefix * 0.1 * (1 - similarity);
53
+ }
54
+ export function nameProfile(key) {
55
+ const counts = new DataView(new ArrayBuffer(32));
56
+ let classes = 0;
57
+ for (let index = 0; index < key.length; index++) {
58
+ const unitClass = key.charCodeAt(index) & 31;
59
+ counts.setUint8(unitClass, counts.getUint8(unitClass) + 1);
60
+ classes |= 1 << unitClass;
61
+ }
62
+ return { key, counts, classes };
63
+ }
64
+ /**
65
+ * An upper bound of the code units two names have in common: their counts merged by class, since
66
+ * a minimum of sums is at least a sum of minimums. Walks the shared classes only.
67
+ */
68
+ export function sharedCodeUnits(a, b) {
69
+ let shared = 0;
70
+ for (let remaining = a.classes & b.classes; remaining !== 0;) {
71
+ const unitClass = 31 - Math.clz32(remaining);
72
+ remaining ^= 1 << unitClass;
73
+ shared += Math.min(a.counts.getUint8(unitClass), b.counts.getUint8(unitClass));
74
+ }
75
+ return shared;
76
+ }
77
+ /** Depth of the common prefix over the deeper folder, 1 for the same folder; the root has depth 0. */
78
+ export function directoryProximity(a, b) {
79
+ const segmentsA = a.split("/");
80
+ const segmentsB = b.split("/");
81
+ let common = 0;
82
+ while (common < segmentsA.length && segmentsA[common] === segmentsB[common])
83
+ common++;
84
+ return common / Math.max(segmentsA.length, segmentsB.length);
85
+ }
86
+ //# sourceMappingURL=similarity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"similarity.js","sourceRoot":"","sources":["../../src/duplicates/similarity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ import type { Clock, Finding } from "@concordance-wiki/core";
2
+ /** What the reconciliation needs of a resource; `text` is extracted text, never binary content. */
3
+ export interface DuplicateResource {
4
+ /** Unique per resource; the lock file names resources by it. */
5
+ id: string;
6
+ source: string;
7
+ /** Forward-slash path relative to the source root. */
8
+ path: string;
9
+ /** Folder part of `path`, empty at the root. */
10
+ folder: string;
11
+ /** File name without its extension. */
12
+ baseName: string;
13
+ /** Document property, as a reader plugin reports it. */
14
+ title?: string;
15
+ /** First level-one heading of a markdown note. */
16
+ heading?: string;
17
+ /** Frontmatter `source`: the twin a note declares, relative to its folder or `<source>:<path>`. */
18
+ declaredSource?: string;
19
+ commit?: string;
20
+ text: string;
21
+ }
22
+ export type DuplicateMode = "estimate" | "exact" | "auto";
23
+ export interface DuplicateOptions {
24
+ mode: DuplicateMode;
25
+ /** Estimated Jaccard from which `auto` recomputes the exact one. */
26
+ exactAbove: number;
27
+ /** Word-count ratio under which the content signal is capped at the lower weight. */
28
+ sizeRatioMin: number;
29
+ shingleSize: number;
30
+ minhashFunctions: number;
31
+ /** Strictly above: merged. */
32
+ mergeAbove: number;
33
+ /** At least: a `W-DUP-CANDIDATE` finding. */
34
+ candidateAbove: number;
35
+ }
36
+ /** Ordered pairs of resource identifiers, as `duplicates.merged` and `duplicates.separated` of the lock file. */
37
+ export interface DuplicateLock {
38
+ merged?: readonly (readonly [string, string])[];
39
+ separated?: readonly (readonly [string, string])[];
40
+ }
41
+ export interface DuplicateInput {
42
+ resources: readonly DuplicateResource[];
43
+ /** The words of a text in comparison form, stopwords removed; the language pack of the source provides it. */
44
+ normalizeText: (text: string) => string[];
45
+ lock?: DuplicateLock;
46
+ /** Measures the time spent; without it the statistics report zero. */
47
+ clock?: Clock;
48
+ }
49
+ /** One contribution to the score of a pair. */
50
+ export interface DuplicateSignal {
51
+ name: "declared" | "same_name" | "similar_name" | "same_title" | "similar_content" | "same_commit" | "same_directory";
52
+ weight: number;
53
+ /** Named in the finding message next to the weight. */
54
+ detail: string;
55
+ }
56
+ export interface DuplicatePair {
57
+ /** The lower identifier. */
58
+ a: string;
59
+ b: string;
60
+ /** Sum of the signal weights, capped at 1 and rounded to four decimals. */
61
+ score: number;
62
+ /** By weight then by name, so that the first one names the grouping criterion. */
63
+ signals: DuplicateSignal[];
64
+ }
65
+ export interface DuplicateRepresentation {
66
+ id: string;
67
+ path: string;
68
+ /** `markdown` for a note, otherwise the lowercase extension, `file` without one. */
69
+ format: string;
70
+ }
71
+ /** Several resources merged into one entity. */
72
+ export interface DuplicateGroup {
73
+ /** The identifier of the markdown representation, or the lowest identifier without one. */
74
+ id: string;
75
+ representations: DuplicateRepresentation[];
76
+ /** What grouped the resources, for the page to name it. */
77
+ criterion: string;
78
+ }
79
+ export interface DuplicateStats {
80
+ resources: number;
81
+ /** Pairs enumerated by the LSH banding, the only ones whose content is compared. */
82
+ candidatePairs: number;
83
+ /** Pairs whose signals were scored: brought together by their content, a base name, a title or a declaration, and not separated by the lock. */
84
+ scoredPairs: number;
85
+ exactVerifications: number;
86
+ merged: number;
87
+ candidates: number;
88
+ timeMs: number;
89
+ }
90
+ export interface DuplicateResult {
91
+ groups: DuplicateGroup[];
92
+ findings: Finding[];
93
+ /** Every scored pair, at or above `candidateAbove`, by identifiers. */
94
+ pairs: DuplicatePair[];
95
+ stats: DuplicateStats;
96
+ }
97
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/duplicates/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/duplicates/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,30 @@
1
+ import type { ExplicitLinksInput, ExplicitLinksResult, LinkableEntity } from "./types.js";
2
+ /** The files of every source, by source name. */
3
+ export type SourceFiles = ReadonlyMap<string, ReadonlySet<string>>;
4
+ /** Where a written link lands: a file of a source, another source when cross-source links are off, nothing, or the web. */
5
+ export type LocatedLink = {
6
+ kind: "external";
7
+ } | {
8
+ kind: "denied";
9
+ source: string;
10
+ } | {
11
+ kind: "missing";
12
+ } | {
13
+ kind: "file";
14
+ source: string;
15
+ path: string;
16
+ anchor?: string;
17
+ };
18
+ /**
19
+ * The file a link target reaches from a note: in its own source, in a source named as a prefix
20
+ * or reached as a sibling folder when cross-source links are on.
21
+ */
22
+ export declare function locateLink(target: string, from: Pick<LinkableEntity["source"], "name" | "path">, files: SourceFiles, crossSource: boolean): LocatedLink;
23
+ /**
24
+ * Markdown links are the strongest relation the tool knows: every link written in a note gives a
25
+ * link at the confidence of `explicit_link`, with the file, the line and the text as provenance. A
26
+ * link to another note is `related` until the relation typing step names it from the type pair; a
27
+ * link to a non-markdown file is `documents`, from the resource to the note.
28
+ */
29
+ export declare function explicitLinks(input: ExplicitLinksInput): ExplicitLinksResult;
30
+ //# sourceMappingURL=links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../src/explicit/links.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE1F,iDAAiD;AACjD,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;AASnE,2HAA2H;AAC3H,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAsCpE;;;GAGG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,EACrD,KAAK,EAAE,WAAW,EAClB,WAAW,EAAE,OAAO,GACnB,WAAW,CAsBb;AAkFD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,mBAAmB,CAoC5E"}
@@ -0,0 +1,173 @@
1
+ import { compareFindings, compareLinks, compareProvenances, identifierFor, } from "@concordance-wiki/core";
2
+ import { resolveLink } from "@concordance-wiki/ingest";
3
+ const NO_FILES = new Set();
4
+ function fileKey(source, path) {
5
+ return `${source}/${path}`;
6
+ }
7
+ function anchorOf(anchor) {
8
+ return anchor === undefined ? {} : { anchor };
9
+ }
10
+ function inSource(source, path, anchor) {
11
+ return { kind: "file", source, path, ...anchorOf(anchor) };
12
+ }
13
+ /** `<source>:<path>` names another source; any other prefix is a URL scheme left to `resolveLink`. */
14
+ function prefixedSource(target, files) {
15
+ const colon = target.indexOf(":");
16
+ if (colon === -1)
17
+ return undefined;
18
+ const source = target.slice(0, colon);
19
+ const sourceFiles = files.get(source);
20
+ return sourceFiles === undefined
21
+ ? undefined
22
+ : { source, rest: target.slice(colon + 1), sourceFiles };
23
+ }
24
+ /**
25
+ * A relative link that climbs one level above the source root and lands in `<source>/<path>` reaches
26
+ * a sibling source: the sources of one repository are often sibling folders.
27
+ */
28
+ function siblingSource(path, files) {
29
+ const [up, source, ...rest] = path.split("/");
30
+ if (up !== ".." || source === undefined || rest.length === 0)
31
+ return undefined;
32
+ const sourceFiles = files.get(source);
33
+ return sourceFiles === undefined ? undefined : { source, rest: rest.join("/"), sourceFiles };
34
+ }
35
+ /**
36
+ * The file a link target reaches from a note: in its own source, in a source named as a prefix
37
+ * or reached as a sibling folder when cross-source links are on.
38
+ */
39
+ export function locateLink(target, from, files, crossSource) {
40
+ const prefixed = prefixedSource(target, files);
41
+ if (prefixed !== undefined) {
42
+ if (!crossSource)
43
+ return { kind: "denied", source: prefixed.source };
44
+ const resolved = resolveLink(prefixed.rest, { path: "", sourceFiles: prefixed.sourceFiles });
45
+ // An empty path resolves to the linking file, which is never a file of the other source.
46
+ return resolved.kind === "internal" && prefixed.sourceFiles.has(resolved.path)
47
+ ? inSource(prefixed.source, resolved.path, resolved.anchor)
48
+ : { kind: "missing" };
49
+ }
50
+ const resolved = resolveLink(target, {
51
+ path: from.path,
52
+ sourceFiles: files.get(from.name) ?? NO_FILES,
53
+ });
54
+ if (resolved.kind === "external")
55
+ return { kind: "external" };
56
+ if (resolved.kind === "internal")
57
+ return inSource(from.name, resolved.path, resolved.anchor);
58
+ const sibling = siblingSource(resolved.path, files);
59
+ if (sibling === undefined)
60
+ return { kind: "missing" };
61
+ if (!crossSource)
62
+ return { kind: "denied", source: sibling.source };
63
+ return sibling.sourceFiles.has(sibling.rest)
64
+ ? inSource(sibling.source, sibling.rest, resolved.anchor)
65
+ : { kind: "missing" };
66
+ }
67
+ function brokenLink(entity, link) {
68
+ return {
69
+ check: "E-LINK-BROKEN",
70
+ severity: "error",
71
+ source: entity.source.name,
72
+ path: entity.source.path,
73
+ line: link.line,
74
+ entity: entity.id,
75
+ message: `link "${link.target}" in ${entity.source.path} points to no file of source ${entity.source.name}`,
76
+ remediation: "Fix the path; the linter rewrites the link under --fix when exactly one file matches the old name.",
77
+ };
78
+ }
79
+ function crossSourceLink(entity, link, source) {
80
+ return {
81
+ check: "W-LINK-CROSS-SOURCE",
82
+ severity: "warning",
83
+ source: entity.source.name,
84
+ path: entity.source.path,
85
+ line: link.line,
86
+ entity: entity.id,
87
+ message: `link "${link.target}" in ${entity.source.path} leaves source ${entity.source.name} for source ${source}; cross-source links are disabled`,
88
+ remediation: "Set inference.cross_source_links to true in concordance.yaml to resolve links across sources, or link to a note of the same source.",
89
+ };
90
+ }
91
+ function outcomeOf(entity, link, context) {
92
+ const target = locateLink(link.target, entity.source, context.files, context.crossSource);
93
+ if (target.kind === "denied")
94
+ return { finding: crossSourceLink(entity, link, target.source) };
95
+ if (target.kind === "missing")
96
+ return { finding: brokenLink(entity, link) };
97
+ if (target.kind === "external")
98
+ return undefined;
99
+ const provenance = {
100
+ method: "explicit_link",
101
+ confidence: context.confidence,
102
+ path: entity.source.path,
103
+ line: link.line,
104
+ text: link.text,
105
+ ...anchorOf(target.anchor),
106
+ };
107
+ if (!target.path.endsWith(".md")) {
108
+ // The resource entities are named from their path alone, so the same derivation finds them.
109
+ const resource = identifierFor({ source: target.source, path: target.path, typeSuffixes: [] });
110
+ return { from: resource.id, to: entity.id, relation: "documents", provenance };
111
+ }
112
+ const to = context.entities.get(fileKey(target.source, target.path));
113
+ if (to === undefined || to.id === entity.id)
114
+ return undefined;
115
+ // A written link says that two notes are related, not how: the relation typing step names it.
116
+ return { from: entity.id, to: to.id, relation: "related", provenance };
117
+ }
118
+ /** Several links to the same target keep every provenance; combining their confidences is a later step. */
119
+ function record(merged, found, confidence) {
120
+ const { from, to, relation, provenance } = found;
121
+ const key = `${from} ${to} ${relation}`;
122
+ const existing = merged.get(key);
123
+ if (existing === undefined) {
124
+ merged.set(key, { from, to, relation, attributes: {}, confidence, provenance: [provenance] });
125
+ }
126
+ else {
127
+ existing.provenance.push(provenance);
128
+ }
129
+ }
130
+ /**
131
+ * Markdown links are the strongest relation the tool knows: every link written in a note gives a
132
+ * link at the confidence of `explicit_link`, with the file, the line and the text as provenance. A
133
+ * link to another note is `related` until the relation typing step names it from the type pair; a
134
+ * link to a non-markdown file is `documents`, from the resource to the note.
135
+ */
136
+ export function explicitLinks(input) {
137
+ const confidence = input.profile.confidence.explicit_link ?? 1;
138
+ const files = new Map();
139
+ for (const resource of input.resources) {
140
+ const paths = files.get(resource.source) ?? new Set();
141
+ paths.add(resource.path);
142
+ files.set(resource.source, paths);
143
+ }
144
+ const entities = new Map(input.entities.map((entity) => [fileKey(entity.source.name, entity.source.path), entity]));
145
+ const context = {
146
+ entities,
147
+ files,
148
+ crossSource: input.inference?.cross_source_links ?? false,
149
+ confidence,
150
+ };
151
+ const merged = new Map();
152
+ const findings = [];
153
+ for (const [key, document] of input.documents) {
154
+ const entity = entities.get(key);
155
+ if (entity === undefined)
156
+ continue;
157
+ for (const link of document.links) {
158
+ const outcome = outcomeOf(entity, link, context);
159
+ if (outcome === undefined)
160
+ continue;
161
+ if ("finding" in outcome) {
162
+ findings.push(outcome.finding);
163
+ continue;
164
+ }
165
+ record(merged, outcome, confidence);
166
+ }
167
+ }
168
+ const links = [...merged.values()].sort(compareLinks);
169
+ for (const link of links)
170
+ link.provenance.sort(compareProvenances);
171
+ return { links, findings: findings.toSorted(compareFindings) };
172
+ }
173
+ //# sourceMappingURL=links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.js","sourceRoot":"","sources":["../../src/explicit/links.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { Finding, InferenceConfig, Link } from "@concordance-wiki/core";
2
+ import type { ParsedMarkdown } from "@concordance-wiki/ingest";
3
+ import type { Profile } from "@concordance-wiki/profile";
4
+ /** What inference needs of a typed entity: its identifier, its type, its title, its frontmatter and the file it comes from. */
5
+ export interface LinkableEntity {
6
+ id: string;
7
+ type: string;
8
+ title: string;
9
+ /** Frontmatter keys that are not common attributes; references are raw strings or lists of strings. */
10
+ attributes: Record<string, unknown>;
11
+ source: {
12
+ name: string;
13
+ /** Forward-slash path relative to the source root. */
14
+ path: string;
15
+ };
16
+ }
17
+ /** Every ingested file of every source, markdown or not. */
18
+ export interface SourceResource {
19
+ source: string;
20
+ /** Forward-slash path relative to the source root. */
21
+ path: string;
22
+ }
23
+ export interface ExplicitLinksInput {
24
+ entities: readonly LinkableEntity[];
25
+ resources: readonly SourceResource[];
26
+ /** Parsed markdown files keyed by `<source name>/<path>`. */
27
+ documents: ReadonlyMap<string, ParsedMarkdown>;
28
+ profile: Profile;
29
+ inference?: InferenceConfig;
30
+ }
31
+ export interface ExplicitLinksResult {
32
+ links: Link[];
33
+ findings: Finding[];
34
+ }
35
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/explicit/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAEzD,+HAA+H;AAC/H,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,uGAAuG;IACvG,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,sDAAsD;QACtD,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,4DAA4D;AAC5D,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IACpC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;IACrC,6DAA6D;IAC7D,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/explicit/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import { type Finding, type Link } from "@concordance-wiki/core";
2
+ import type { Profile } from "@concordance-wiki/profile";
3
+ import type { LinkableEntity } from "../explicit/types.js";
4
+ export interface FrontmatterLinksInput {
5
+ entities: readonly LinkableEntity[];
6
+ profile: Profile;
7
+ /** Overrides `confidence.frontmatter_ref` of the profile. */
8
+ confidence?: number;
9
+ }
10
+ export interface FrontmatterLinksResult {
11
+ links: Link[];
12
+ findings: Finding[];
13
+ }
14
+ /**
15
+ * A reference-typed attribute with a relation in the profile turns each of its values into a link of
16
+ * that relation, carrying the attributes the profile declares, such as `accesses` in `read` mode for
17
+ * `reads`. A value that resolves to nothing or to several titles is reported and gives no link; a
18
+ * note of a type the attribute does not accept gives its link, for the relation typing step to judge.
19
+ */
20
+ export declare function frontmatterLinks(input: FrontmatterLinksInput): FrontmatterLinksResult;
21
+ //# sourceMappingURL=links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../src/frontmatter/links.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,OAAO,EACZ,KAAK,IAAI,EAEV,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAuB,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAE9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AA+ID;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,sBAAsB,CAsBrF"}
@@ -0,0 +1,131 @@
1
+ import { compareFindings, compareLinks, } from "@concordance-wiki/core";
2
+ import { indexEntities, resolveReference } from "./resolve.js";
3
+ /** The confidence the specification gives the method when the profile is silent. */
4
+ const DEFAULT_CONFIDENCE = 0.9;
5
+ const REMEDIATION = "Write the identifier, the path relative to the source root or the exact title of an existing note, or remove the reference.";
6
+ function isReference(definition) {
7
+ return ((definition.type === "ref" || definition.type === "ref[]") && definition.relation !== undefined);
8
+ }
9
+ // Code-unit order, not locale order: the output must not depend on the collation data of the runtime.
10
+ function byCodeUnit(a, b) {
11
+ return Number(a > b) - Number(a < b);
12
+ }
13
+ function canonical(attributes) {
14
+ return JSON.stringify(Object.keys(attributes)
15
+ .sort(byCodeUnit)
16
+ .map((key) => [key, attributes[key]]));
17
+ }
18
+ function unresolved(reference, message) {
19
+ const { entity, attribute } = reference;
20
+ return {
21
+ check: "W-REF-UNRESOLVED",
22
+ severity: "warning",
23
+ source: entity.source.name,
24
+ path: entity.source.path,
25
+ line: 1,
26
+ entity: entity.id,
27
+ message: `${message} in attribute ${attribute} of ${entity.source.path}`,
28
+ remediation: REMEDIATION,
29
+ };
30
+ }
31
+ /**
32
+ * The note a value names, whatever its type: a reference to an existing note of a type the relation
33
+ * does not admit is a link outside the profile matrix, which the relation typing step drops with
34
+ * `E-META-REL`, not an unresolved reference.
35
+ */
36
+ function targetOf(value, reference, index) {
37
+ const resolution = resolveReference(value, { from: reference.entity, index });
38
+ if (resolution.kind === "unresolved") {
39
+ return {
40
+ finding: unresolved(reference, `reference "${value}" matches no identifier, path or title`),
41
+ };
42
+ }
43
+ if (resolution.kind === "ambiguous") {
44
+ const candidates = resolution.candidates.map((candidate) => candidate.id).join(", ");
45
+ return {
46
+ finding: unresolved(reference, `reference "${value}" is the title of several notes (${candidates})`),
47
+ };
48
+ }
49
+ return { target: resolution.entity };
50
+ }
51
+ function record(collector, reference, target) {
52
+ const { entity, attribute, definition } = reference;
53
+ const { relation } = definition;
54
+ const [from, to] = definition.inverse === true ? [target.id, entity.id] : [entity.id, target.id];
55
+ const attributes = { ...definition.attributes };
56
+ const serialised = canonical(attributes);
57
+ const provenance = {
58
+ method: "frontmatter_ref",
59
+ confidence: collector.confidence,
60
+ path: entity.source.path,
61
+ line: 1,
62
+ attribute,
63
+ };
64
+ const key = `${from} ${to} ${relation} ${serialised}`;
65
+ const existing = collector.merged.get(key);
66
+ if (existing === undefined) {
67
+ collector.merged.set(key, {
68
+ link: {
69
+ from,
70
+ to,
71
+ relation,
72
+ attributes,
73
+ confidence: collector.confidence,
74
+ provenance: [provenance],
75
+ },
76
+ attributes: serialised,
77
+ });
78
+ }
79
+ else {
80
+ // Several references to one target keep every provenance; combining their confidences is a later step.
81
+ existing.link.provenance.push(provenance);
82
+ }
83
+ }
84
+ /** Every value of one reference attribute: a string names a note, anything else is reported. */
85
+ function collect(collector, reference, raw) {
86
+ const values = Array.isArray(raw) ? raw : [raw];
87
+ for (const value of values) {
88
+ if (typeof value !== "string") {
89
+ const detail = `value ${JSON.stringify(value)} is neither a string nor a list of strings`;
90
+ collector.findings.push(unresolved(reference, detail));
91
+ continue;
92
+ }
93
+ const resolved = targetOf(value, reference, collector.index);
94
+ if ("finding" in resolved) {
95
+ collector.findings.push(resolved.finding);
96
+ }
97
+ else if (resolved.target.id !== reference.entity.id) {
98
+ record(collector, reference, resolved.target);
99
+ }
100
+ }
101
+ }
102
+ /**
103
+ * A reference-typed attribute with a relation in the profile turns each of its values into a link of
104
+ * that relation, carrying the attributes the profile declares, such as `accesses` in `read` mode for
105
+ * `reads`. A value that resolves to nothing or to several titles is reported and gives no link; a
106
+ * note of a type the attribute does not accept gives its link, for the relation typing step to judge.
107
+ */
108
+ export function frontmatterLinks(input) {
109
+ const { entities, profile } = input;
110
+ const collector = {
111
+ index: indexEntities(entities),
112
+ confidence: input.confidence ?? profile.confidence.frontmatter_ref ?? DEFAULT_CONFIDENCE,
113
+ merged: new Map(),
114
+ findings: [],
115
+ };
116
+ for (const entity of entities) {
117
+ const declared = profile.types[entity.type]?.attributes ?? {};
118
+ for (const [attribute, definition] of Object.entries(declared)) {
119
+ const raw = entity.attributes[attribute];
120
+ if (!isReference(definition) || raw === undefined)
121
+ continue;
122
+ collect(collector, { entity, attribute, definition }, raw);
123
+ }
124
+ }
125
+ // The provenances of one link all come from one note, at line 1: they are already in canonical order.
126
+ const links = [...collector.merged.values()]
127
+ .sort((a, b) => compareLinks(a.link, b.link) || byCodeUnit(a.attributes, b.attributes))
128
+ .map((entry) => entry.link);
129
+ return { links, findings: collector.findings.toSorted(compareFindings) };
130
+ }
131
+ //# sourceMappingURL=links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.js","sourceRoot":"","sources":["../../src/frontmatter/links.ts"],"names":[],"mappings":"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"}