@plebeiantech/lat.md 0.12.3-fork.17 → 0.12.3-fork.20
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 +1 -1
- package/dist/src/cli/agent-invocation.d.ts +6 -0
- package/dist/src/cli/agent-invocation.js +23 -0
- package/dist/src/cli/fork-instructions.js +1 -1
- package/dist/src/cli/fork-scaffold.js +2 -2
- package/dist/src/cli/graph.d.ts +1 -1
- package/dist/src/cli/hook.js +11 -11
- package/dist/src/cli/index.js +41 -59
- package/dist/src/cli/init-preferences.js +5 -4
- package/dist/src/cli/init.d.ts +1 -1
- package/dist/src/cli/init.js +54 -45
- package/dist/src/cli/reindex.d.ts +1 -1
- package/dist/src/cli/reindex.js +2 -2
- package/dist/src/cli/search.d.ts +4 -4
- package/dist/src/cli/search.js +41 -28
- package/dist/src/cli/ui-build-server.d.ts +1 -1
- package/dist/src/cli/ui-build.d.ts +1 -1
- package/dist/src/cli/ui.d.ts +1 -1
- package/dist/src/fork/antigravity-hook.js +6 -6
- package/dist/src/fork/antigravity-init.d.ts +2 -2
- package/dist/src/fork/antigravity-init.js +2 -2
- package/dist/src/graph-export.js +7 -7
- package/dist/src/knowledge/index.js +2 -2
- package/dist/src/mcp/server.js +8 -8
- package/dist/src/search/cache.d.ts +1 -1
- package/dist/src/search/cache.js +40 -7
- package/dist/src/search/chunks.d.ts +2 -2
- package/dist/src/search/db.d.ts +5 -4
- package/dist/src/search/db.js +36 -40
- package/dist/src/search/embedder.js +1 -1
- package/dist/src/search/index.d.ts +1 -1
- package/dist/src/search/index.js +2 -2
- package/dist/src/search/lock.d.ts +4 -1
- package/dist/src/search/lock.js +30 -8
- package/dist/src/search/query.d.ts +5 -2
- package/dist/src/search/query.js +55 -38
- package/dist/src/search/search.d.ts +3 -1
- package/dist/src/search/search.js +21 -12
- package/dist/src/search/types.d.ts +2 -18
- package/dist/src/view/client/assets/{GraphView-BWlRdQM4.js → GraphView-Dij8mAA_.js} +1 -1
- package/dist/src/view/client/assets/{MarkdownEditor-MW-Ck1O0.js → MarkdownEditor-88Wbt0M1.js} +1 -1
- package/dist/src/view/client/assets/{abnfDiagram-VCTEODGH-Bn3RshMV.js → abnfDiagram-VCTEODGH-y0DlYa8E.js} +1 -1
- package/dist/src/view/client/assets/{arc-En9tdFQF.js → arc-FlMu8dnO.js} +1 -1
- package/dist/src/view/client/assets/{architectureDiagram-5GKGNRK7-B-9J1VAM.js → architectureDiagram-5GKGNRK7-DA_uWZW1.js} +1 -1
- package/dist/src/view/client/assets/{blockDiagram-I7D4REHJ-QlznwalP.js → blockDiagram-I7D4REHJ-BHQ5LU85.js} +1 -1
- package/dist/src/view/client/assets/{c4Diagram-7LVT6UL2-Bp2y8B4_.js → c4Diagram-7LVT6UL2-BRucKCt2.js} +1 -1
- package/dist/src/view/client/assets/channel-BgDNA_Ay.js +1 -0
- package/dist/src/view/client/assets/{chunk-2Q5K7J3B-CnBKL-lm.js → chunk-2Q5K7J3B-BJPcFivt.js} +1 -1
- package/dist/src/view/client/assets/{chunk-5VM5RSS4-LLYMi_n6.js → chunk-5VM5RSS4-v2q99bGz.js} +1 -1
- package/dist/src/view/client/assets/{chunk-F27PBJKO-VIeO7VF0.js → chunk-F27PBJKO-CcHOuJCs.js} +1 -1
- package/dist/src/view/client/assets/{chunk-IMKFNOWR-D5i67DVD.js → chunk-IMKFNOWR-DNxYuJNq.js} +1 -1
- package/dist/src/view/client/assets/{chunk-JWPE2WC7-D4qAtoL3.js → chunk-JWPE2WC7-C0eHKvLW.js} +1 -1
- package/dist/src/view/client/assets/{chunk-POPQ4Y6H-BMzOyiW_.js → chunk-POPQ4Y6H-57CWp2Ve.js} +1 -1
- package/dist/src/view/client/assets/{chunk-SVP7TREG-DWy5nbfp.js → chunk-SVP7TREG-BqcoxIJw.js} +1 -1
- package/dist/src/view/client/assets/{chunk-TICWLB2K-CVqCANFB.js → chunk-TICWLB2K-DRUJR5zH.js} +1 -1
- package/dist/src/view/client/assets/{chunk-XXDRQBXY-Bp23h6Tf.js → chunk-XXDRQBXY-Dez0oRoM.js} +1 -1
- package/dist/src/view/client/assets/classDiagram-ZZMXUADV-CFZ_Sgh5.js +1 -0
- package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-CFZ_Sgh5.js +1 -0
- package/dist/src/view/client/assets/{cose-bilkent-JH36ORCC-BCw7fCC2.js → cose-bilkent-JH36ORCC-BHtud6Hg.js} +1 -1
- package/dist/src/view/client/assets/{cynefin-OW5HDTMX--lYN4N9m.js → cynefin-OW5HDTMX-BjBW8VGk.js} +1 -1
- package/dist/src/view/client/assets/{cynefinDiagram-5FMLGOSQ-9sK5EV7v.js → cynefinDiagram-5FMLGOSQ-DwGuD7oF.js} +1 -1
- package/dist/src/view/client/assets/{dagre-GXQ25YYZ-CoMdEFCq.js → dagre-GXQ25YYZ-C5zSlGK9.js} +1 -1
- package/dist/src/view/client/assets/{diagram-S7CK7UJ4-D13dyWdd.js → diagram-S7CK7UJ4-C_NhA3bj.js} +1 -1
- package/dist/src/view/client/assets/{diagram-UQ7AKVKN-PdwLPPPA.js → diagram-UQ7AKVKN-az7QPYNb.js} +1 -1
- package/dist/src/view/client/assets/{diagram-VSXAHHWV-CtWWa_A7.js → diagram-VSXAHHWV-BRvDuM8_.js} +1 -1
- package/dist/src/view/client/assets/{diagram-VX7I27RA-BeCYcSU-.js → diagram-VX7I27RA-BWLgF6S-.js} +1 -1
- package/dist/src/view/client/assets/{diagram-Z3DM3KII-DiWabOBM.js → diagram-Z3DM3KII-DV3d6mL5.js} +1 -1
- package/dist/src/view/client/assets/{ebnfDiagram-PWID7BFC-CZQ3MD_K.js → ebnfDiagram-PWID7BFC-yUXrEAvK.js} +1 -1
- package/dist/src/view/client/assets/{erDiagram-RLTQ6QDP-B1AhXIrP.js → erDiagram-RLTQ6QDP-D35FN1Pt.js} +1 -1
- package/dist/src/view/client/assets/{flowDiagram-HODETNUW-Bhr0JM6P.js → flowDiagram-HODETNUW-BciZqsjT.js} +1 -1
- package/dist/src/view/client/assets/{ganttDiagram-EL5Y4UJY-CbP8iAkg.js → ganttDiagram-EL5Y4UJY-BysPGgXS.js} +1 -1
- package/dist/src/view/client/assets/{gitGraphDiagram-WWUBYQGX-B9uuGdLF.js → gitGraphDiagram-WWUBYQGX-C3DdJ5xG.js} +1 -1
- package/dist/src/view/client/assets/index-CJokoRSp.js +13 -0
- package/dist/src/view/client/assets/{infoDiagram-27XIBGKW-BrfwQ_Cq.js → infoDiagram-27XIBGKW-D3HZrDRb.js} +1 -1
- package/dist/src/view/client/assets/{ishikawaDiagram-5VMMS53U-CHtJ36re.js → ishikawaDiagram-5VMMS53U-BXyVIXTU.js} +1 -1
- package/dist/src/view/client/assets/{journeyDiagram-3NMN7TZE-BChcgX1s.js → journeyDiagram-3NMN7TZE-D4-1NxVU.js} +1 -1
- package/dist/src/view/client/assets/{kanban-definition-UXKFOSKX-BnwFsKiB.js → kanban-definition-UXKFOSKX-4Gu_5yBA.js} +1 -1
- package/dist/src/view/client/assets/{layout-Dnd0pLdb.js → layout-Jf1K3TMM.js} +1 -1
- package/dist/src/view/client/assets/{linear-CFhW2ozn.js → linear-DWfwzUT_.js} +1 -1
- package/dist/src/view/client/assets/{mermaid.core--OP6lXtW.js → mermaid.core-DMx_DAl8.js} +5 -5
- package/dist/src/view/client/assets/{mindmap-definition-YA3MSWOX-D51y2zbm.js → mindmap-definition-YA3MSWOX-8pxY_RWi.js} +1 -1
- package/dist/src/view/client/assets/{pegDiagram-XKGWAZYB--zyQJDvI.js → pegDiagram-XKGWAZYB-DNAw_O5t.js} +1 -1
- package/dist/src/view/client/assets/{pieDiagram-E7YTZNPT-Cj8mvpJy.js → pieDiagram-E7YTZNPT-uuvRCDkC.js} +1 -1
- package/dist/src/view/client/assets/{quadrantDiagram-AXDQQJYC-qvhJrnBf.js → quadrantDiagram-AXDQQJYC-BER2O4Aq.js} +1 -1
- package/dist/src/view/client/assets/{railroadDiagram-O6MQD6OU-CtWvxpSo.js → railroadDiagram-O6MQD6OU-CxEsJ_0n.js} +1 -1
- package/dist/src/view/client/assets/{requirementDiagram-BXWQKSXE-CBxen_KG.js → requirementDiagram-BXWQKSXE-yS9rspca.js} +1 -1
- package/dist/src/view/client/assets/{sankeyDiagram-P5KCCOFB-B_fUkmfc.js → sankeyDiagram-P5KCCOFB-Bqt70a2j.js} +1 -1
- package/dist/src/view/client/assets/{sequenceDiagram-WJ2MYXX4-Dclv4p68.js → sequenceDiagram-WJ2MYXX4-BvOOEJNr.js} +1 -1
- package/dist/src/view/client/assets/{sizeCapture-INFHLROL-GfG0sMTZ.js → sizeCapture-INFHLROL-CvO_Pjjo.js} +1 -1
- package/dist/src/view/client/assets/{stateDiagram-D77RDMKH-YQWPnzxU.js → stateDiagram-D77RDMKH-KLmVOZkq.js} +1 -1
- package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-KCS8Mdzu.js +1 -0
- package/dist/src/view/client/assets/{swimlanes-42K2YHIH-5yiCveVS.js → swimlanes-42K2YHIH-DC1r4_sq.js} +1 -1
- package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-B2TcAwis.js +8 -0
- package/dist/src/view/client/assets/{timeline-definition-24CTP7MA-BvAbB5Zs.js → timeline-definition-24CTP7MA-ChXLOuBL.js} +1 -1
- package/dist/src/view/client/assets/{vennDiagram-4TSXK5OY-guC-r60n.js → vennDiagram-4TSXK5OY-D9_h25-Y.js} +1 -1
- package/dist/src/view/client/assets/{wardleyDiagram-VM6X3IG4-C0yXcU2x.js → wardleyDiagram-VM6X3IG4-CsQJGGW0.js} +1 -1
- package/dist/src/view/client/assets/{xychartDiagram-S5SC5T6Z-RPmkPNfK.js → xychartDiagram-S5SC5T6Z-DGMuPMlm.js} +1 -1
- package/dist/src/view/client/index.html +1 -1
- package/dist/src/view/diagnostics.d.ts +2 -2
- package/dist/src/view/diagnostics.js +5 -5
- package/dist/src/view/external-document-tree.js +1 -1
- package/dist/src/view/git-diff.js +1 -1
- package/dist/src/view/git.js +1 -1
- package/dist/src/view/graph.d.ts +2 -2
- package/dist/src/view/graph.js +2 -2
- package/dist/src/view/markdown.js +1 -1
- package/dist/src/view/preindexed-search.d.ts +1 -1
- package/dist/src/view/protocol.d.ts +2 -18
- package/dist/src/view/publication.d.ts +2 -0
- package/dist/src/view/publication.js +78 -0
- package/dist/src/view/references.d.ts +3 -3
- package/dist/src/view/references.js +3 -3
- package/dist/src/view/repository.d.ts +6 -6
- package/dist/src/view/repository.js +28 -14
- package/dist/src/view/request-security.d.ts +5 -0
- package/dist/src/view/request-security.js +46 -0
- package/dist/src/view/search-result.d.ts +1 -1
- package/dist/src/view/search-result.js +1 -1
- package/dist/src/view/search.d.ts +1 -1
- package/dist/src/view/server-build.d.ts +2 -2
- package/dist/src/view/server-build.js +2 -2
- package/dist/src/view/server-deployment.d.ts +1 -2
- package/dist/src/view/server-deployment.js +6 -46
- package/dist/src/view/server-index-worker.d.ts +1 -1
- package/dist/src/view/server.d.ts +1 -1
- package/dist/src/view/server.js +13 -3
- package/dist/src/view/source-target.js +2 -2
- package/dist/src/view/static-build.d.ts +1 -1
- package/dist/src/view/static-build.js +49 -17
- package/dist/src/view/store.d.ts +4 -2
- package/dist/src/view/store.js +31 -19
- package/dist/src/view/table-of-contents.d.ts +1 -1
- package/dist/src/view/table-of-contents.js +1 -1
- package/dist/src/view/vercel-server-build.d.ts +1 -1
- package/package.json +19 -29
- package/templates/AGENTS.md +2 -2
- package/templates/cursor-rules.md +2 -2
- package/templates/opencode-plugin.ts +9 -9
- package/templates/pi-extension.ts +11 -11
- package/templates/skill/SKILL.md +2 -1
- package/dist/src/cli/check-context.d.ts +0 -56
- package/dist/src/cli/check-context.js +0 -215
- package/dist/src/cli/check-coverage.d.ts +0 -2
- package/dist/src/cli/check-coverage.js +0 -75
- package/dist/src/cli/check-frontmatter.d.ts +0 -12
- package/dist/src/cli/check-frontmatter.js +0 -44
- package/dist/src/cli/check-mode.d.ts +0 -21
- package/dist/src/cli/check-mode.js +0 -394
- package/dist/src/cli/check-status.d.ts +0 -74
- package/dist/src/cli/check-status.js +0 -217
- package/dist/src/cli/check.d.ts +0 -52
- package/dist/src/cli/check.js +0 -834
- package/dist/src/cli/context.d.ts +0 -11
- package/dist/src/cli/context.js +0 -58
- package/dist/src/cli/expand.d.ts +0 -7
- package/dist/src/cli/expand.js +0 -141
- package/dist/src/cli/external.d.ts +0 -11
- package/dist/src/cli/external.js +0 -185
- package/dist/src/cli/gen-index.d.ts +0 -45
- package/dist/src/cli/gen-index.js +0 -235
- package/dist/src/cli/link-scheme.d.ts +0 -54
- package/dist/src/cli/link-scheme.js +0 -101
- package/dist/src/cli/locate.d.ts +0 -2
- package/dist/src/cli/locate.js +0 -18
- package/dist/src/cli/refs.d.ts +0 -23
- package/dist/src/cli/refs.js +0 -274
- package/dist/src/cli/section.d.ts +0 -45
- package/dist/src/cli/section.js +0 -328
- package/dist/src/cli/select-menu.d.ts +0 -13
- package/dist/src/cli/select-menu.js +0 -100
- package/dist/src/code-refs.d.ts +0 -29
- package/dist/src/code-refs.js +0 -479
- package/dist/src/config.d.ts +0 -29
- package/dist/src/config.js +0 -83
- package/dist/src/context.d.ts +0 -26
- package/dist/src/context.js +0 -11
- package/dist/src/document-formats.d.ts +0 -7
- package/dist/src/document-formats.js +0 -39
- package/dist/src/extensions/alert-marker.d.ts +0 -25
- package/dist/src/extensions/alert-marker.js +0 -55
- package/dist/src/extensions/wiki-link/from-markdown.d.ts +0 -5
- package/dist/src/extensions/wiki-link/from-markdown.js +0 -34
- package/dist/src/extensions/wiki-link/index.d.ts +0 -4
- package/dist/src/extensions/wiki-link/index.js +0 -3
- package/dist/src/extensions/wiki-link/syntax.d.ts +0 -14
- package/dist/src/extensions/wiki-link/syntax.js +0 -121
- package/dist/src/extensions/wiki-link/to-markdown.d.ts +0 -5
- package/dist/src/extensions/wiki-link/to-markdown.js +0 -28
- package/dist/src/extensions/wiki-link/types.d.ts +0 -34
- package/dist/src/extensions/wiki-link/types.js +0 -1
- package/dist/src/external-documents.d.ts +0 -56
- package/dist/src/external-documents.js +0 -404
- package/dist/src/external-sources.d.ts +0 -136
- package/dist/src/external-sources.js +0 -1098
- package/dist/src/fork/frontmatter-fields.d.ts +0 -36
- package/dist/src/fork/frontmatter-fields.js +0 -23
- package/dist/src/format.d.ts +0 -16
- package/dist/src/format.js +0 -76
- package/dist/src/init-version.d.ts +0 -10
- package/dist/src/init-version.js +0 -49
- package/dist/src/lattice-model.d.ts +0 -84
- package/dist/src/lattice-model.js +0 -467
- package/dist/src/lattice.d.ts +0 -14
- package/dist/src/lattice.js +0 -353
- package/dist/src/markdown-analysis-cache.d.ts +0 -20
- package/dist/src/markdown-analysis-cache.js +0 -139
- package/dist/src/markdown-analysis-worker.d.ts +0 -16
- package/dist/src/markdown-analysis-worker.js +0 -33
- package/dist/src/markdown-analysis.d.ts +0 -61
- package/dist/src/markdown-analysis.js +0 -169
- package/dist/src/markdown-analyzer-loader.d.ts +0 -4
- package/dist/src/markdown-analyzer-loader.js +0 -13
- package/dist/src/markdown-validation.d.ts +0 -25
- package/dist/src/markdown-validation.js +0 -104
- package/dist/src/parser-cache.d.ts +0 -17
- package/dist/src/parser-cache.js +0 -65
- package/dist/src/parser-import.d.ts +0 -8
- package/dist/src/parser-import.js +0 -1
- package/dist/src/parser.d.ts +0 -3
- package/dist/src/parser.js +0 -93
- package/dist/src/path.d.ts +0 -2
- package/dist/src/path.js +0 -4
- package/dist/src/profiler.d.ts +0 -16
- package/dist/src/profiler.js +0 -81
- package/dist/src/project-analysis.d.ts +0 -59
- package/dist/src/project-analysis.js +0 -233
- package/dist/src/project-discovery.d.ts +0 -6
- package/dist/src/project-discovery.js +0 -30
- package/dist/src/repository-path.d.ts +0 -11
- package/dist/src/repository-path.js +0 -52
- package/dist/src/source-formats.d.ts +0 -7
- package/dist/src/source-formats.js +0 -30
- package/dist/src/source-parser.d.ts +0 -67
- package/dist/src/source-parser.js +0 -1749
- package/dist/src/untrusted.d.ts +0 -18
- package/dist/src/untrusted.js +0 -93
- package/dist/src/view/client/assets/channel-uy0fFvcW.js +0 -1
- package/dist/src/view/client/assets/classDiagram-ZZMXUADV-DbSEqjA5.js +0 -1
- package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-DbSEqjA5.js +0 -1
- package/dist/src/view/client/assets/index-nBmbYfun.js +0 -13
- package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-gUj6Hzgl.js +0 -1
- package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-DR7JhrxL.js +0 -8
- package/dist/src/walk.d.ts +0 -20
- package/dist/src/walk.js +0 -121
package/dist/src/lattice.js
DELETED
|
@@ -1,353 +0,0 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import { dirname, basename, relative } from 'node:path';
|
|
3
|
-
import GithubSlugger from 'github-slugger';
|
|
4
|
-
import { parse as parseYaml } from 'yaml';
|
|
5
|
-
import { parse } from './parser.js';
|
|
6
|
-
import { toPosix } from './path.js';
|
|
7
|
-
import { visit } from 'unist-util-visit';
|
|
8
|
-
import { listLatticeFiles } from './project-discovery.js';
|
|
9
|
-
import { flattenSections, } from './lattice-model.js';
|
|
10
|
-
import { LAT_FIELDS, } from './fork/frontmatter-fields.js';
|
|
11
|
-
export { buildFileIndex, buildSectionSlugIndex, findSections, flattenSections, resolveRef, } from './lattice-model.js';
|
|
12
|
-
export { findLatticeDir, findProjectRoot, listLatticeFiles, } from './project-discovery.js';
|
|
13
|
-
export { LAT_FIELDS } from './fork/frontmatter-fields.js';
|
|
14
|
-
export function parseFrontmatter(content) {
|
|
15
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
16
|
-
if (!match)
|
|
17
|
-
return { raw: {} };
|
|
18
|
-
let raw = {};
|
|
19
|
-
const problems = [];
|
|
20
|
-
try {
|
|
21
|
-
const parsed = parseYaml(match[1]);
|
|
22
|
-
if (parsed !== null &&
|
|
23
|
-
typeof parsed === 'object' &&
|
|
24
|
-
!Array.isArray(parsed)) {
|
|
25
|
-
const root = parsed;
|
|
26
|
-
const lat = root['lat'];
|
|
27
|
-
const hasLatMapping = lat !== null && typeof lat === 'object' && !Array.isArray(lat);
|
|
28
|
-
if (hasLatMapping) {
|
|
29
|
-
raw = lat;
|
|
30
|
-
}
|
|
31
|
-
// A field written at the document root was accepted by the regex reader
|
|
32
|
-
// this parser replaced. Staying quiet about it is what makes the change
|
|
33
|
-
// dangerous: the field simply stops being read.
|
|
34
|
-
for (const field of LAT_FIELDS) {
|
|
35
|
-
if (Object.hasOwn(root, field) && !Object.hasOwn(raw, field)) {
|
|
36
|
-
problems.push({ kind: 'root-level-field', field });
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
catch (err) {
|
|
42
|
-
// One malformed line anywhere in the block used to be harmless, because
|
|
43
|
-
// the old reader pattern-matched the raw text. A strict parse throws away
|
|
44
|
-
// every field instead, so the failure has to be reported rather than
|
|
45
|
-
// swallowed.
|
|
46
|
-
raw = {};
|
|
47
|
-
problems.push({
|
|
48
|
-
kind: 'parse-error',
|
|
49
|
-
message: err.message.split('\n')[0],
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
const result = { raw };
|
|
53
|
-
if (raw['require-code-mention'] === true) {
|
|
54
|
-
result.requireCodeMention = true;
|
|
55
|
-
}
|
|
56
|
-
if (problems.length > 0)
|
|
57
|
-
result.problems = problems;
|
|
58
|
-
return result;
|
|
59
|
-
}
|
|
60
|
-
/** Extract the rendered text GitHub uses as input to its heading slugger. */
|
|
61
|
-
function headingText(node) {
|
|
62
|
-
if (!node || typeof node !== 'object')
|
|
63
|
-
return '';
|
|
64
|
-
const value = node;
|
|
65
|
-
if (value.type === 'text' || value.type === 'inlineCode') {
|
|
66
|
-
return value.value ?? '';
|
|
67
|
-
}
|
|
68
|
-
if (value.type === 'image' || value.type === 'imageReference') {
|
|
69
|
-
return value.alt ?? '';
|
|
70
|
-
}
|
|
71
|
-
if (value.type === 'wikiLink') {
|
|
72
|
-
return value.data?.alias ?? value.value ?? '';
|
|
73
|
-
}
|
|
74
|
-
if (value.children) {
|
|
75
|
-
return value.children.map(headingText).join('');
|
|
76
|
-
}
|
|
77
|
-
return '';
|
|
78
|
-
}
|
|
79
|
-
function inlineText(node) {
|
|
80
|
-
return node.children
|
|
81
|
-
.map((c) => {
|
|
82
|
-
if (c.type === 'text')
|
|
83
|
-
return c.value;
|
|
84
|
-
if (c.type === 'inlineCode')
|
|
85
|
-
return '`' + c.value + '`';
|
|
86
|
-
if (c.type === 'wikiLink')
|
|
87
|
-
return '[[' + c.value + ']]';
|
|
88
|
-
if ('children' in c)
|
|
89
|
-
return inlineText(c);
|
|
90
|
-
return '';
|
|
91
|
-
})
|
|
92
|
-
.join('');
|
|
93
|
-
}
|
|
94
|
-
function lastLine(content) {
|
|
95
|
-
const lines = content.split('\n');
|
|
96
|
-
// If trailing newline, count doesn't include empty last line
|
|
97
|
-
return lines[lines.length - 1] === '' ? lines.length - 1 : lines.length;
|
|
98
|
-
}
|
|
99
|
-
export function parseSections(filePath, content, projectRoot, tree = parse(content)) {
|
|
100
|
-
const file = projectRoot
|
|
101
|
-
? toPosix(relative(projectRoot, filePath)).replace(/\.md$/, '')
|
|
102
|
-
: basename(filePath, '.md');
|
|
103
|
-
const sectionFilePath = projectRoot
|
|
104
|
-
? toPosix(relative(projectRoot, filePath))
|
|
105
|
-
: basename(filePath);
|
|
106
|
-
const roots = [];
|
|
107
|
-
const stack = [];
|
|
108
|
-
const flat = [];
|
|
109
|
-
const slugger = new GithubSlugger();
|
|
110
|
-
const usedIds = new Set();
|
|
111
|
-
const nextSuffix = new Map();
|
|
112
|
-
visit(tree, 'heading', (node) => {
|
|
113
|
-
const heading = headingText(node);
|
|
114
|
-
const depth = node.depth;
|
|
115
|
-
const startLine = node.position.start.line;
|
|
116
|
-
// Pop stack until we find a parent with smaller depth
|
|
117
|
-
while (stack.length > 0 && stack[stack.length - 1].depth >= depth) {
|
|
118
|
-
stack.pop();
|
|
119
|
-
}
|
|
120
|
-
const parent = stack.length > 0 ? stack[stack.length - 1] : null;
|
|
121
|
-
const baseId = parent ? `${parent.id}#${heading}` : `${file}#${heading}`;
|
|
122
|
-
let id = baseId;
|
|
123
|
-
const key = baseId.toLowerCase();
|
|
124
|
-
let suffix = nextSuffix.get(key) ?? 1;
|
|
125
|
-
while (usedIds.has(id.toLowerCase()))
|
|
126
|
-
id = `${baseId}-${suffix++}`;
|
|
127
|
-
nextSuffix.set(key, suffix);
|
|
128
|
-
usedIds.add(id.toLowerCase());
|
|
129
|
-
const section = {
|
|
130
|
-
id,
|
|
131
|
-
heading,
|
|
132
|
-
depth,
|
|
133
|
-
file,
|
|
134
|
-
filePath: sectionFilePath,
|
|
135
|
-
children: [],
|
|
136
|
-
startLine,
|
|
137
|
-
endLine: 0,
|
|
138
|
-
firstParagraph: '',
|
|
139
|
-
githubSlug: slugger.slug(headingText(node)),
|
|
140
|
-
};
|
|
141
|
-
if (parent) {
|
|
142
|
-
parent.children.push(section);
|
|
143
|
-
}
|
|
144
|
-
else {
|
|
145
|
-
roots.push(section);
|
|
146
|
-
}
|
|
147
|
-
stack.push(section);
|
|
148
|
-
flat.push(section);
|
|
149
|
-
});
|
|
150
|
-
// Compute endLine: line before next heading or last line of file
|
|
151
|
-
const fileLastLine = lastLine(content);
|
|
152
|
-
for (let i = 0; i < flat.length; i++) {
|
|
153
|
-
if (i + 1 < flat.length) {
|
|
154
|
-
flat[i].endLine = flat[i + 1].startLine - 1;
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
flat[i].endLine = fileLastLine;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
// Extract firstParagraph: first paragraph after each heading
|
|
161
|
-
const children = tree.children;
|
|
162
|
-
let headingIdx = 0;
|
|
163
|
-
for (let i = 0; i < children.length; i++) {
|
|
164
|
-
const node = children[i];
|
|
165
|
-
if (node.type === 'heading') {
|
|
166
|
-
// Find the first paragraph after this heading, before the next heading
|
|
167
|
-
for (let j = i + 1; j < children.length; j++) {
|
|
168
|
-
if (children[j].type === 'heading')
|
|
169
|
-
break;
|
|
170
|
-
if (children[j].type === 'paragraph') {
|
|
171
|
-
flat[headingIdx].firstParagraph = inlineText(children[j]);
|
|
172
|
-
break;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
headingIdx++;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
return roots;
|
|
179
|
-
}
|
|
180
|
-
export async function loadAllSections(latticeDir, projectRoot = dirname(latticeDir), profile) {
|
|
181
|
-
const files = profile
|
|
182
|
-
? await profile.time('list Markdown files', () => listLatticeFiles(latticeDir))
|
|
183
|
-
: await listLatticeFiles(latticeDir);
|
|
184
|
-
const all = [];
|
|
185
|
-
for (const file of files) {
|
|
186
|
-
const detail = toPosix(relative(latticeDir, file));
|
|
187
|
-
const content = profile
|
|
188
|
-
? await profile.time('read Markdown file', () => readFile(file, 'utf-8'), detail)
|
|
189
|
-
: await readFile(file, 'utf-8');
|
|
190
|
-
const sections = profile
|
|
191
|
-
? profile.timeSync('parse Markdown sections', () => parseSections(file, content, projectRoot), detail)
|
|
192
|
-
: parseSections(file, content, projectRoot);
|
|
193
|
-
all.push(...sections);
|
|
194
|
-
}
|
|
195
|
-
return all;
|
|
196
|
-
}
|
|
197
|
-
export function extractRefs(filePath, content, projectRoot, tree = parse(content), sections = parseSections(filePath, content, projectRoot, tree)) {
|
|
198
|
-
const file = projectRoot
|
|
199
|
-
? toPosix(relative(projectRoot, filePath)).replace(/\.md$/, '')
|
|
200
|
-
: basename(filePath, '.md');
|
|
201
|
-
const refs = [];
|
|
202
|
-
// Reuse canonical identities, including duplicate suffixes and formatted text.
|
|
203
|
-
const flat = flattenSections(sections);
|
|
204
|
-
visit(tree, 'wikiLink', (node) => {
|
|
205
|
-
const line = node.position.start.line;
|
|
206
|
-
// Find enclosing section: last heading with startLine <= link line
|
|
207
|
-
let fromSection = '';
|
|
208
|
-
for (const s of flat) {
|
|
209
|
-
if (s.startLine <= line) {
|
|
210
|
-
fromSection = s.id;
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
break;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
refs.push({
|
|
217
|
-
target: node.value,
|
|
218
|
-
fromSection,
|
|
219
|
-
file,
|
|
220
|
-
line,
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
return refs;
|
|
224
|
-
}
|
|
225
|
-
function isEscapedAt(value, index) {
|
|
226
|
-
let slashes = 0;
|
|
227
|
-
for (let i = index - 1; i >= 0 && value[i] === '\\'; i--)
|
|
228
|
-
slashes++;
|
|
229
|
-
return slashes % 2 === 1;
|
|
230
|
-
}
|
|
231
|
-
function closingBracket(value, open) {
|
|
232
|
-
let depth = 0;
|
|
233
|
-
for (let i = open; i < value.length; i++) {
|
|
234
|
-
if (isEscapedAt(value, i))
|
|
235
|
-
continue;
|
|
236
|
-
if (value[i] === '[') {
|
|
237
|
-
depth++;
|
|
238
|
-
}
|
|
239
|
-
else if (value[i] === ']') {
|
|
240
|
-
depth--;
|
|
241
|
-
if (depth === 0)
|
|
242
|
-
return i;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
return -1;
|
|
246
|
-
}
|
|
247
|
-
/** Extract link destinations and undefined reference syntax. */
|
|
248
|
-
export function extractLinks(content, tree = parse(content)) {
|
|
249
|
-
const links = [];
|
|
250
|
-
visit(tree, ['link', 'image', 'definition'], (node) => {
|
|
251
|
-
const { url, type, position } = node;
|
|
252
|
-
links.push({ url, kind: type, line: position.start.line });
|
|
253
|
-
});
|
|
254
|
-
// CommonMark parses a reference with no matching definition as plain text,
|
|
255
|
-
// so it has no linkReference node to visit. Scan the authored syntax while
|
|
256
|
-
// excluding AST ranges where bracket text is data rather than prose.
|
|
257
|
-
const excluded = [];
|
|
258
|
-
visit(tree, [
|
|
259
|
-
'code',
|
|
260
|
-
'inlineCode',
|
|
261
|
-
'html',
|
|
262
|
-
'math',
|
|
263
|
-
'inlineMath',
|
|
264
|
-
'yaml',
|
|
265
|
-
'link',
|
|
266
|
-
'image',
|
|
267
|
-
'definition',
|
|
268
|
-
'linkReference',
|
|
269
|
-
'imageReference',
|
|
270
|
-
'footnoteReference',
|
|
271
|
-
'alertMarker',
|
|
272
|
-
'wikiLink',
|
|
273
|
-
], (node) => {
|
|
274
|
-
const start = node.position?.start.offset;
|
|
275
|
-
const end = node.position?.end.offset;
|
|
276
|
-
if (start !== undefined && end !== undefined) {
|
|
277
|
-
excluded.push({ start, end });
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
// GFM removes task-list markers from the paragraph AST. Exclude just the
|
|
281
|
-
// marker prefix so strict shortcut checks still apply to the item body.
|
|
282
|
-
visit(tree, 'listItem', (node) => {
|
|
283
|
-
if (typeof node.checked !== 'boolean')
|
|
284
|
-
return;
|
|
285
|
-
const start = node.position?.start.offset;
|
|
286
|
-
const bodyStart = node.children[0]?.position?.start.offset;
|
|
287
|
-
if (start === undefined || bodyStart === undefined)
|
|
288
|
-
return;
|
|
289
|
-
const marker = /\[[ xX]\]/.exec(content.slice(start, bodyStart));
|
|
290
|
-
if (marker) {
|
|
291
|
-
excluded.push({
|
|
292
|
-
start: start + marker.index,
|
|
293
|
-
end: start + marker.index + marker[0].length,
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
// Likewise, exclude only a footnote definition's label and delimiter. Its
|
|
298
|
-
// body remains prose and must still obey strict shortcut validation.
|
|
299
|
-
visit(tree, 'footnoteDefinition', (node) => {
|
|
300
|
-
const start = node.position?.start.offset;
|
|
301
|
-
const bodyStart = node.children[0]?.position?.start.offset;
|
|
302
|
-
if (start !== undefined && bodyStart !== undefined) {
|
|
303
|
-
excluded.push({ start, end: bodyStart });
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
const overlapsExcluded = (start, end) => excluded.some((range) => start < range.end && end > range.start);
|
|
307
|
-
for (let open = 0; open < content.length; open++) {
|
|
308
|
-
if (content[open] !== '[' || isEscapedAt(content, open))
|
|
309
|
-
continue;
|
|
310
|
-
const labelEnd = closingBracket(content, open);
|
|
311
|
-
if (labelEnd === -1)
|
|
312
|
-
continue;
|
|
313
|
-
const identifierStart = labelEnd + 1;
|
|
314
|
-
const hasSecondLabel = content[identifierStart] === '[' &&
|
|
315
|
-
!isEscapedAt(content, identifierStart);
|
|
316
|
-
const identifierEnd = hasSecondLabel
|
|
317
|
-
? closingBracket(content, identifierStart)
|
|
318
|
-
: labelEnd;
|
|
319
|
-
if (identifierEnd === -1)
|
|
320
|
-
continue;
|
|
321
|
-
const isImage = open > 0 && content[open - 1] === '!' && !isEscapedAt(content, open - 1);
|
|
322
|
-
const isMalformedDefinition = !isImage && !hasSecondLabel && content[labelEnd + 1] === ':';
|
|
323
|
-
const start = isImage ? open - 1 : open;
|
|
324
|
-
const end = identifierEnd + 1 + (isMalformedDefinition ? 1 : 0);
|
|
325
|
-
if (overlapsExcluded(start, end)) {
|
|
326
|
-
open = identifierEnd;
|
|
327
|
-
continue;
|
|
328
|
-
}
|
|
329
|
-
const explicitIdentifier = hasSecondLabel
|
|
330
|
-
? content.slice(identifierStart + 1, identifierEnd)
|
|
331
|
-
: '';
|
|
332
|
-
const identifier = explicitIdentifier || content.slice(open + 1, labelEnd);
|
|
333
|
-
if (identifier.trim() === '') {
|
|
334
|
-
open = identifierEnd;
|
|
335
|
-
continue;
|
|
336
|
-
}
|
|
337
|
-
links.push({
|
|
338
|
-
identifier: identifier.trim(),
|
|
339
|
-
source: content.slice(start, end),
|
|
340
|
-
kind: isImage ? 'imageReference' : 'linkReference',
|
|
341
|
-
style: !hasSecondLabel
|
|
342
|
-
? isMalformedDefinition
|
|
343
|
-
? 'definition'
|
|
344
|
-
: 'shortcut'
|
|
345
|
-
: explicitIdentifier
|
|
346
|
-
? 'full'
|
|
347
|
-
: 'collapsed',
|
|
348
|
-
line: content.slice(0, start).split('\n').length,
|
|
349
|
-
});
|
|
350
|
-
open = identifierEnd;
|
|
351
|
-
}
|
|
352
|
-
return links.sort((a, b) => a.line - b.line);
|
|
353
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { MarkdownAnalysisTimings, MarkdownFileAnalysis } from './markdown-analysis.js';
|
|
2
|
-
import type { ParserImportObserver } from './parser-import.js';
|
|
3
|
-
export { PARSER_CACHE_VERSION } from './parser-cache.js';
|
|
4
|
-
export type MarkdownAnalysisCacheStatus = 'disabled' | 'hit' | 'miss';
|
|
5
|
-
export type PreparedMarkdownAnalysis = {
|
|
6
|
-
absolutePath: string;
|
|
7
|
-
cachePath: string;
|
|
8
|
-
content: string;
|
|
9
|
-
contentHash: string;
|
|
10
|
-
analysis?: MarkdownFileAnalysis;
|
|
11
|
-
timings: Pick<MarkdownAnalysisTimings, 'readMs' | 'hashMs' | 'cacheReadMs' | 'cacheStatus'>;
|
|
12
|
-
};
|
|
13
|
-
/** Return the collision-safe, sharded cache path for one Markdown file. */
|
|
14
|
-
export declare function markdownAnalysisCachePath(latDir: string, projectRoot: string, absolutePath: string): string;
|
|
15
|
-
/** Read, hash, and attempt to hydrate one Markdown file from persistent cache. */
|
|
16
|
-
export declare function prepareMarkdownAnalysis(absolutePath: string, latDir: string, projectRoot: string, cache?: boolean): Promise<PreparedMarkdownAnalysis>;
|
|
17
|
-
/** Attach I/O timings and best-effort publish one newly parsed analysis. */
|
|
18
|
-
export declare function publishMarkdownAnalysis(prepared: PreparedMarkdownAnalysis, analysis: MarkdownFileAnalysis): Promise<MarkdownFileAnalysis>;
|
|
19
|
-
/** Analyze one path through the same persistent cache used by project runs. */
|
|
20
|
-
export declare function analyzeMarkdownPath(absolutePath: string, latDir: string, projectRoot: string, cache?: boolean, onParserImport?: ParserImportObserver): Promise<MarkdownFileAnalysis>;
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import { relative } from 'node:path';
|
|
3
|
-
import { performance } from 'node:perf_hooks';
|
|
4
|
-
import { PARSER_CACHE_VERSION, hashParserContent, parsedCachePath, parserCacheIdentity, readParsedCache, writeParsedCache, } from './parser-cache.js';
|
|
5
|
-
import { toPosix } from './path.js';
|
|
6
|
-
import { loadMarkdownAnalyzer } from './markdown-analyzer-loader.js';
|
|
7
|
-
export { PARSER_CACHE_VERSION } from './parser-cache.js';
|
|
8
|
-
/** Return the collision-safe, sharded cache path for one Markdown file. */
|
|
9
|
-
export function markdownAnalysisCachePath(latDir, projectRoot, absolutePath) {
|
|
10
|
-
return parsedCachePath(latDir, parserCacheIdentity(absolutePath, projectRoot));
|
|
11
|
-
}
|
|
12
|
-
function emptyTimings(values) {
|
|
13
|
-
return {
|
|
14
|
-
...values,
|
|
15
|
-
cacheWriteMs: 0,
|
|
16
|
-
parseMs: 0,
|
|
17
|
-
sectionsMs: 0,
|
|
18
|
-
refsMs: 0,
|
|
19
|
-
linksMs: 0,
|
|
20
|
-
paragraphsMs: 0,
|
|
21
|
-
frontmatterMs: 0,
|
|
22
|
-
indexEntriesMs: 0,
|
|
23
|
-
diagnosticsMs: 0,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
function isRecord(value) {
|
|
27
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
28
|
-
}
|
|
29
|
-
function cachedAnalysis(entry, contentHash, content, absolutePath, latDir, projectRoot) {
|
|
30
|
-
if (!entry ||
|
|
31
|
-
entry.version !== PARSER_CACHE_VERSION ||
|
|
32
|
-
entry.contentHash !== contentHash) {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
try {
|
|
36
|
-
const analysis = entry.value;
|
|
37
|
-
const expectedPath = toPosix(relative(latDir, absolutePath));
|
|
38
|
-
const expectedProjectPath = toPosix(relative(projectRoot, absolutePath));
|
|
39
|
-
if (!isRecord(analysis) ||
|
|
40
|
-
analysis.content !== content ||
|
|
41
|
-
analysis.path !== expectedPath ||
|
|
42
|
-
analysis.projectPath !== expectedProjectPath ||
|
|
43
|
-
!isRecord(analysis.frontmatter) ||
|
|
44
|
-
!Array.isArray(analysis.sections) ||
|
|
45
|
-
!Array.isArray(analysis.headingTitles) ||
|
|
46
|
-
!Array.isArray(analysis.wikiRefs) ||
|
|
47
|
-
!Array.isArray(analysis.paragraphs) ||
|
|
48
|
-
!Array.isArray(analysis.markdownLinks) ||
|
|
49
|
-
!Array.isArray(analysis.validationLinks) ||
|
|
50
|
-
!Array.isArray(analysis.indexEntries) ||
|
|
51
|
-
!Array.isArray(analysis.diagnostics)) {
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
return { ...analysis, absolutePath };
|
|
55
|
-
}
|
|
56
|
-
catch {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
/** Read, hash, and attempt to hydrate one Markdown file from persistent cache. */
|
|
61
|
-
export async function prepareMarkdownAnalysis(absolutePath, latDir, projectRoot, cache = true) {
|
|
62
|
-
const cachePath = markdownAnalysisCachePath(latDir, projectRoot, absolutePath);
|
|
63
|
-
const readStarted = performance.now();
|
|
64
|
-
const contentPromise = readFile(absolutePath, 'utf8').then((content) => ({
|
|
65
|
-
content,
|
|
66
|
-
readMs: performance.now() - readStarted,
|
|
67
|
-
}));
|
|
68
|
-
const cacheStarted = performance.now();
|
|
69
|
-
const cachePromise = cache
|
|
70
|
-
? readParsedCache(cachePath).then((entry) => ({
|
|
71
|
-
entry,
|
|
72
|
-
cacheReadMs: performance.now() - cacheStarted,
|
|
73
|
-
}))
|
|
74
|
-
: Promise.resolve({ entry: null, cacheReadMs: 0 });
|
|
75
|
-
const [{ content, readMs }, { entry, cacheReadMs }] = await Promise.all([
|
|
76
|
-
contentPromise,
|
|
77
|
-
cachePromise,
|
|
78
|
-
]);
|
|
79
|
-
const hashStarted = performance.now();
|
|
80
|
-
const contentHash = hashParserContent(content);
|
|
81
|
-
const hashMs = performance.now() - hashStarted;
|
|
82
|
-
const analysis = cache
|
|
83
|
-
? cachedAnalysis(entry, contentHash, content, absolutePath, latDir, projectRoot)
|
|
84
|
-
: null;
|
|
85
|
-
const timings = {
|
|
86
|
-
readMs,
|
|
87
|
-
hashMs,
|
|
88
|
-
cacheReadMs,
|
|
89
|
-
cacheStatus: cache ? (analysis ? 'hit' : 'miss') : 'disabled',
|
|
90
|
-
};
|
|
91
|
-
return {
|
|
92
|
-
absolutePath,
|
|
93
|
-
cachePath,
|
|
94
|
-
content,
|
|
95
|
-
contentHash,
|
|
96
|
-
analysis: analysis
|
|
97
|
-
? { ...analysis, timings: emptyTimings(timings) }
|
|
98
|
-
: undefined,
|
|
99
|
-
timings,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
/** Attach I/O timings and best-effort publish one newly parsed analysis. */
|
|
103
|
-
export async function publishMarkdownAnalysis(prepared, analysis) {
|
|
104
|
-
const base = {
|
|
105
|
-
...analysis,
|
|
106
|
-
timings: {
|
|
107
|
-
...analysis.timings,
|
|
108
|
-
...prepared.timings,
|
|
109
|
-
cacheWriteMs: 0,
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
if (prepared.timings.cacheStatus === 'disabled')
|
|
113
|
-
return base;
|
|
114
|
-
const started = performance.now();
|
|
115
|
-
try {
|
|
116
|
-
await writeParsedCache(prepared.cachePath, prepared.contentHash, base);
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
// The cache is a disposable optimization; analysis must work read-only.
|
|
120
|
-
}
|
|
121
|
-
base.timings.cacheWriteMs = performance.now() - started;
|
|
122
|
-
return base;
|
|
123
|
-
}
|
|
124
|
-
/** Analyze one path through the same persistent cache used by project runs. */
|
|
125
|
-
export async function analyzeMarkdownPath(absolutePath, latDir, projectRoot, cache = true, onParserImport) {
|
|
126
|
-
const prepared = await prepareMarkdownAnalysis(absolutePath, latDir, projectRoot, cache);
|
|
127
|
-
const detail = toPosix(relative(latDir, absolutePath));
|
|
128
|
-
if (prepared.analysis) {
|
|
129
|
-
onParserImport?.({
|
|
130
|
-
parser: 'Markdown analyzer',
|
|
131
|
-
imported: false,
|
|
132
|
-
durationMs: 0,
|
|
133
|
-
detail: `${detail} cached`,
|
|
134
|
-
});
|
|
135
|
-
return prepared.analysis;
|
|
136
|
-
}
|
|
137
|
-
const analyzeMarkdownFile = await loadMarkdownAnalyzer(onParserImport, detail);
|
|
138
|
-
return publishMarkdownAnalysis(prepared, analyzeMarkdownFile(absolutePath, prepared.content, latDir, projectRoot));
|
|
139
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { MarkdownFileAnalysis } from './markdown-analysis.js';
|
|
2
|
-
export type MarkdownWorkerTask = {
|
|
3
|
-
id: number;
|
|
4
|
-
absolutePath: string;
|
|
5
|
-
content: string;
|
|
6
|
-
latDir: string;
|
|
7
|
-
projectRoot: string;
|
|
8
|
-
};
|
|
9
|
-
export type MarkdownWorkerResponse = {
|
|
10
|
-
id: number;
|
|
11
|
-
analysis: MarkdownFileAnalysis;
|
|
12
|
-
importMs?: number;
|
|
13
|
-
} | {
|
|
14
|
-
id: number;
|
|
15
|
-
error: string;
|
|
16
|
-
};
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { parentPort } from 'node:worker_threads';
|
|
2
|
-
import { performance } from 'node:perf_hooks';
|
|
3
|
-
if (!parentPort)
|
|
4
|
-
throw new Error('Markdown analysis worker needs a parent port');
|
|
5
|
-
async function loadAnalyzer() {
|
|
6
|
-
const started = performance.now();
|
|
7
|
-
const sourceRuntime = import.meta.url.endsWith('.ts');
|
|
8
|
-
const moduleUrl = new URL(sourceRuntime ? './markdown-analysis.ts' : './markdown-analysis.js', import.meta.url).href;
|
|
9
|
-
const module = sourceRuntime
|
|
10
|
-
? await import('tsx/esm/api').then(({ tsImport }) => tsImport(moduleUrl, import.meta.url))
|
|
11
|
-
: await import(moduleUrl);
|
|
12
|
-
return {
|
|
13
|
-
analyzeMarkdownFile: module.analyzeMarkdownFile,
|
|
14
|
-
importMs: performance.now() - started,
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
const analyzerPromise = loadAnalyzer();
|
|
18
|
-
let importReported = false;
|
|
19
|
-
parentPort.on('message', async (task) => {
|
|
20
|
-
try {
|
|
21
|
-
const loaded = await analyzerPromise;
|
|
22
|
-
const importMs = importReported ? undefined : loaded.importMs;
|
|
23
|
-
importReported = true;
|
|
24
|
-
const analysis = loaded.analyzeMarkdownFile(task.absolutePath, task.content, task.latDir, task.projectRoot);
|
|
25
|
-
parentPort.postMessage({ id: task.id, analysis, importMs });
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
parentPort.postMessage({
|
|
29
|
-
id: task.id,
|
|
30
|
-
error: error instanceof Error ? error.message : String(error),
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
});
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import type { LatFrontmatter, MdLink, Ref, Section } from './lattice-model.js';
|
|
2
|
-
import { type LocalMarkdownDiagnostic } from './markdown-validation.js';
|
|
3
|
-
export type MarkdownParagraph = {
|
|
4
|
-
markdown: string;
|
|
5
|
-
startLine: number;
|
|
6
|
-
endLine: number;
|
|
7
|
-
text: string;
|
|
8
|
-
};
|
|
9
|
-
/** Source-positioned block facts; never retains the parser AST. */
|
|
10
|
-
export type MarkdownBlock = {
|
|
11
|
-
type: string;
|
|
12
|
-
start: number;
|
|
13
|
-
end: number;
|
|
14
|
-
startLine: number;
|
|
15
|
-
endLine: number;
|
|
16
|
-
language?: string;
|
|
17
|
-
children: MarkdownBlock[];
|
|
18
|
-
};
|
|
19
|
-
export type MarkdownDestinationLink = {
|
|
20
|
-
kind: 'image' | 'link';
|
|
21
|
-
line: number;
|
|
22
|
-
url: string;
|
|
23
|
-
};
|
|
24
|
-
export type MarkdownAnalysisTimings = {
|
|
25
|
-
readMs: number;
|
|
26
|
-
hashMs: number;
|
|
27
|
-
cacheReadMs: number;
|
|
28
|
-
cacheWriteMs: number;
|
|
29
|
-
cacheStatus: 'disabled' | 'hit' | 'miss';
|
|
30
|
-
parseMs: number;
|
|
31
|
-
sectionsMs: number;
|
|
32
|
-
refsMs: number;
|
|
33
|
-
linksMs: number;
|
|
34
|
-
paragraphsMs: number;
|
|
35
|
-
frontmatterMs: number;
|
|
36
|
-
indexEntriesMs: number;
|
|
37
|
-
diagnosticsMs: number;
|
|
38
|
-
};
|
|
39
|
-
/** Serializable semantic facts extracted from one Markdown file. */
|
|
40
|
-
export type MarkdownFileAnalysis = {
|
|
41
|
-
absolutePath: string;
|
|
42
|
-
content: string;
|
|
43
|
-
path: string;
|
|
44
|
-
projectPath: string;
|
|
45
|
-
frontmatter: LatFrontmatter;
|
|
46
|
-
sections: Section[];
|
|
47
|
-
headingTitles: string[];
|
|
48
|
-
wikiRefs: Ref[];
|
|
49
|
-
paragraphs: MarkdownParagraph[];
|
|
50
|
-
blocks: MarkdownBlock[];
|
|
51
|
-
markdownLinks: MarkdownDestinationLink[];
|
|
52
|
-
validationLinks: MdLink[];
|
|
53
|
-
indexEntries: string[];
|
|
54
|
-
diagnostics: LocalMarkdownDiagnostic[];
|
|
55
|
-
timings: MarkdownAnalysisTimings;
|
|
56
|
-
};
|
|
57
|
-
/**
|
|
58
|
-
* Parse and analyze one Markdown document. The syntax tree is deliberately
|
|
59
|
-
* confined to this call so callers and workers only exchange serializable facts.
|
|
60
|
-
*/
|
|
61
|
-
export declare function analyzeMarkdownFile(absolutePath: string, content: string, latDir: string, projectRoot: string): MarkdownFileAnalysis;
|