lens-content-processor 0.79.0 → 0.80.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 (130) hide show
  1. package/dist/authoring-markup.d.ts +22 -0
  2. package/dist/authoring-markup.js +24 -0
  3. package/dist/authoring-markup.js.map +1 -1
  4. package/dist/cache.d.ts +10 -0
  5. package/dist/cache.js +6 -5
  6. package/dist/cache.js.map +1 -1
  7. package/dist/cli-steps.d.ts +37 -0
  8. package/dist/cli-steps.js +80 -0
  9. package/dist/cli-steps.js.map +1 -0
  10. package/dist/cli.d.ts +7 -0
  11. package/dist/cli.js +52 -70
  12. package/dist/cli.js.map +1 -1
  13. package/dist/course-graph.d.ts +2 -2
  14. package/dist/course-graph.js +7 -2
  15. package/dist/course-graph.js.map +1 -1
  16. package/dist/criticmarkup-forms.d.ts +8 -6
  17. package/dist/criticmarkup-forms.js +22 -19
  18. package/dist/criticmarkup-forms.js.map +1 -1
  19. package/dist/dedupe-errors.d.ts +16 -0
  20. package/dist/dedupe-errors.js +23 -9
  21. package/dist/dedupe-errors.js.map +1 -1
  22. package/dist/dependency-cache.d.ts +15 -5
  23. package/dist/dependency-cache.js +33 -74
  24. package/dist/dependency-cache.js.map +1 -1
  25. package/dist/dropped.d.ts +114 -0
  26. package/dist/dropped.js +253 -0
  27. package/dist/dropped.js.map +1 -0
  28. package/dist/engine/assemble.d.ts +44 -0
  29. package/dist/engine/assemble.js +132 -0
  30. package/dist/engine/assemble.js.map +1 -0
  31. package/dist/engine/build.d.ts +8 -0
  32. package/dist/engine/build.js +558 -0
  33. package/dist/engine/build.js.map +1 -0
  34. package/dist/engine/file-facts.d.ts +26 -0
  35. package/dist/engine/file-facts.js +63 -0
  36. package/dist/engine/file-facts.js.map +1 -0
  37. package/dist/engine/git-source.d.ts +35 -0
  38. package/dist/engine/git-source.js +242 -0
  39. package/dist/engine/git-source.js.map +1 -0
  40. package/dist/engine/overlay.d.ts +43 -0
  41. package/dist/engine/overlay.js +167 -0
  42. package/dist/engine/overlay.js.map +1 -0
  43. package/dist/engine/protocol.d.ts +146 -0
  44. package/dist/engine/protocol.js +40 -0
  45. package/dist/engine/protocol.js.map +1 -0
  46. package/dist/engine/reader.d.ts +133 -0
  47. package/dist/engine/reader.js +298 -0
  48. package/dist/engine/reader.js.map +1 -0
  49. package/dist/engine/sources.d.ts +39 -0
  50. package/dist/engine/sources.js +137 -0
  51. package/dist/engine/sources.js.map +1 -0
  52. package/dist/engine/sqlite-store.d.ts +99 -0
  53. package/dist/engine/sqlite-store.js +452 -0
  54. package/dist/engine/sqlite-store.js.map +1 -0
  55. package/dist/engine/store.d.ts +85 -0
  56. package/dist/engine/store.js +31 -0
  57. package/dist/engine/store.js.map +1 -0
  58. package/dist/engine/tables.d.ts +15 -0
  59. package/dist/engine/tables.js +70 -0
  60. package/dist/engine/tables.js.map +1 -0
  61. package/dist/engine/units.d.ts +58 -0
  62. package/dist/engine/units.js +186 -0
  63. package/dist/engine/units.js.map +1 -0
  64. package/dist/engine/version.d.ts +6 -0
  65. package/dist/engine/version.js +21 -0
  66. package/dist/engine/version.js.map +1 -0
  67. package/dist/engine/worker.d.ts +1 -0
  68. package/dist/engine/worker.js +220 -0
  69. package/dist/engine/worker.js.map +1 -0
  70. package/dist/flattener/index.d.ts +34 -17
  71. package/dist/flattener/index.js +245 -114
  72. package/dist/flattener/index.js.map +1 -1
  73. package/dist/flattener/resolve-text-links.d.ts +15 -14
  74. package/dist/flattener/resolve-text-links.js +24 -25
  75. package/dist/flattener/resolve-text-links.js.map +1 -1
  76. package/dist/glossary.d.ts +2 -2
  77. package/dist/glossary.js.map +1 -1
  78. package/dist/index.d.ts +168 -2
  79. package/dist/index.js +883 -639
  80. package/dist/index.js.map +1 -1
  81. package/dist/markdown-parse.d.ts +6 -0
  82. package/dist/markdown-parse.js +14 -0
  83. package/dist/markdown-parse.js.map +1 -1
  84. package/dist/parser/learning-outcome.js +11 -2
  85. package/dist/parser/learning-outcome.js.map +1 -1
  86. package/dist/parser/lens.d.ts +5 -1
  87. package/dist/parser/lens.js +22 -7
  88. package/dist/parser/lens.js.map +1 -1
  89. package/dist/parser/meeting-doc.d.ts +2 -1
  90. package/dist/parser/meeting-doc.js +2 -1
  91. package/dist/parser/meeting-doc.js.map +1 -1
  92. package/dist/parser/module.d.ts +3 -1
  93. package/dist/parser/module.js +7 -5
  94. package/dist/parser/module.js.map +1 -1
  95. package/dist/parser/question-embeds.d.ts +4 -3
  96. package/dist/parser/question-embeds.js.map +1 -1
  97. package/dist/parser/sections.d.ts +10 -0
  98. package/dist/parser/sections.js +8 -3
  99. package/dist/parser/sections.js.map +1 -1
  100. package/dist/parser/widget.d.ts +2 -1
  101. package/dist/parser/widget.js.map +1 -1
  102. package/dist/parser/wikilink.d.ts +13 -3
  103. package/dist/parser/wikilink.js +55 -34
  104. package/dist/parser/wikilink.js.map +1 -1
  105. package/dist/reference-graph.d.ts +21 -3
  106. package/dist/reference-graph.js +35 -12
  107. package/dist/reference-graph.js.map +1 -1
  108. package/dist/same-page-links.d.ts +11 -1
  109. package/dist/same-page-links.js +9 -0
  110. package/dist/same-page-links.js.map +1 -1
  111. package/dist/skill-tree.d.ts +2 -1
  112. package/dist/skill-tree.js.map +1 -1
  113. package/dist/source-location.d.ts +0 -4
  114. package/dist/source-location.js +0 -43
  115. package/dist/source-location.js.map +1 -1
  116. package/dist/validator/card-module-membership.d.ts +17 -1
  117. package/dist/validator/card-module-membership.js +60 -56
  118. package/dist/validator/card-module-membership.js.map +1 -1
  119. package/dist/validator/criticmarkup.js +1 -1
  120. package/dist/validator/criticmarkup.js.map +1 -1
  121. package/dist/validator/field-typos.d.ts +1 -1
  122. package/dist/validator/field-typos.js +21 -21
  123. package/dist/validator/field-typos.js.map +1 -1
  124. package/dist/validator/output-integrity.d.ts +9 -5
  125. package/dist/validator/output-integrity.js +43 -45
  126. package/dist/validator/output-integrity.js.map +1 -1
  127. package/dist/validator/tier.d.ts +2 -2
  128. package/dist/validator/tier.js.map +1 -1
  129. package/dist/validator/uuid.d.ts +1 -1
  130. package/package.json +2 -1
