@plebeiantech/lat.md 0.12.3-fork.13 → 0.12.3-fork.15
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 +24 -0
- package/dist/src/cli/check-context.d.ts +56 -0
- package/dist/src/cli/check-context.js +215 -0
- package/dist/src/cli/check-coverage.js +9 -5
- package/dist/src/cli/check-frontmatter.js +1 -1
- package/dist/src/cli/check-mode.js +1 -1
- package/dist/src/cli/check-status.js +1 -1
- package/dist/src/cli/check.d.ts +19 -12
- package/dist/src/cli/check.js +259 -206
- package/dist/src/cli/context.js +1 -1
- package/dist/src/cli/expand.d.ts +1 -2
- package/dist/src/cli/expand.js +52 -5
- package/dist/src/cli/external.d.ts +11 -0
- package/dist/src/cli/external.js +185 -0
- package/dist/src/cli/fork-instructions.d.ts +1 -0
- package/dist/src/cli/fork-instructions.js +3 -2
- package/dist/src/cli/hook.d.ts +26 -0
- package/dist/src/cli/hook.js +112 -40
- package/dist/src/cli/index.js +55 -3
- package/dist/src/cli/init.d.ts +1 -0
- package/dist/src/cli/init.js +40 -2
- package/dist/src/cli/locate.js +4 -3
- package/dist/src/cli/refs.d.ts +2 -1
- package/dist/src/cli/refs.js +88 -43
- package/dist/src/cli/reindex.js +2 -1
- package/dist/src/cli/search.d.ts +12 -3
- package/dist/src/cli/search.js +45 -49
- package/dist/src/cli/section.d.ts +3 -1
- package/dist/src/cli/section.js +114 -38
- package/dist/src/code-refs.d.ts +17 -5
- package/dist/src/code-refs.js +246 -65
- package/dist/src/context.d.ts +3 -0
- package/dist/src/document-formats.d.ts +7 -0
- package/dist/src/document-formats.js +39 -0
- package/dist/src/extensions/alert-marker.d.ts +25 -0
- package/dist/src/extensions/alert-marker.js +55 -0
- package/dist/src/external-documents.d.ts +56 -0
- package/dist/src/external-documents.js +404 -0
- package/dist/src/external-sources.d.ts +136 -0
- package/dist/src/external-sources.js +1098 -0
- package/dist/src/fork/antigravity-hook.d.ts +47 -0
- package/dist/src/fork/antigravity-hook.js +424 -0
- package/dist/src/fork/antigravity-init.d.ts +17 -0
- package/dist/src/fork/antigravity-init.js +124 -0
- package/dist/src/fork/frontmatter-fields.d.ts +36 -0
- package/dist/src/fork/frontmatter-fields.js +23 -0
- package/dist/src/format.d.ts +5 -2
- package/dist/src/format.js +8 -3
- package/dist/src/graph-export.js +1 -1
- package/dist/src/lattice-model.d.ts +77 -0
- package/dist/src/lattice-model.js +464 -0
- package/dist/src/lattice.d.ts +9 -104
- package/dist/src/lattice.js +69 -516
- package/dist/src/markdown-analysis-cache.d.ts +20 -0
- package/dist/src/markdown-analysis-cache.js +139 -0
- package/dist/src/markdown-analysis-worker.d.ts +16 -0
- package/dist/src/markdown-analysis-worker.js +33 -0
- package/dist/src/markdown-analysis.d.ts +50 -0
- package/dist/src/markdown-analysis.js +139 -0
- package/dist/src/markdown-analyzer-loader.d.ts +4 -0
- package/dist/src/markdown-analyzer-loader.js +13 -0
- package/dist/src/markdown-validation.d.ts +25 -0
- package/dist/src/markdown-validation.js +104 -0
- package/dist/src/mcp/server.js +27 -11
- package/dist/src/parser-cache.d.ts +17 -0
- package/dist/src/parser-cache.js +65 -0
- package/dist/src/parser-import.d.ts +8 -0
- package/dist/src/parser-import.js +1 -0
- package/dist/src/parser.js +80 -5
- package/dist/src/path.d.ts +2 -0
- package/dist/src/path.js +4 -0
- package/dist/src/profiler.d.ts +16 -0
- package/dist/src/profiler.js +81 -0
- package/dist/src/project-analysis.d.ts +59 -0
- package/dist/src/project-analysis.js +233 -0
- package/dist/src/project-discovery.d.ts +6 -0
- package/dist/src/project-discovery.js +30 -0
- package/dist/src/repository-path.d.ts +11 -0
- package/dist/src/repository-path.js +52 -0
- package/dist/src/search/db.d.ts +1 -1
- package/dist/src/search/db.js +2 -2
- package/dist/src/search/embedder.d.ts +2 -1
- package/dist/src/search/embedder.js +6 -5
- package/dist/src/search/index.d.ts +2 -1
- package/dist/src/search/index.js +10 -8
- package/dist/src/search/query.d.ts +20 -0
- package/dist/src/search/query.js +67 -0
- package/dist/src/search/search.d.ts +3 -1
- package/dist/src/search/search.js +5 -2
- package/dist/src/source-formats.d.ts +7 -0
- package/dist/src/source-formats.js +26 -0
- package/dist/src/source-parser.d.ts +44 -4
- package/dist/src/source-parser.js +494 -57
- package/dist/src/view/client/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/src/view/client/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/src/view/client/assets/MarkdownEditor-B7quqPb8.js +28 -0
- package/dist/src/view/client/assets/OrbitControls-DwcpQNja.js +1 -0
- package/dist/src/view/client/assets/STLLoader-CLWTKt5i.js +1 -0
- package/dist/src/view/client/assets/abnfDiagram-VCTEODGH-V7-T6qsl.js +1 -0
- package/dist/src/view/client/assets/arc-BnwR8Bu7.js +1 -0
- package/dist/src/view/client/assets/architectureDiagram-5GKGNRK7-u97vDna9.js +36 -0
- package/dist/src/view/client/assets/blockDiagram-I7D4REHJ-DETl8e_H.js +129 -0
- package/dist/src/view/client/assets/c4Diagram-7LVT6UL2-DJRAT1Ve.js +38 -0
- package/dist/src/view/client/assets/channel-BwQbnWCN.js +1 -0
- package/dist/src/view/client/assets/chunk-2Q5K7J3B-C0TmOC1Q.js +1 -0
- package/dist/src/view/client/assets/chunk-5VM5RSS4-dfBOrYE6.js +15 -0
- package/dist/src/view/client/assets/chunk-F27PBJKO-DAnks99K.js +1 -0
- package/dist/src/view/client/assets/chunk-IMKFNOWR-CPjB07if.js +231 -0
- package/dist/src/view/client/assets/chunk-JWPE2WC7-VvU_gZI6.js +1 -0
- package/dist/src/view/client/assets/chunk-POPQ4Y6H-DDUbVF55.js +1 -0
- package/dist/src/view/client/assets/chunk-SVP7TREG-BHROkr6D.js +88 -0
- package/dist/src/view/client/assets/chunk-TICWLB2K-95PzGIOg.js +206 -0
- package/dist/src/view/client/assets/chunk-XXDRQBXY-MdmuLhIs.js +1 -0
- package/dist/src/view/client/assets/classDiagram-ZZMXUADV-HvQKkIS-.js +1 -0
- package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-HvQKkIS-.js +1 -0
- package/dist/src/view/client/assets/cose-bilkent-JH36ORCC-CauUf_rN.js +1 -0
- package/dist/src/view/client/assets/cynefin-OW5HDTMX-CeA8IKWo.js +166 -0
- package/dist/src/view/client/assets/cynefinDiagram-5FMLGOSQ-L1rtcT8l.js +62 -0
- package/dist/src/view/client/assets/cytoscape.esm-DzSz-X2X.js +321 -0
- package/dist/src/view/client/assets/dagre-GXQ25YYZ-DLQwTa3H.js +4 -0
- package/dist/src/view/client/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/src/view/client/assets/diagram-S7CK7UJ4-kbKdIyXG.js +30 -0
- package/dist/src/view/client/assets/diagram-UQ7AKVKN-kmzp92RC.js +41 -0
- package/dist/src/view/client/assets/diagram-VSXAHHWV-EXJTU8qq.js +3 -0
- package/dist/src/view/client/assets/diagram-VX7I27RA-DAiIyMCG.js +24 -0
- package/dist/src/view/client/assets/diagram-Z3DM3KII-G9wz50ZV.js +24 -0
- package/dist/src/view/client/assets/ebnfDiagram-PWID7BFC-D2tVRCNA.js +1 -0
- package/dist/src/view/client/assets/erDiagram-RLTQ6QDP-C925J5A3.js +99 -0
- package/dist/src/view/client/assets/flowDiagram-HODETNUW-DzoCa-Nq.js +168 -0
- package/dist/src/view/client/assets/ganttDiagram-EL5Y4UJY-D2ebbg4p.js +292 -0
- package/dist/src/view/client/assets/gitGraphDiagram-WWUBYQGX-B4QratYy.js +106 -0
- package/dist/src/view/client/assets/index-BnENo9bV.js +1 -0
- package/dist/src/view/client/assets/index-D0ajr_Ja.css +1 -0
- package/dist/src/view/client/assets/index-KZcnpXJH.js +321 -0
- package/dist/src/view/client/assets/infoDiagram-27XIBGKW-DL4mtHkt.js +2 -0
- package/dist/src/view/client/assets/init-Gi6I4Gst.js +1 -0
- package/dist/src/view/client/assets/ishikawaDiagram-5VMMS53U-CW4mto2d.js +70 -0
- package/dist/src/view/client/assets/journeyDiagram-3NMN7TZE-8R4eacFW.js +139 -0
- package/dist/src/view/client/assets/kanban-definition-UXKFOSKX-Cy9ioXEJ.js +89 -0
- package/dist/src/view/client/assets/katex-HP8lGamR.js +257 -0
- package/dist/src/view/client/assets/layout-C0MFuhth.js +1 -0
- package/dist/src/view/client/assets/linear-Dv3N4dQR.js +1 -0
- package/dist/src/view/client/assets/logo-small-RR_KBOAT.svg +149 -0
- package/dist/src/view/client/assets/maplibre-gl-DnqZgfUS.js +800 -0
- package/dist/src/view/client/assets/mermaid.core-bds9A7e2.js +310 -0
- package/dist/src/view/client/assets/mindmap-definition-YA3MSWOX-DjmGW355.js +96 -0
- package/dist/src/view/client/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/src/view/client/assets/pegDiagram-XKGWAZYB-BWsZp0ab.js +1 -0
- package/dist/src/view/client/assets/pieDiagram-E7YTZNPT-CCH2gGR-.js +39 -0
- package/dist/src/view/client/assets/quadrantDiagram-AXDQQJYC-CjocPJFz.js +7 -0
- package/dist/src/view/client/assets/railroadDiagram-O6MQD6OU-BjLeb2KF.js +1 -0
- package/dist/src/view/client/assets/requirementDiagram-BXWQKSXE-Ct6AoXRr.js +84 -0
- package/dist/src/view/client/assets/sankeyDiagram-P5KCCOFB-CIpgGN_w.js +40 -0
- package/dist/src/view/client/assets/sequenceDiagram-WJ2MYXX4-DrmLFj6w.js +162 -0
- package/dist/src/view/client/assets/sizeCapture-INFHLROL-BdFMe2Lr.js +1 -0
- package/dist/src/view/client/assets/stateDiagram-D77RDMKH-Zd9F1goW.js +1 -0
- package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-ByIKCftl.js +1 -0
- package/dist/src/view/client/assets/swimlanes-42K2YHIH-a7VFwi00.js +1 -0
- package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-CzxaUHB-.js +8 -0
- package/dist/src/view/client/assets/three.module-PDSP0dbZ.js +4108 -0
- package/dist/src/view/client/assets/timeline-definition-24CTP7MA-BExPu6X5.js +120 -0
- package/dist/src/view/client/assets/vennDiagram-4TSXK5OY-PC1MU3si.js +34 -0
- package/dist/src/view/client/assets/wardleyDiagram-VM6X3IG4-DNWqU3fa.js +78 -0
- package/dist/src/view/client/assets/xychartDiagram-S5SC5T6Z-E1uA28_D.js +7 -0
- package/dist/src/view/client/index.html +2 -2
- package/dist/src/view/client-shell.d.ts +2 -0
- package/dist/src/view/client-shell.js +5 -0
- package/dist/src/view/diagnostics.d.ts +3 -2
- package/dist/src/view/diagnostics.js +49 -58
- package/dist/src/view/document-edit.d.ts +8 -0
- package/dist/src/view/document-edit.js +25 -0
- package/dist/src/view/document-route.d.ts +12 -0
- package/dist/src/view/document-route.js +93 -0
- package/dist/src/view/document-tree.d.ts +18 -0
- package/dist/src/view/document-tree.js +139 -0
- package/dist/src/view/external-document-tree.d.ts +3 -0
- package/dist/src/view/external-document-tree.js +674 -0
- package/dist/src/view/git-diff.js +187 -0
- package/dist/src/view/git.js +1 -1
- package/dist/src/view/graph.d.ts +3 -2
- package/dist/src/view/graph.js +94 -7
- package/dist/src/view/highlight.d.ts +10 -2
- package/dist/src/view/highlight.js +4540 -1360
- package/dist/src/view/markdown.d.ts +3 -2
- package/dist/src/view/markdown.js +214 -53
- package/dist/src/view/protocol.d.ts +59 -6
- package/dist/src/view/references.d.ts +10 -25
- package/dist/src/view/references.js +117 -107
- package/dist/src/view/repository.d.ts +13 -3
- package/dist/src/view/repository.js +234 -15
- package/dist/src/view/search.d.ts +1 -1
- package/dist/src/view/search.js +3 -7
- package/dist/src/view/server.d.ts +11 -2
- package/dist/src/view/server.js +212 -70
- package/dist/src/view/source-target.js +5 -8
- package/dist/src/view/static-build.d.ts +1 -0
- package/dist/src/view/static-build.js +245 -42
- package/dist/src/view/static-protocol.d.ts +19 -2
- package/dist/src/view/store.d.ts +16 -3
- package/dist/src/view/store.js +228 -36
- package/dist/src/view/table-of-contents.d.ts +2 -2
- package/dist/src/view/table-of-contents.js +2 -22
- package/dist/src/walk.d.ts +5 -3
- package/dist/src/walk.js +102 -8
- package/dist/vendor/lat.md-server/cli.d.ts +2 -0
- package/dist/vendor/lat.md-server/cli.js +12 -0
- package/dist/vendor/lat.md-server/index.d.ts +38 -0
- package/dist/vendor/lat.md-server/index.js +128 -0
- package/package.json +52 -12
- package/plugins/lat-md/README.md +61 -0
- package/plugins/lat-md/hooks.json +38 -0
- package/plugins/lat-md/plugin.json +9 -0
- package/plugins/lat-md/rules/AGENTS.md +118 -0
- package/plugins/lat-md/skills/lat-md/SKILL.md +178 -0
- package/plugins/lat-md/skills/lat-md-conventions/SKILL.md +182 -0
- package/templates/AGENTS.md +15 -3
- package/templates/cursor-rules.md +12 -3
- package/templates/skill/SKILL.md +22 -1
- package/dist/src/view/client/assets/index-C3iaZyYT.css +0 -1
- package/dist/src/view/client/assets/index-KWi67IMz.js +0 -334
- package/dist/src/view/client/assets/logo-CNF8zs47.svg +0 -182
package/dist/src/code-refs.js
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
|
+
import { lstatSync } from 'node:fs';
|
|
1
2
|
import { readFile } from 'node:fs/promises';
|
|
2
3
|
import { execFile } from 'node:child_process';
|
|
4
|
+
import { availableParallelism } from 'node:os';
|
|
3
5
|
import { join, posix, relative } from 'node:path';
|
|
4
|
-
import {
|
|
6
|
+
import { isSourceFilePath, SOURCE_FILE_EXTENSIONS } from './source-formats.js';
|
|
7
|
+
import { toPosix } from './path.js';
|
|
8
|
+
import { ALWAYS_IGNORED_DIRECTORIES, walkEntries } from './walk.js';
|
|
5
9
|
/** Glob patterns used to exclude directories/files from code-ref scanning.
|
|
6
10
|
* Shared between rg args and the TS fallback's walkFiles filter. */
|
|
7
|
-
const EXCLUDE_DIRS = ['lat.md', '.claude'];
|
|
8
|
-
const EXCLUDE_GLOBS = ['*.md'];
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
const EXCLUDE_DIRS = ['lat.md', '.claude', ...ALWAYS_IGNORED_DIRECTORIES];
|
|
12
|
+
const EXCLUDE_GLOBS = ['*.md', '.*', '**/.*'];
|
|
13
|
+
const RG_IGNORE_ARGS = ['--no-require-git', '--ignore-file-case-insensitive'];
|
|
14
|
+
/** Walk supported source files for code-ref scanning. Uses walkEntries for
|
|
15
|
+
* .gitignore support, then additionally skips lat.md/, .claude/, generated
|
|
16
|
+
* UI output, and sub-projects. */
|
|
11
17
|
export async function walkFiles(dir) {
|
|
12
18
|
const entries = (await walkEntries(dir)).map(toPosix);
|
|
19
|
+
// Generated UI output carries a .lat-ui-build marker; the whole directory it
|
|
20
|
+
// marks is build product, not source, so nothing in it is a real code ref.
|
|
13
21
|
const generatedOutputs = new Set(entries
|
|
14
22
|
.filter((entry) => entry.endsWith('/.lat-ui-build'))
|
|
15
23
|
.map((entry) => `${posix.dirname(entry)}/`));
|
|
@@ -21,7 +29,7 @@ export async function walkFiles(dir) {
|
|
|
21
29
|
subProjects.add(e.slice(0, i + 1));
|
|
22
30
|
}
|
|
23
31
|
return entries
|
|
24
|
-
.filter((e) =>
|
|
32
|
+
.filter((e) => isSourceFilePath(e) &&
|
|
25
33
|
!e.startsWith('lat.md/') &&
|
|
26
34
|
!e.startsWith('.claude/') &&
|
|
27
35
|
![...generatedOutputs].some((prefix) => e.startsWith(prefix)) &&
|
|
@@ -97,6 +105,9 @@ function extractRefsFromLine(line) {
|
|
|
97
105
|
}
|
|
98
106
|
return targets;
|
|
99
107
|
}
|
|
108
|
+
function profileScan(profile, label, work) {
|
|
109
|
+
return profile ? profile.time(label, work) : work();
|
|
110
|
+
}
|
|
100
111
|
/**
|
|
101
112
|
* Run an external command and return stdout, or null if the command is not found
|
|
102
113
|
* or fails.
|
|
@@ -105,13 +116,13 @@ function tryExec(cmd, args, cwd) {
|
|
|
105
116
|
return new Promise((resolve) => {
|
|
106
117
|
execFile(cmd, args, { cwd, maxBuffer: 50 * 1024 * 1024 }, (err, out) => {
|
|
107
118
|
if (err) {
|
|
108
|
-
// Exit code 1 with no stderr typically means "no matches" for
|
|
119
|
+
// Exit code 1 with no stderr typically means "no matches" for rg.
|
|
109
120
|
const exitCode = err.code;
|
|
110
121
|
if (exitCode === 'ENOENT') {
|
|
111
122
|
resolve(null); // command not found
|
|
112
123
|
return;
|
|
113
124
|
}
|
|
114
|
-
// rg
|
|
125
|
+
// rg exit 1 = no matches (not an error)
|
|
115
126
|
if ('status' in err &&
|
|
116
127
|
err.status === 1 &&
|
|
117
128
|
out === '') {
|
|
@@ -134,7 +145,7 @@ async function findSubProjects(projectRoot) {
|
|
|
134
145
|
// List files inside any lat.md/ dir, then extract unique parent paths.
|
|
135
146
|
// The root lat.md/ is excluded by EXCLUDE_DIRS in the caller, so we only
|
|
136
147
|
// need to find nested ones here — search for files under */lat.md/.
|
|
137
|
-
const out = await tryExec('rg', ['--files', '--glob', '**/lat.md/**', '.'], projectRoot);
|
|
148
|
+
const out = await tryExec('rg', ['--files', ...RG_IGNORE_ARGS, '--glob', '**/lat.md/**', '.'], projectRoot);
|
|
138
149
|
if (!out)
|
|
139
150
|
return [];
|
|
140
151
|
const subProjects = new Set();
|
|
@@ -152,9 +163,69 @@ async function findSubProjects(projectRoot) {
|
|
|
152
163
|
}
|
|
153
164
|
return [...subProjects];
|
|
154
165
|
}
|
|
155
|
-
|
|
166
|
+
function nestedLatProjects(paths) {
|
|
167
|
+
const projects = new Set();
|
|
168
|
+
for (const path of paths) {
|
|
169
|
+
const index = path.indexOf('/lat.md/');
|
|
170
|
+
if (index !== -1)
|
|
171
|
+
projects.add(path.slice(0, index));
|
|
172
|
+
}
|
|
173
|
+
return [...projects];
|
|
174
|
+
}
|
|
175
|
+
function hasDotDirectory(path) {
|
|
176
|
+
const parts = path.split('/');
|
|
177
|
+
return parts.slice(0, -1).some((part) => part.startsWith('.'));
|
|
178
|
+
}
|
|
179
|
+
/** List readable regular source files tracked by the enclosing Git repository. */
|
|
180
|
+
async function findGitTrackedSourceFiles(projectRoot) {
|
|
181
|
+
const out = await tryExec('git', ['ls-files', '--stage', '-z', '--', '.'], projectRoot);
|
|
182
|
+
if (out === null)
|
|
183
|
+
return null;
|
|
184
|
+
const entries = out
|
|
185
|
+
.split('\0')
|
|
186
|
+
.filter(Boolean)
|
|
187
|
+
.flatMap((entry) => {
|
|
188
|
+
const tab = entry.indexOf('\t');
|
|
189
|
+
if (tab === -1)
|
|
190
|
+
return [];
|
|
191
|
+
const mode = entry.slice(0, entry.indexOf(' '));
|
|
192
|
+
if (mode !== '100644' && mode !== '100755')
|
|
193
|
+
return [];
|
|
194
|
+
return [toPosix(entry.slice(tab + 1))];
|
|
195
|
+
});
|
|
196
|
+
const subProjects = nestedLatProjects(entries);
|
|
197
|
+
const candidates = entries.filter((path) => isSourceFilePath(path) &&
|
|
198
|
+
!hasDotDirectory(path) &&
|
|
199
|
+
!path.startsWith('lat.md/') &&
|
|
200
|
+
!subProjects.some((project) => path === project || path.startsWith(`${project}/`)));
|
|
201
|
+
return candidates
|
|
202
|
+
.flatMap((path) => {
|
|
203
|
+
const absolute = join(projectRoot, path);
|
|
204
|
+
try {
|
|
205
|
+
return lstatSync(absolute).isFile() ? [absolute] : [];
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
if (error.code === 'ENOENT')
|
|
209
|
+
return [];
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
})
|
|
213
|
+
.sort((a, b) => a.localeCompare(b, 'en'));
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Directories holding generated UI output, found by the `.lat-ui-build` marker
|
|
217
|
+
* the build writes beside what it produces. Build product is not source, so a
|
|
218
|
+
* `@lat:` string inside it is not a reference to anything.
|
|
219
|
+
*/
|
|
156
220
|
async function findGeneratedOutputs(projectRoot) {
|
|
157
|
-
const out = await tryExec('rg', [
|
|
221
|
+
const out = await tryExec('rg', [
|
|
222
|
+
'--files',
|
|
223
|
+
'--hidden',
|
|
224
|
+
...RG_IGNORE_ARGS,
|
|
225
|
+
'--glob',
|
|
226
|
+
'**/.lat-ui-build',
|
|
227
|
+
'.',
|
|
228
|
+
], projectRoot);
|
|
158
229
|
if (!out)
|
|
159
230
|
return [];
|
|
160
231
|
return [
|
|
@@ -167,7 +238,7 @@ async function findGeneratedOutputs(projectRoot) {
|
|
|
167
238
|
];
|
|
168
239
|
}
|
|
169
240
|
/** Build rg glob exclusion args. */
|
|
170
|
-
function rgExcludeArgs(subProjects, generatedOutputs) {
|
|
241
|
+
function rgExcludeArgs(subProjects, generatedOutputs = []) {
|
|
171
242
|
const args = [];
|
|
172
243
|
for (const dir of EXCLUDE_DIRS)
|
|
173
244
|
args.push('--glob', `!${dir}/`);
|
|
@@ -179,44 +250,105 @@ function rgExcludeArgs(subProjects, generatedOutputs) {
|
|
|
179
250
|
args.push('--glob', `!${output}/`);
|
|
180
251
|
return args;
|
|
181
252
|
}
|
|
182
|
-
/**
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
253
|
+
/** Build an rg file type from the shared supported-source registry. */
|
|
254
|
+
function rgSourceIncludeArgs() {
|
|
255
|
+
return [
|
|
256
|
+
...SOURCE_FILE_EXTENSIONS.flatMap((extension) => [
|
|
257
|
+
'--type-add',
|
|
258
|
+
`latsource:*${extension}`,
|
|
259
|
+
]),
|
|
260
|
+
'--type',
|
|
261
|
+
'latsource',
|
|
262
|
+
];
|
|
263
|
+
}
|
|
264
|
+
async function discoverRipgrepExcludes(projectRoot, profile) {
|
|
265
|
+
const [subProjects, generatedOutputs] = await Promise.all([
|
|
266
|
+
profileScan(profile, 'find nested lat.md projects with ripgrep', () => findSubProjects(projectRoot)),
|
|
267
|
+
profileScan(profile, 'find generated UI output with ripgrep', () => findGeneratedOutputs(projectRoot)),
|
|
268
|
+
]);
|
|
269
|
+
return rgExcludeArgs(subProjects, generatedOutputs);
|
|
270
|
+
}
|
|
271
|
+
function ripgrepPathBatches(paths) {
|
|
272
|
+
const batches = [];
|
|
273
|
+
let batch = [];
|
|
274
|
+
let length = 0;
|
|
275
|
+
for (const path of paths) {
|
|
276
|
+
if (batch.length > 0 && length + path.length + 1 > 16_000) {
|
|
277
|
+
batches.push(batch);
|
|
278
|
+
batch = [];
|
|
279
|
+
length = 0;
|
|
280
|
+
}
|
|
281
|
+
batch.push(path);
|
|
282
|
+
length += path.length + 1;
|
|
283
|
+
}
|
|
284
|
+
if (batch.length > 0)
|
|
285
|
+
batches.push(batch);
|
|
286
|
+
return batches;
|
|
287
|
+
}
|
|
288
|
+
async function runRipgrepBatches(projectRoot, args, paths) {
|
|
289
|
+
const batches = ripgrepPathBatches(paths);
|
|
290
|
+
if (batches.length === 0)
|
|
291
|
+
return [];
|
|
292
|
+
const results = new Array(batches.length);
|
|
293
|
+
let nextIndex = 0;
|
|
294
|
+
const workerCount = Math.min(availableParallelism(), batches.length);
|
|
295
|
+
await Promise.all(Array.from({ length: workerCount }, async () => {
|
|
296
|
+
while (true) {
|
|
297
|
+
const index = nextIndex++;
|
|
298
|
+
if (index >= batches.length)
|
|
299
|
+
return;
|
|
300
|
+
results[index] = await tryExec('rg', [...args, '--', ...batches[index]], projectRoot);
|
|
301
|
+
}
|
|
302
|
+
}));
|
|
303
|
+
return results.some((result) => result === null)
|
|
304
|
+
? null
|
|
305
|
+
: results;
|
|
306
|
+
}
|
|
307
|
+
/** Search supported source files for code references with ripgrep. */
|
|
308
|
+
async function tryRipgrepCodeRefs(projectRoot, excludes, profile, files) {
|
|
193
309
|
const searchArgs = [
|
|
194
310
|
'--no-heading',
|
|
195
311
|
'--line-number',
|
|
196
312
|
'--with-filename',
|
|
313
|
+
...RG_IGNORE_ARGS,
|
|
314
|
+
...rgSourceIncludeArgs(),
|
|
197
315
|
...excludes,
|
|
198
316
|
'@lat:.*\\[\\[',
|
|
199
|
-
'.',
|
|
200
317
|
];
|
|
201
|
-
const
|
|
202
|
-
|
|
318
|
+
const outputs = await profileScan(profile, 'scan @lat references with ripgrep', () => files
|
|
319
|
+
? runRipgrepBatches(projectRoot, searchArgs, files.map((file) => toPosix(relative(projectRoot, file))))
|
|
320
|
+
: tryExec('rg', [...searchArgs, '.'], projectRoot).then((output) => output === null ? null : [output]));
|
|
321
|
+
if (outputs === null)
|
|
322
|
+
return null;
|
|
323
|
+
const refs = outputs.flatMap((output) => parseGrepOutput(output, projectRoot).refs);
|
|
324
|
+
refs.sort((a, b) => a.file.localeCompare(b.file, 'en') || a.line - b.line);
|
|
325
|
+
return refs;
|
|
326
|
+
}
|
|
327
|
+
/** Discover the supported source-file scope with ripgrep. */
|
|
328
|
+
async function tryRipgrepSourceFiles(projectRoot, excludes, profile) {
|
|
329
|
+
const filesOut = await profileScan(profile, 'list source files with ripgrep', () => tryExec('rg', [
|
|
330
|
+
'--files',
|
|
331
|
+
...RG_IGNORE_ARGS,
|
|
332
|
+
...rgSourceIncludeArgs(),
|
|
333
|
+
...excludes,
|
|
334
|
+
'.',
|
|
335
|
+
], projectRoot));
|
|
336
|
+
if (filesOut === null)
|
|
203
337
|
return null;
|
|
204
|
-
const { refs } = parseGrepOutput(out);
|
|
205
|
-
// List all scanned files (for stats) — rg --files is fast
|
|
206
|
-
const filesOut = await tryExec('rg', ['--files', ...excludes, '.'], projectRoot);
|
|
207
338
|
const files = (filesOut || '')
|
|
208
339
|
.split('\n')
|
|
209
340
|
.filter(Boolean)
|
|
210
341
|
.map((f) => {
|
|
211
342
|
const clean = toPosix(f).replace(/^\.\//, '');
|
|
212
343
|
return join(projectRoot, clean);
|
|
213
|
-
})
|
|
214
|
-
|
|
344
|
+
})
|
|
345
|
+
.sort((a, b) => a.localeCompare(b, 'en'));
|
|
346
|
+
return files;
|
|
215
347
|
}
|
|
216
348
|
/**
|
|
217
349
|
* Parse rg output lines (file:line:content) into CodeRef entries.
|
|
218
350
|
*/
|
|
219
|
-
function parseGrepOutput(output) {
|
|
351
|
+
function parseGrepOutput(output, projectRoot) {
|
|
220
352
|
const refs = [];
|
|
221
353
|
if (!output.trim())
|
|
222
354
|
return { refs };
|
|
@@ -250,30 +382,51 @@ function parseGrepOutput(output) {
|
|
|
250
382
|
}
|
|
251
383
|
return { refs };
|
|
252
384
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
385
|
+
async function scanFileWithTs(file, projectRoot) {
|
|
386
|
+
let content;
|
|
387
|
+
try {
|
|
388
|
+
content = await readFile(file, 'utf-8');
|
|
389
|
+
}
|
|
390
|
+
catch (err) {
|
|
391
|
+
return {
|
|
392
|
+
refs: [],
|
|
393
|
+
error: `Error: failed to read ${file}: ${err.message}\n`,
|
|
394
|
+
};
|
|
395
|
+
}
|
|
257
396
|
const refs = [];
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
397
|
+
const relativePath = toPosix(relative(projectRoot, file));
|
|
398
|
+
const lines = content.split('\n');
|
|
399
|
+
for (let i = 0; i < lines.length; i++) {
|
|
400
|
+
// Same literal-span and `lat:ignore` filtering the ripgrep path applies in
|
|
401
|
+
// parseGrepOutput, so both paths agree on what counts as a reference.
|
|
402
|
+
for (const target of extractRefsFromLine(lines[i])) {
|
|
403
|
+
refs.push({
|
|
404
|
+
target,
|
|
405
|
+
file: relativePath,
|
|
406
|
+
line: i + 1,
|
|
407
|
+
});
|
|
266
408
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
409
|
+
}
|
|
410
|
+
return { refs };
|
|
411
|
+
}
|
|
412
|
+
/** TypeScript fallback: scan supported source files through a bounded pool. */
|
|
413
|
+
async function scanWithTs(files, projectRoot) {
|
|
414
|
+
const results = new Array(files.length);
|
|
415
|
+
let nextIndex = 0;
|
|
416
|
+
const workerCount = Math.min(availableParallelism(), files.length);
|
|
417
|
+
await Promise.all(Array.from({ length: workerCount }, async () => {
|
|
418
|
+
while (true) {
|
|
419
|
+
const index = nextIndex++;
|
|
420
|
+
if (index >= files.length)
|
|
421
|
+
return;
|
|
422
|
+
results[index] = await scanFileWithTs(files[index], projectRoot);
|
|
276
423
|
}
|
|
424
|
+
}));
|
|
425
|
+
const refs = [];
|
|
426
|
+
for (const result of results) {
|
|
427
|
+
if (result.error)
|
|
428
|
+
process.stderr.write(result.error);
|
|
429
|
+
refs.push(...result.refs);
|
|
277
430
|
}
|
|
278
431
|
return refs;
|
|
279
432
|
}
|
|
@@ -282,17 +435,45 @@ export async function hasRipgrep() {
|
|
|
282
435
|
const result = await tryExec('rg', ['--version'], '.');
|
|
283
436
|
return result !== null;
|
|
284
437
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
438
|
+
/**
|
|
439
|
+
* Create a lazy project-scoped discovery API. Code-reference scanning and
|
|
440
|
+
* source-file inventory are separate operations, but share ripgrep exclusion
|
|
441
|
+
* discovery and coalesce fallback file walking when both are requested.
|
|
442
|
+
*/
|
|
443
|
+
export function createCodeReferenceDiscovery(projectRoot, profile) {
|
|
444
|
+
let excludesPromise;
|
|
445
|
+
let trackedFilesPromise;
|
|
446
|
+
let sourceFilesPromise;
|
|
447
|
+
let scanPromise;
|
|
448
|
+
const ripgrepExcludes = () => (excludesPromise ??= discoverRipgrepExcludes(projectRoot, profile));
|
|
449
|
+
const trackedFiles = () => (trackedFilesPromise ??= profileScan(profile, 'list tracked source files with git', () => findGitTrackedSourceFiles(projectRoot)));
|
|
450
|
+
const listSourceFiles = () => (sourceFilesPromise ??= (async () => {
|
|
451
|
+
const tracked = await trackedFiles();
|
|
452
|
+
if (tracked !== null)
|
|
453
|
+
return tracked;
|
|
454
|
+
if (process.env._LAT_DISABLE_RG !== '1') {
|
|
455
|
+
const files = await tryRipgrepSourceFiles(projectRoot, await ripgrepExcludes(), profile);
|
|
456
|
+
if (files !== null)
|
|
457
|
+
return files;
|
|
292
458
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
459
|
+
return profileScan(profile, 'walk project source files', () => walkFiles(projectRoot));
|
|
460
|
+
})());
|
|
461
|
+
const scan = () => (scanPromise ??= (async () => {
|
|
462
|
+
const tracked = await trackedFiles();
|
|
463
|
+
if (process.env._LAT_DISABLE_RG !== '1') {
|
|
464
|
+
const refs = await tryRipgrepCodeRefs(projectRoot, tracked === null ? await ripgrepExcludes() : [], profile, tracked ?? undefined);
|
|
465
|
+
if (refs !== null)
|
|
466
|
+
return { refs };
|
|
467
|
+
}
|
|
468
|
+
const refs = await profileScan(profile, 'scan project files with TypeScript fallback', async () => scanWithTs(await listSourceFiles(), projectRoot));
|
|
469
|
+
return { refs };
|
|
470
|
+
})());
|
|
471
|
+
return { scan, listSourceFiles };
|
|
472
|
+
}
|
|
473
|
+
export async function scanCodeRefs(projectRoot, profile) {
|
|
474
|
+
return createCodeReferenceDiscovery(projectRoot, profile).scan();
|
|
475
|
+
}
|
|
476
|
+
/** Discover the source files that may contain code references. */
|
|
477
|
+
export async function discoverSourceFiles(projectRoot, profile) {
|
|
478
|
+
return createCodeReferenceDiscovery(projectRoot, profile).listSourceFiles();
|
|
298
479
|
}
|
package/dist/src/context.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MarkdownProjectSession } from './project-analysis.js';
|
|
1
2
|
export type Styler = {
|
|
2
3
|
bold: (s: string) => string;
|
|
3
4
|
dim: (s: string) => string;
|
|
@@ -16,6 +17,8 @@ export type CmdContext = {
|
|
|
16
17
|
mode: 'cli' | 'mcp';
|
|
17
18
|
/** The check target was supplied explicitly instead of discovered as lat.md. */
|
|
18
19
|
headless?: boolean;
|
|
20
|
+
/** Lazy Markdown analysis shared by nested operations in this request. */
|
|
21
|
+
analysis?: MarkdownProjectSession;
|
|
19
22
|
};
|
|
20
23
|
export type CmdResult = {
|
|
21
24
|
output: string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Document formats that external sources can resolve by heading. */
|
|
2
|
+
export declare const DOCUMENT_FILE_EXTENSIONS: ReadonlySet<string>;
|
|
3
|
+
export type DocumentFormat = 'asciidoc' | 'markdown' | 'restructuredtext';
|
|
4
|
+
export declare function documentFormat(path: string): DocumentFormat | null;
|
|
5
|
+
export declare function isDocumentPath(path: string): boolean;
|
|
6
|
+
export declare function stripDocumentExtension(path: string): string;
|
|
7
|
+
export declare function documentFormatLabel(format: DocumentFormat): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** Document formats that external sources can resolve by heading. */
|
|
2
|
+
export const DOCUMENT_FILE_EXTENSIONS = new Set([
|
|
3
|
+
'.adoc',
|
|
4
|
+
'.asciidoc',
|
|
5
|
+
'.md',
|
|
6
|
+
'.rst',
|
|
7
|
+
]);
|
|
8
|
+
export function documentFormat(path) {
|
|
9
|
+
const lower = path.toLowerCase();
|
|
10
|
+
if (lower.endsWith('.md'))
|
|
11
|
+
return 'markdown';
|
|
12
|
+
if (lower.endsWith('.rst'))
|
|
13
|
+
return 'restructuredtext';
|
|
14
|
+
if (lower.endsWith('.adoc') || lower.endsWith('.asciidoc')) {
|
|
15
|
+
return 'asciidoc';
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
export function isDocumentPath(path) {
|
|
20
|
+
return documentFormat(path) !== null;
|
|
21
|
+
}
|
|
22
|
+
export function stripDocumentExtension(path) {
|
|
23
|
+
const lower = path.toLowerCase();
|
|
24
|
+
for (const extension of DOCUMENT_FILE_EXTENSIONS) {
|
|
25
|
+
if (lower.endsWith(extension))
|
|
26
|
+
return path.slice(0, -extension.length);
|
|
27
|
+
}
|
|
28
|
+
return path;
|
|
29
|
+
}
|
|
30
|
+
export function documentFormatLabel(format) {
|
|
31
|
+
switch (format) {
|
|
32
|
+
case 'asciidoc':
|
|
33
|
+
return 'AsciiDoc';
|
|
34
|
+
case 'markdown':
|
|
35
|
+
return 'Markdown';
|
|
36
|
+
case 'restructuredtext':
|
|
37
|
+
return 'reStructuredText';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Data, Literal, Root } from 'mdast';
|
|
2
|
+
import type { Options } from 'mdast-util-to-markdown';
|
|
3
|
+
export declare const ALERT_KINDS: readonly ["NOTE", "TIP", "IMPORTANT", "WARNING", "CAUTION"];
|
|
4
|
+
export type AlertKind = (typeof ALERT_KINDS)[number];
|
|
5
|
+
export interface AlertMarker extends Literal {
|
|
6
|
+
type: 'alertMarker';
|
|
7
|
+
value: AlertKind;
|
|
8
|
+
data?: Data;
|
|
9
|
+
}
|
|
10
|
+
/** Promote GitHub alert markers so serialization does not escape their brackets. */
|
|
11
|
+
export declare function markAlertMarkers(tree: Root): void;
|
|
12
|
+
export declare function alertMarkerToMarkdown(): Options;
|
|
13
|
+
declare module 'mdast' {
|
|
14
|
+
interface RootContentMap {
|
|
15
|
+
alertMarker: AlertMarker;
|
|
16
|
+
}
|
|
17
|
+
interface PhrasingContentMap {
|
|
18
|
+
alertMarker: AlertMarker;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
declare module 'mdast-util-to-markdown' {
|
|
22
|
+
interface ConstructNameMap {
|
|
23
|
+
alertMarker: 'alertMarker';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { visit } from 'unist-util-visit';
|
|
2
|
+
export const ALERT_KINDS = [
|
|
3
|
+
'NOTE',
|
|
4
|
+
'TIP',
|
|
5
|
+
'IMPORTANT',
|
|
6
|
+
'WARNING',
|
|
7
|
+
'CAUTION',
|
|
8
|
+
];
|
|
9
|
+
const ALERT_PATTERN = /^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\](?:\r?\n|$)/;
|
|
10
|
+
/** Promote GitHub alert markers so serialization does not escape their brackets. */
|
|
11
|
+
export function markAlertMarkers(tree) {
|
|
12
|
+
visit(tree, 'blockquote', (node) => {
|
|
13
|
+
const firstBlock = node.children[0];
|
|
14
|
+
if (firstBlock?.type !== 'paragraph')
|
|
15
|
+
return;
|
|
16
|
+
const firstInline = firstBlock.children[0];
|
|
17
|
+
if (firstInline?.type !== 'text')
|
|
18
|
+
return;
|
|
19
|
+
const match = firstInline.value.match(ALERT_PATTERN);
|
|
20
|
+
if (!match)
|
|
21
|
+
return;
|
|
22
|
+
const marker = {
|
|
23
|
+
type: 'alertMarker',
|
|
24
|
+
value: match[1],
|
|
25
|
+
};
|
|
26
|
+
const start = firstInline.position?.start;
|
|
27
|
+
if (start) {
|
|
28
|
+
const markerLength = match[0].replace(/\r?\n$/, '').length;
|
|
29
|
+
marker.position = {
|
|
30
|
+
start,
|
|
31
|
+
end: {
|
|
32
|
+
line: start.line,
|
|
33
|
+
column: start.column + markerLength,
|
|
34
|
+
...(start.offset === undefined
|
|
35
|
+
? {}
|
|
36
|
+
: { offset: start.offset + markerLength }),
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const remaining = firstInline.value.slice(match[0].length);
|
|
41
|
+
const replacement = [marker];
|
|
42
|
+
if (remaining !== '')
|
|
43
|
+
replacement.push({ type: 'text', value: remaining });
|
|
44
|
+
firstBlock.children.splice(0, 1, ...replacement);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function alertMarkerHandler(node, _parent, state, _info) {
|
|
48
|
+
const exit = state.enter('alertMarker');
|
|
49
|
+
const value = `[!${node.value}]\n`;
|
|
50
|
+
exit();
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
export function alertMarkerToMarkdown() {
|
|
54
|
+
return { handlers: { alertMarker: alertMarkerHandler } };
|
|
55
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type Section } from './lattice-model.js';
|
|
2
|
+
import { type DocumentFormat } from './document-formats.js';
|
|
3
|
+
import type { ParserImportObserver } from './parser-import.js';
|
|
4
|
+
import type { ViewDocumentTree } from './view/protocol.js';
|
|
5
|
+
export type ExternalDocumentSection = {
|
|
6
|
+
title: string;
|
|
7
|
+
depth: number;
|
|
8
|
+
anchor: string;
|
|
9
|
+
aliases: string[];
|
|
10
|
+
hierarchy: string[];
|
|
11
|
+
startLine: number;
|
|
12
|
+
endLine: number;
|
|
13
|
+
};
|
|
14
|
+
/** Serializable document facts retained after a format parser discards its AST. */
|
|
15
|
+
export type ExternalDocumentAnalysis = {
|
|
16
|
+
format: DocumentFormat;
|
|
17
|
+
title: string;
|
|
18
|
+
sections: ExternalDocumentSection[];
|
|
19
|
+
};
|
|
20
|
+
export type ExternalDocumentCacheStatus = 'disabled' | 'hit' | 'miss';
|
|
21
|
+
export type ExternalDocumentAnalysisTimings = {
|
|
22
|
+
hashMs: number;
|
|
23
|
+
cacheReadMs: number;
|
|
24
|
+
cacheWriteMs: number;
|
|
25
|
+
parseMs: number;
|
|
26
|
+
cacheStatus: ExternalDocumentCacheStatus;
|
|
27
|
+
};
|
|
28
|
+
export type ExternalDocumentFileAnalysis = {
|
|
29
|
+
path: string;
|
|
30
|
+
document: ExternalDocumentAnalysis;
|
|
31
|
+
timings: ExternalDocumentAnalysisTimings;
|
|
32
|
+
};
|
|
33
|
+
export type AnalyzeExternalDocumentOptions = {
|
|
34
|
+
identity?: string;
|
|
35
|
+
cache?: boolean;
|
|
36
|
+
runtime?: ExternalDocumentParserRuntime;
|
|
37
|
+
onFileAnalyzed?: (analysis: ExternalDocumentFileAnalysis) => void;
|
|
38
|
+
onParserImport?: ParserImportObserver;
|
|
39
|
+
};
|
|
40
|
+
/** Accept legacy AsciiDoc source listings whose delimiter lengths do not match. */
|
|
41
|
+
export declare function asciidocCompatibleContent(content: string): string;
|
|
42
|
+
export declare function analyzeExternalDocument(path: string, content: string, onParserImport?: ParserImportObserver, importDetail?: string): Promise<ExternalDocumentAnalysis>;
|
|
43
|
+
/** Request-scoped owner for external document parser work. */
|
|
44
|
+
export declare class ExternalDocumentParserRuntime {
|
|
45
|
+
readonly analyses: Map<string, Promise<ExternalDocumentFileAnalysis>>;
|
|
46
|
+
clear(): void;
|
|
47
|
+
}
|
|
48
|
+
/** Return the shared parsed-cache path for one external document identity. */
|
|
49
|
+
export declare function externalDocumentAnalysisCachePath(latDir: string, identity: string): string;
|
|
50
|
+
/** Analyze an external document through the shared persistent parser cache. */
|
|
51
|
+
export declare function analyzeExternalDocumentCached(path: string, content: string, latDir: string, options?: AnalyzeExternalDocumentOptions): Promise<ExternalDocumentFileAnalysis>;
|
|
52
|
+
export declare function findExternalDocumentSection(analysis: ExternalDocumentAnalysis, fragment: string): ExternalDocumentSection | undefined;
|
|
53
|
+
/** Project format-neutral document sections into the existing browser TOC model. */
|
|
54
|
+
export declare function externalDocumentSections(path: string, analysis: ExternalDocumentAnalysis): Section[];
|
|
55
|
+
/** Add zero-size alias anchors to the normalized external document tree. */
|
|
56
|
+
export declare function addExternalDocumentAliasAnchors(source: ViewDocumentTree, analysis: ExternalDocumentAnalysis): ViewDocumentTree;
|