@@ -0,0 +1,146 @@
1
+ import type { ContentError } from "../index.js";
2
+ /**
3
+ * Which files of a checkout are content: each top-level directory that holds
4
+ * content → the endings its files' names may have, such as
5
+ * {"modules": [".md", ".timestamps.json"], "widgets": [".md", ".html"]}. The
6
+ * platform sends its own list (core/content/git_fetcher.content_directories),
7
+ * so the engine keeps none.
8
+ */
9
+ export type ContentDirectories = Record<string, string[]>;
10
+ /** Where a job's content comes from. */
11
+ export type JobSource =
12
+ /** A checkout of the content repository; the job reads the content files (`directories`) of the tree of `commit`. */
13
+ {
14
+ type: "git";
15
+ repoDir: string;
16
+ commit: string;
17
+ directories: ContentDirectories;
18
+ }
19
+ /** An explicit file map, as `cli.ts --stdin` takes it (path → content). */
20
+ | {
21
+ type: "files";
22
+ files: Record<string, string>;
23
+ };
24
+ export type JobKind =
25
+ /** Bring the build layer up to date with the source; store the results. */
26
+ "commit"
27
+ /** Like commit, but every unit runs again (a new validator version, or a damaged store). */
28
+ | "cold"
29
+ /** Build the source with `overlays` applied, and store nothing. For agents' checks. */
30
+ | "overlay";
31
+ export interface Job {
32
+ kind: JobKind;
33
+ source: JobSource;
34
+ /** The build-layer file, or ":memory:" for a store that lives only in this process. */
35
+ storePath: string;
36
+ /** Overlay jobs: text that replaces a file for this job only; null deletes the file. */
37
+ overlays?: Record<string, string | null>;
38
+ /** Units that killed an earlier attempt of this job: not run (worker.ts, blame and skip). */
39
+ skipUnits?: string[];
40
+ /**
41
+ * Run every unit that the build layer marks failed, not only those whose
42
+ * inputs changed: one that hung once, or was killed from outside, may pass
43
+ * now. A unit that fails again is blamed again. The platform sets it on the
44
+ * first job a process runs against a store.
45
+ */
46
+ retryFailed?: boolean;
47
+ /** Write today's complete CLI output (byte-identical to `cli.ts --stdin --defer-urls`) here. */
48
+ fullOutputPath?: string;
49
+ /**
50
+ * Leave the course-graph checks out of the full output's errors, as
51
+ * `cli.ts --skip-course-graph` does (the platform runs them as a job of
52
+ * their own and merges them itself).
53
+ */
54
+ skipCourseGraph?: boolean;
55
+ /**
56
+ * Overlay jobs: the paths whose issues are the overlay's own
57
+ * (OverlayReport.issues); by default the overlaid paths.
58
+ */
59
+ focusPaths?: string[];
60
+ /**
61
+ * Overlay jobs: the content paths built with their pending CriticMarkup
62
+ * suggestions accepted (acceptAllSuggestions, authoring-markup.ts), the
63
+ * drafts view. Every other file is built as published, its suggestions
64
+ * rejected. Absent or empty: the approved view.
65
+ */
66
+ draftPaths?: string[];
67
+ }
68
+ export type PageChange = {
69
+ sourcePath: string;
70
+ index: number;
71
+ slug: string;
72
+ change: "added" | "changed" | "removed";
73
+ };
74
+ /** A content file whose version differs from the one the build layer held before the job. */
75
+ export type FileChange = {
76
+ path: string;
77
+ change: "added" | "changed" | "removed";
78
+ };
79
+ export interface JobResult {
80
+ event: "result";
81
+ status: "ok" | "error";
82
+ /** Set when status is "error". */
83
+ message?: string;
84
+ validatorVersion: string;
85
+ /** The commit the build layer now describes (git sources). */
86
+ commit?: string;
87
+ /**
88
+ * Advice ("What a reader applies" above): pages whose final JSON this job
89
+ * added, changed or removed in the build layer, in canonical order.
90
+ */
91
+ changedPages: PageChange[];
92
+ /** Advice: whole-content artifacts whose JSON this job changed ("errors", "courses", ...). */
93
+ changedArtifacts: string[];
94
+ /** Advice: content files whose version differs from the build layer's before the job, in path order. */
95
+ changedFiles?: FileChange[];
96
+ /** Path units (one per file) that ran, and units skipped because they are marked failed. */
97
+ unitsRun: number;
98
+ skippedUnits: string[];
99
+ /** Finish units (one per page) that ran. */
100
+ finishUnitsRun?: number;
101
+ /**
102
+ * The URL report of `cli.ts --defer-urls` for the job's content: issues
103
+ * from still-fresh entries of the URL cache file, and the number of URLs
104
+ * that need a live check (commit, cold and overlay jobs).
105
+ */
106
+ urlIssues?: ContentError[];
107
+ staleUrlCount?: number;
108
+ /** Milliseconds per stage, for the logs. */
109
+ timings: Record<string, number>;
110
+ /** Overlay jobs only: what the overlay would change. */
111
+ overlay?: OverlayReport;
112
+ }
113
+ export interface OverlayReport {
114
+ /** Issues whose file is one of focusPaths, as the content would be with the overlay. */
115
+ issues: ContentError[];
116
+ /** Issues in other files that the overlay adds (not present without it). */
117
+ causedIssues: ContentError[];
118
+ /** Pages whose final JSON the overlay would change. */
119
+ changedPages: PageChange[];
120
+ /** The course reachability map of the checked content (fileToCourses, as cli.ts emits it). */
121
+ fileToCourses: Record<string, string[]>;
122
+ }
123
+ /** A progress event (worker.ts): the unit the worker is about to run, or null once it has finished. */
124
+ export interface UnitEvent {
125
+ event: "unit";
126
+ id: string | null;
127
+ }
128
+ /**
129
+ * The content of one job. `versions()` lists every content file; the version of a
130
+ * file is the Git blob id of its raw bytes. `read()` returns the text exactly as
131
+ * the platform passes it to the processor today (UTF-8, universal newlines; see
132
+ * core/content/git_fetcher.read_all_files).
133
+ */
134
+ export interface ContentSource {
135
+ versions(): Map<string, string>;
136
+ read(path: string): string;
137
+ }
138
+ /**
139
+ * Calls the engine makes around each unit: the worker reports progress and
140
+ * records the running unit (worker.ts); tests see which units run, and stop a
141
+ * job part way.
142
+ */
143
+ export interface JobHooks {
144
+ beforeUnit?(unitId: string): void;
145
+ afterUnit?(unitId: string): void;
146
+ }
@@ -0,0 +1,40 @@
1
+ // The job protocol between the platform and the content worker: the Job the
2
+ // worker reads, the JobResult it writes last, and what the build layer holds
3
+ // afterwards. How the worker runs, its events, and blame and skip: worker.ts.
4
+ // Results that are large (pages, errors) are read from the build layer, not
5
+ // from stdout.
6
+ //
7
+ // Artifacts (the build layer's artifacts table; JobResult.changedArtifacts
8
+ // names the ones a job changed):
9
+ //
10
+ // errors every content error, in today's order, without the
11
+ // course-graph checks (they run as their own job)
12
+ // errorSources one entry per entry of errors: the ids of the units that
13
+ // reported it, in the order they did. "path:<file>" is a
14
+ // file's unit, "page:<file>#<index>" a page's finish step,
15
+ // "whole" a check across files (no unit, no reads). A
16
+ // unit's reads are in the reads table. A finish step's
17
+ // "flat:<file>#<index>" read is the flattened page that unit
18
+ // "path:<file>" made: follow that unit's reads to files.
19
+ // courses, surveys, meetingDocs, articleSegments, urlsToValidate, skillTree
20
+ // as in processContent's result; meetingDocs and
21
+ // articleSegments are absent when empty
22
+ // fileToCourses the course reachability map, as cli.ts emits it
23
+ // dropped what errors left out of pages, for the staging admins'
24
+ // error boxes: page slug → {page, sourcePath, items,
25
+ // moduleError} (src/dropped.ts). Not in the CLI output.
26
+ //
27
+ // What a reader applies. A job commits its writes in batches while it runs,
28
+ // so a job that fails or is killed can leave pages and artifacts written that
29
+ // no result ever listed, and the next job finds them up to date and does not
30
+ // list them either. So a reader such as the platform's cache keeps the state
31
+ // it applied last and, after every job whose status is "ok", reads the build
32
+ // layer's state in one read transaction and applies what differs: the hash of
33
+ // each page, the hash of each artifact (the meta keys "artifact:*"), the file
34
+ // versions and the commit (schema: sqlite-store.ts). After a failed or killed
35
+ // job that state can mix the old and the new content, so a reader applies
36
+ // nothing then; the next ok job brings everything it missed. A JobResult's
37
+ // changedPages, changedArtifacts and changedFiles are advice, for logs: what
38
+ // the job changed relative to the build layer before it ran.
39
+ export {};
40
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/engine/protocol.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,6EAA6E;AAC7E,8EAA8E;AAC9E,4EAA4E;AAC5E,eAAe;AACf,EAAE;AACF,2EAA2E;AAC3E,iCAAiC;AACjC,EAAE;AACF,uEAAuE;AACvE,oEAAoE;AACpE,6EAA6E;AAC7E,2EAA2E;AAC3E,6EAA6E;AAC7E,wEAAwE;AACxE,yEAAyE;AACzE,+EAA+E;AAC/E,2EAA2E;AAC3E,8EAA8E;AAC9E,mEAAmE;AACnE,0DAA0D;AAC1D,oEAAoE;AACpE,2EAA2E;AAC3E,uEAAuE;AACvE,0EAA0E;AAC1E,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,6EAA6E;AAC7E,6EAA6E;AAC7E,8EAA8E;AAC9E,8EAA8E;AAC9E,8EAA8E;AAC9E,0EAA0E;AAC1E,2EAA2E;AAC3E,6EAA6E;AAC7E,6DAA6D"}
@@ -0,0 +1,133 @@
1
+ import { type ContentTier } from "../validator/tier.js";
2
+ import type { RecordedRead } from "./store.js";
3
+ /** What a view tells its log. */
4
+ export interface ReadObserver {
5
+ get(key: string): void;
6
+ has(key: string): void;
7
+ /** The caller looked at the whole set of keys (iteration or size). */
8
+ scan(): void;
9
+ /** The caller read only a file's link facts (readFacts). */
10
+ facts?(path: string): void;
11
+ /** The caller asked which paths look like a missing one: `<dir>|<path>`. */
12
+ similar?(query: string): void;
13
+ /** The caller iterated every value; without this hook, a scan and a get of each key. */
14
+ all?(): void;
15
+ }
16
+ /** A read-only map from path to file text, tier or tags, or from key to a table entry. */
17
+ export declare class ContentView<V> implements ReadonlyMap<string, V> {
18
+ private readonly map;
19
+ private readonly observer?;
20
+ private findSimilar;
21
+ constructor(map: ReadonlyMap<string, V>, observer?: ReadObserver | undefined);
22
+ get(key: string): V | undefined;
23
+ has(key: string): boolean;
24
+ get size(): number;
25
+ keys(): MapIterator<string>;
26
+ values(): MapIterator<V>;
27
+ entries(): MapIterator<[string, V]>;
28
+ [Symbol.iterator](): MapIterator<[string, V]>;
29
+ forEach(callback: (value: V, key: string, map: ReadonlyMap<string, V>) => void, thisArg?: unknown): void;
30
+ /** A file's link facts, recorded as facts:<path> (a whole read without a facts observer). */
31
+ facts(this: ContentView<string>, path: string): LinkFacts | undefined;
32
+ /**
33
+ * The paths findSimilarFiles suggests for the missing `path`, recorded as
34
+ * similar:<dir>|<path> (a scan without a similar observer).
35
+ */
36
+ similar(this: ContentView<string>, path: string, dir: string): string[];
37
+ /** Iterating values reads every entry. */
38
+ private readAll;
39
+ }
40
+ export type ContentFiles = ContentView<string>;
41
+ export type TierMap = ContentView<ContentTier>;
42
+ export type TagMap = ContentView<string[]>;
43
+ /**
44
+ * What a card or an inline link shows of the file it points to
45
+ * (flattener/resolve-text-links.ts): the raw frontmatter values, which the
46
+ * link turns into a title, a slug, a content id and a summary. Nothing else
47
+ * of the target's text reaches the linking page.
48
+ */
49
+ export interface LinkFacts {
50
+ title?: unknown;
51
+ slug?: unknown;
52
+ id?: unknown;
53
+ tldr?: unknown;
54
+ }
55
+ export declare function linkFacts(path: string, text: string): LinkFacts;
56
+ /**
57
+ * The link facts of a file in `files`, which must hold it. A view records the
58
+ * read as facts:<path>; a plain map (tests call rules with one) is read as is.
59
+ */
60
+ export declare function readFacts(files: ContentFiles, path: string): LinkFacts;
61
+ /** The version a facts:<path> read sees. Non-finite numbers are tagged: JSON writes them as null. */
62
+ export declare function factsVersion(facts: LinkFacts): string;
63
+ /** Path order: code-unit order, the order the processor visits files in. */
64
+ export declare function byPath(a: string, b: string): number;
65
+ /**
66
+ * `files` in path order, as a view that records nothing. Callers list files
67
+ * in whatever order they found them (a file system walk, a JSON object), and
68
+ * every output order is derived from this one, so the output depends on the
69
+ * content alone.
70
+ */
71
+ export declare function inPathOrder(files: ReadonlyMap<string, string>): ContentFiles;
72
+ /** The views one unit (or one whole-content step) reads content through. */
73
+ export interface ContentViews {
74
+ files: ContentFiles;
75
+ tierMap: TierMap;
76
+ tagMap: TagMap;
77
+ }
78
+ /** Answers the current version of a read key; how a stored unit's reads are checked. */
79
+ export interface Versions {
80
+ versionOf(key: string): string;
81
+ }
82
+ /**
83
+ * The content of one job: every file's version and text, and the tags of
84
+ * every Markdown and widget file. It answers the current version of any
85
+ * content read key (file, facts, exists, paths, similar, tier, tags).
86
+ */
87
+ export declare class ContentState implements Versions {
88
+ readonly versions: ReadonlyMap<string, string>;
89
+ readonly texts: ReadonlyMap<string, string>;
90
+ readonly tags: ReadonlyMap<string, string[]>;
91
+ readonly tiers: Map<string, ContentTier>;
92
+ private pathsHash;
93
+ private readonly factsVersions;
94
+ private readonly similarVersions;
95
+ private findSimilar;
96
+ /**
97
+ * @param versions path → Git blob id, for every file
98
+ * @param texts path → text, with keys in sorted order (the order units see)
99
+ * @param tags lower-cased frontmatter tags of every Markdown and widget file
100
+ * @param factsVersions path → factsVersion of its link facts, when known
101
+ * (the engine keeps them per file); others are computed from the text
102
+ */
103
+ constructor(versions: ReadonlyMap<string, string>, texts: ReadonlyMap<string, string>, tags: ReadonlyMap<string, string[]>, factsVersions?: ReadonlyMap<string, string>);
104
+ /** The version a read of `key` sees in this content. */
105
+ versionOf(key: string): string;
106
+ /**
107
+ * A hash of what findSimilarFiles suggests for `query` (`<dir>|<path>`) in
108
+ * this content: a function of the query and the path list alone, so after
109
+ * a file is added or removed it tells which suggestions changed.
110
+ */
111
+ private similarVersion;
112
+ /** Views that record nothing. */
113
+ views(): ContentViews;
114
+ /** Views that write every lookup to `log`. */
115
+ recordingViews(log: ReadLog): ContentViews;
116
+ }
117
+ /**
118
+ * A view of a whole-content table whose lookups `log` records as
119
+ * `<prefix><key>` (any lookup of a key, found or not, is one read of it).
120
+ */
121
+ export declare function tableView<V>(table: ReadonlyMap<string, V>, prefix: string, log?: ReadLog): ContentView<V>;
122
+ /** The version of a table entry: a hash of its JSON, or "-" when there is none. */
123
+ export declare function entryVersion(value: unknown): string;
124
+ /** The reads of one unit, with the version each saw. */
125
+ export declare class ReadLog {
126
+ private readonly versions;
127
+ private readonly seen;
128
+ constructor(versions: Versions);
129
+ read(key: string): void;
130
+ /** Every read, sorted by key. */
131
+ reads(): RecordedRead[];
132
+ }
133
+ export declare function sha1(text: string): string;
@@ -0,0 +1,298 @@
1
+ // The reader: the only way a unit sees content, and the record of what it saw.
2
+ //
3
+ // A unit (one content file's pass, runPathUnit in ../index.ts, or one page's
4
+ // finish step, finishPage) reads other files' text, their facts, tiers and
5
+ // tags, and the whole-content step's tables, through ContentViews. A view
6
+ // built with a ReadLog writes down every lookup as a key and the version it
7
+ // saw:
8
+ //
9
+ // file:<path> get(path) on the files the Git blob id, or "missing"
10
+ // facts:<path> readFacts(files, path) a hash of the link facts, or "missing"
11
+ // exists:<path> has(path) on any view "1" or "0"
12
+ // paths:* keys(), size, iteration a hash of the sorted path list
13
+ // similar:<q> similar(path, dir) on the a hash of the paths findSimilarFiles
14
+ // files; q is <dir>|<path> suggests for the missing path
15
+ // similar:* with every similar: read "1": finds the units to check
16
+ // when a file is added or removed
17
+ // tier:<path> get(path) on the tiers the tier, or "-"
18
+ // tags:<path> get(path) on the tags the tags as JSON, or "-"
19
+ // table:<t>:<key> get(key) on a table view a hash of the entry, or "-"
20
+ // glossary:<path> get(path) on the glossary a hash of the entry, or "-"
21
+ // flat:<page> a finish unit's input a hash of the flattened page
22
+ //
23
+ // After an edit, a unit runs again only when a key it read has a new version
24
+ // (build.ts). A unit that only checked that a file exists does not run again
25
+ // when that file's text changes; a card or link that shows a lens's title
26
+ // does not run again when the lens's body changes; a tag edit that leaves
27
+ // the tier alone does not rerun the units that read only the tier; and a
28
+ // unit with a broken link runs again when a file is added or removed only if
29
+ // its "did you mean" suggestion changes.
30
+ //
31
+ // The views are nominal: a Map is not a ContentView, so TypeScript refuses a
32
+ // raw map where a unit or a rule takes one. That is what keeps every read on
33
+ // the record.
34
+ //
35
+ // Two more rules keep an incremental build equal to a cold one. Break either
36
+ // and a page stays stale after an edit, with no test failing at once:
37
+ // - A memo shared between units is safe only when it is keyed by a text the
38
+ // unit read through a view (runMemo in ../markdown-parse.ts): it gives only
39
+ // what that text gives. The --cache-dir caches return results without the
40
+ // reads that made them, so only processContent uses them (runPathUnit's
41
+ // steps).
42
+ // - A unit's output is plain data, with no Map or class instance: the build
43
+ // layer stores it as JSON.
44
+ import { createHash } from "crypto";
45
+ import { parseFrontmatter } from "../parser/frontmatter.js";
46
+ import { similarFilesIn } from "../parser/wikilink.js";
47
+ import { buildTierMap } from "../validator/tier.js";
48
+ /** A read-only map from path to file text, tier or tags, or from key to a table entry. */
49
+ export class ContentView {
50
+ map;
51
+ observer;
52
+ findSimilar;
53
+ constructor(map, observer) {
54
+ this.map = map;
55
+ this.observer = observer;
56
+ }
57
+ get(key) {
58
+ this.observer?.get(key);
59
+ return this.map.get(key);
60
+ }
61
+ has(key) {
62
+ this.observer?.has(key);
63
+ return this.map.has(key);
64
+ }
65
+ get size() {
66
+ this.observer?.scan();
67
+ return this.map.size;
68
+ }
69
+ keys() {
70
+ this.observer?.scan();
71
+ return this.map.keys();
72
+ }
73
+ values() {
74
+ this.readAll();
75
+ return this.map.values();
76
+ }
77
+ entries() {
78
+ this.readAll();
79
+ return this.map.entries();
80
+ }
81
+ [Symbol.iterator]() {
82
+ return this.entries();
83
+ }
84
+ forEach(callback, thisArg) {
85
+ this.readAll();
86
+ this.map.forEach((value, key) => callback.call(thisArg, value, key, this));
87
+ }
88
+ /** A file's link facts, recorded as facts:<path> (a whole read without a facts observer). */
89
+ facts(path) {
90
+ if (this.observer?.facts)
91
+ this.observer.facts(path);
92
+ else
93
+ this.observer?.get(path);
94
+ const text = this.map.get(path);
95
+ return text === undefined ? undefined : linkFacts(path, text);
96
+ }
97
+ /**
98
+ * The paths findSimilarFiles suggests for the missing `path`, recorded as
99
+ * similar:<dir>|<path> (a scan without a similar observer).
100
+ */
101
+ similar(path, dir) {
102
+ if (this.observer?.similar)
103
+ this.observer.similar(`${dir}|${path}`);
104
+ else
105
+ this.observer?.scan();
106
+ this.findSimilar ??= similarFilesIn(this.map.keys());
107
+ return this.findSimilar(path, dir);
108
+ }
109
+ /** Iterating values reads every entry. */
110
+ readAll() {
111
+ if (!this.observer)
112
+ return;
113
+ if (this.observer.all)
114
+ return this.observer.all();
115
+ this.observer.scan();
116
+ for (const key of this.map.keys())
117
+ this.observer.get(key);
118
+ }
119
+ }
120
+ export function linkFacts(path, text) {
121
+ const { frontmatter } = parseFrontmatter(text, path);
122
+ const { title, slug, id, tldr } = frontmatter;
123
+ return { title, slug, id, tldr };
124
+ }
125
+ /**
126
+ * The link facts of a file in `files`, which must hold it. A view records the
127
+ * read as facts:<path>; a plain map (tests call rules with one) is read as is.
128
+ */
129
+ export function readFacts(files, path) {
130
+ if (files instanceof ContentView)
131
+ return files.facts(path);
132
+ return linkFacts(path, files.get(path));
133
+ }
134
+ /** The version a facts:<path> read sees. Non-finite numbers are tagged: JSON writes them as null. */
135
+ export function factsVersion(facts) {
136
+ return sha1(JSON.stringify(facts, (_key, value) => typeof value === "number" && !Number.isFinite(value)
137
+ ? `\u0000${value}`
138
+ : value));
139
+ }
140
+ /** Path order: code-unit order, the order the processor visits files in. */
141
+ export function byPath(a, b) {
142
+ return a < b ? -1 : a > b ? 1 : 0;
143
+ }
144
+ /**
145
+ * `files` in path order, as a view that records nothing. Callers list files
146
+ * in whatever order they found them (a file system walk, a JSON object), and
147
+ * every output order is derived from this one, so the output depends on the
148
+ * content alone.
149
+ */
150
+ export function inPathOrder(files) {
151
+ return new ContentView(new Map([...files].sort(([a], [b]) => byPath(a, b))));
152
+ }
153
+ /**
154
+ * The content of one job: every file's version and text, and the tags of
155
+ * every Markdown and widget file. It answers the current version of any
156
+ * content read key (file, facts, exists, paths, similar, tier, tags).
157
+ */
158
+ export class ContentState {
159
+ versions;
160
+ texts;
161
+ tags;
162
+ tiers;
163
+ pathsHash;
164
+ factsVersions;
165
+ similarVersions = new Map();
166
+ findSimilar;
167
+ /**
168
+ * @param versions path → Git blob id, for every file
169
+ * @param texts path → text, with keys in sorted order (the order units see)
170
+ * @param tags lower-cased frontmatter tags of every Markdown and widget file
171
+ * @param factsVersions path → factsVersion of its link facts, when known
172
+ * (the engine keeps them per file); others are computed from the text
173
+ */
174
+ constructor(versions, texts, tags, factsVersions = new Map()) {
175
+ this.versions = versions;
176
+ this.texts = texts;
177
+ this.tags = tags;
178
+ this.tiers = buildTierMap(tags);
179
+ this.factsVersions = new Map(factsVersions);
180
+ }
181
+ /** The version a read of `key` sees in this content. */
182
+ versionOf(key) {
183
+ const colon = key.indexOf(":");
184
+ const kind = key.slice(0, colon);
185
+ const path = key.slice(colon + 1);
186
+ switch (kind) {
187
+ case "file":
188
+ return this.versions.get(path) ?? "missing";
189
+ case "facts": {
190
+ if (!this.versions.has(path))
191
+ return "missing";
192
+ let version = this.factsVersions.get(path);
193
+ if (version === undefined) {
194
+ version = factsVersion(linkFacts(path, this.texts.get(path)));
195
+ this.factsVersions.set(path, version);
196
+ }
197
+ return version;
198
+ }
199
+ case "exists":
200
+ return this.versions.has(path) ? "1" : "0";
201
+ case "paths":
202
+ return (this.pathsHash ??= hashPaths(this.versions.keys()));
203
+ case "similar":
204
+ return path === "*" ? "1" : this.similarVersion(path);
205
+ case "tier":
206
+ return this.tiers.get(path) ?? "-";
207
+ case "tags": {
208
+ const tags = this.tags.get(path);
209
+ return tags ? JSON.stringify(tags) : "-";
210
+ }
211
+ default:
212
+ throw new Error(`Unknown read key: ${key}`);
213
+ }
214
+ }
215
+ /**
216
+ * A hash of what findSimilarFiles suggests for `query` (`<dir>|<path>`) in
217
+ * this content: a function of the query and the path list alone, so after
218
+ * a file is added or removed it tells which suggestions changed.
219
+ */
220
+ similarVersion(query) {
221
+ let version = this.similarVersions.get(query);
222
+ if (version === undefined) {
223
+ const bar = query.indexOf("|");
224
+ this.findSimilar ??= similarFilesIn(this.texts.keys());
225
+ const found = this.findSimilar(query.slice(bar + 1), query.slice(0, bar));
226
+ version = entryVersion(found);
227
+ this.similarVersions.set(query, version);
228
+ }
229
+ return version;
230
+ }
231
+ /** Views that record nothing. */
232
+ views() {
233
+ return {
234
+ files: new ContentView(this.texts),
235
+ tierMap: new ContentView(this.tiers),
236
+ tagMap: new ContentView(this.tags),
237
+ };
238
+ }
239
+ /** Views that write every lookup to `log`. */
240
+ recordingViews(log) {
241
+ const observer = (kind) => ({
242
+ get: (path) => log.read(`${kind}:${path}`),
243
+ has: (path) => log.read(`exists:${path}`),
244
+ scan: () => log.read("paths:*"),
245
+ facts: (path) => log.read(`facts:${path}`),
246
+ similar: (query) => {
247
+ log.read("similar:*");
248
+ log.read(`similar:${query}`);
249
+ },
250
+ });
251
+ return {
252
+ files: new ContentView(this.texts, observer("file")),
253
+ tierMap: new ContentView(this.tiers, observer("tier")),
254
+ tagMap: new ContentView(this.tags, observer("tags")),
255
+ };
256
+ }
257
+ }
258
+ /**
259
+ * A view of a whole-content table whose lookups `log` records as
260
+ * `<prefix><key>` (any lookup of a key, found or not, is one read of it).
261
+ */
262
+ export function tableView(table, prefix, log) {
263
+ return new ContentView(table, log && {
264
+ get: (key) => log.read(prefix + key),
265
+ has: (key) => log.read(prefix + key),
266
+ scan: () => log.read(`${prefix}*`),
267
+ });
268
+ }
269
+ /** The version of a table entry: a hash of its JSON, or "-" when there is none. */
270
+ export function entryVersion(value) {
271
+ return value === undefined ? "-" : sha1(JSON.stringify(value));
272
+ }
273
+ /** The reads of one unit, with the version each saw. */
274
+ export class ReadLog {
275
+ versions;
276
+ seen = new Map();
277
+ constructor(versions) {
278
+ this.versions = versions;
279
+ }
280
+ read(key) {
281
+ if (!this.seen.has(key))
282
+ this.seen.set(key, this.versions.versionOf(key));
283
+ }
284
+ /** Every read, sorted by key. */
285
+ reads() {
286
+ return [...this.seen]
287
+ .sort(([a], [b]) => byPath(a, b))
288
+ .map(([key, version]) => ({ key, version }));
289
+ }
290
+ }
291
+ export function sha1(text) {
292
+ return createHash("sha1").update(text).digest("hex");
293
+ }
294
+ function hashPaths(paths) {
295
+ const sorted = [...paths].sort(byPath);
296
+ return sha1(sorted.join("\n"));
297
+ }
298
+ //# sourceMappingURL=reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.js","sourceRoot":"","sources":["../../src/engine/reader.ts"],"names":[],"mappings":"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"}