260719_5
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
.b03-file {
|
.b03-file {
|
||||||
min-height: calc(100vh - var(--app-header-height, 0px));
|
min-height: calc(100vh - var(--app-header-height, 0px));
|
||||||
background: linear-gradient(180deg, var(--color-canvas, #ffffff) 0%, var(--color-mist-violet, #edecff) 100%);
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
var(--color-canvas, #ffffff) 0%,
|
||||||
|
var(--color-mist-violet, #edecff) 100%
|
||||||
|
);
|
||||||
padding: 0 var(--spacing-24) var(--spacing-48) var(--spacing-24); /* 상단 여백은 main-layout 마진으로 조정하므로 padding-top은 0 */
|
padding: 0 var(--spacing-24) var(--spacing-48) var(--spacing-24); /* 상단 여백은 main-layout 마진으로 조정하므로 padding-top은 0 */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +56,10 @@
|
|||||||
gap: var(--spacing-8);
|
gap: var(--spacing-8);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transition: background var(--transition-base, 0.2s), border-color var(--transition-base, 0.2s), box-shadow var(--transition-base, 0.2s);
|
transition:
|
||||||
|
background var(--transition-base, 0.2s),
|
||||||
|
border-color var(--transition-base, 0.2s),
|
||||||
|
box-shadow var(--transition-base, 0.2s);
|
||||||
}
|
}
|
||||||
|
|
||||||
.b03-file__dropzone:hover {
|
.b03-file__dropzone:hover {
|
||||||
@@ -140,7 +147,10 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--spacing-20);
|
gap: var(--spacing-20);
|
||||||
transition: transform var(--transition-base, 0.2s), border-color var(--transition-base, 0.2s), box-shadow var(--transition-base, 0.2s);
|
transition:
|
||||||
|
transform var(--transition-base, 0.2s),
|
||||||
|
border-color var(--transition-base, 0.2s),
|
||||||
|
box-shadow var(--transition-base, 0.2s);
|
||||||
}
|
}
|
||||||
|
|
||||||
.b03-file__card:hover {
|
.b03-file__card:hover {
|
||||||
@@ -258,7 +268,9 @@
|
|||||||
font-size: var(--text-body-sm, 14px);
|
font-size: var(--text-body-sm, 14px);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-bottom: var(--spacing-8); /* 파일 선택 버튼 하단 마진 추가 */
|
margin-bottom: var(--spacing-8); /* 파일 선택 버튼 하단 마진 추가 */
|
||||||
transition: background var(--transition-base, 0.2s), border-color var(--transition-base, 0.2s);
|
transition:
|
||||||
|
background var(--transition-base, 0.2s),
|
||||||
|
border-color var(--transition-base, 0.2s);
|
||||||
}
|
}
|
||||||
|
|
||||||
.b03-file__file-info {
|
.b03-file__file-info {
|
||||||
@@ -373,4 +385,3 @@
|
|||||||
grid-template-columns: 1fr; /* 모바일에서는 1행 1열 구조 */
|
grid-template-columns: 1fr; /* 모바일에서는 1행 1열 구조 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { createWorkflowPanelHandle } from "@ui/ui_template_overlay";
|
|||||||
import "../B06_wf3_ProfileCross/B06_wf3_ProfileCross_UI_Style.css";
|
import "../B06_wf3_ProfileCross/B06_wf3_ProfileCross_UI_Style.css";
|
||||||
|
|
||||||
const COLLAPSED_KEY = "b05-route-profile-collapsed";
|
const COLLAPSED_KEY = "b05-route-profile-collapsed";
|
||||||
|
const HORIZONTAL_SCROLLBAR_HEIGHT = 16;
|
||||||
|
|
||||||
function normalizedLongitudinal(data: LongitudinalSection): LongitudinalSection {
|
function normalizedLongitudinal(data: LongitudinalSection): LongitudinalSection {
|
||||||
return {
|
return {
|
||||||
@@ -43,11 +44,9 @@ export function createRouteProfilePanel(onSelectStation: (stationId: string) =>
|
|||||||
function draw(): void {
|
function draw(): void {
|
||||||
if (!detail || body.clientWidth <= 0 || body.clientHeight <= 0) return;
|
if (!detail || body.clientWidth <= 0 || body.clientHeight <= 0) return;
|
||||||
const availableWidth = Math.max(1, body.clientWidth - 30);
|
const availableWidth = Math.max(1, body.clientWidth - 30);
|
||||||
const height = body.clientHeight;
|
const height = Math.max(1, body.clientHeight - HORIZONTAL_SCROLLBAR_HEIGHT);
|
||||||
const width = Math.max(
|
const minimumWidth = longitudinalMinimumWidth(detail.longitudinal, stationInterval);
|
||||||
availableWidth,
|
const width = Math.max(availableWidth, minimumWidth);
|
||||||
longitudinalMinimumWidth(detail.longitudinal, stationInterval),
|
|
||||||
);
|
|
||||||
lastWidth = body.clientWidth;
|
lastWidth = body.clientWidth;
|
||||||
lastHeight = height;
|
lastHeight = height;
|
||||||
body.replaceChildren(
|
body.replaceChildren(
|
||||||
@@ -60,6 +59,7 @@ export function createRouteProfilePanel(onSelectStation: (stationId: string) =>
|
|||||||
stationInterval,
|
stationInterval,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
minimumWidth,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ const LONG_WIDTH = 1200;
|
|||||||
const LONG_HEIGHT = 220;
|
const LONG_HEIGHT = 220;
|
||||||
const CROSS_WIDTH = 560;
|
const CROSS_WIDTH = 560;
|
||||||
const CROSS_HEIGHT = 250;
|
const CROSS_HEIGHT = 250;
|
||||||
|
const CROSS_GRID_MIN_WIDTH = 480;
|
||||||
|
const CROSS_GRID_GAP = 16;
|
||||||
const LONG_PAD = { left: 62, right: 24, top: 30, bottom: 52 };
|
const LONG_PAD = { left: 62, right: 24, top: 30, bottom: 52 };
|
||||||
const CROSS_PAD = { left: 58, right: 20, top: 20, bottom: 52 };
|
const CROSS_PAD = { left: 58, right: 20, top: 20, bottom: 52 };
|
||||||
|
|
||||||
@@ -119,6 +121,7 @@ export function createLongitudinalProfile(
|
|||||||
configuredStationInterval?: number,
|
configuredStationInterval?: number,
|
||||||
widthPx = LONG_WIDTH,
|
widthPx = LONG_WIDTH,
|
||||||
heightPx = LONG_HEIGHT,
|
heightPx = LONG_HEIGHT,
|
||||||
|
minimumWidthPx = widthPx,
|
||||||
): HTMLElement {
|
): HTMLElement {
|
||||||
const samples = data.samples.filter(validElevation);
|
const samples = data.samples.filter(validElevation);
|
||||||
if (samples.length < 2) return emptyView(L("B06_Profile_View_NoLongitudinal"));
|
if (samples.length < 2) return emptyView(L("B06_Profile_View_NoLongitudinal"));
|
||||||
@@ -133,6 +136,8 @@ export function createLongitudinalProfile(
|
|||||||
role: "img",
|
role: "img",
|
||||||
"aria-label": L("B06_Profile_View_Longitudinal"),
|
"aria-label": L("B06_Profile_View_Longitudinal"),
|
||||||
});
|
});
|
||||||
|
svg.style.width = "100%";
|
||||||
|
svg.style.minWidth = `${minimumWidthPx}px`;
|
||||||
svg.append(svgElement("rect", { width: widthPx, height: heightPx, class: "b06-chart__bg" }));
|
svg.append(svgElement("rect", { width: widthPx, height: heightPx, class: "b06-chart__bg" }));
|
||||||
|
|
||||||
const maxChainage = Math.max(data.length_m, samples[samples.length - 1]?.chainage_m ?? 1, 1);
|
const maxChainage = Math.max(data.length_m, samples[samples.length - 1]?.chainage_m ?? 1, 1);
|
||||||
@@ -499,6 +504,7 @@ export function createSectionView(): SectionViewController {
|
|||||||
|
|
||||||
const longitudinalPanel = document.createElement("section");
|
const longitudinalPanel = document.createElement("section");
|
||||||
longitudinalPanel.className = "b06-section__panel";
|
longitudinalPanel.className = "b06-section__panel";
|
||||||
|
const longitudinalMinWidth = longitudinalMinimumWidth(detail.longitudinal, stationInterval);
|
||||||
longitudinalPanel.append(
|
longitudinalPanel.append(
|
||||||
createLongitudinalProfile(
|
createLongitudinalProfile(
|
||||||
detail.longitudinal,
|
detail.longitudinal,
|
||||||
@@ -507,8 +513,9 @@ export function createSectionView(): SectionViewController {
|
|||||||
yScale,
|
yScale,
|
||||||
(stationId) => selectStation(stationId, true),
|
(stationId) => selectStation(stationId, true),
|
||||||
stationInterval,
|
stationInterval,
|
||||||
Math.max(renderWidth, longitudinalMinimumWidth(detail.longitudinal, stationInterval)),
|
Math.max(renderWidth, longitudinalMinWidth),
|
||||||
LONG_HEIGHT,
|
LONG_HEIGHT,
|
||||||
|
longitudinalMinWidth,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -521,8 +528,11 @@ export function createSectionView(): SectionViewController {
|
|||||||
crossHeading.append(crossTitle, crossCount);
|
crossHeading.append(crossTitle, crossCount);
|
||||||
const grid = document.createElement("div");
|
const grid = document.createElement("div");
|
||||||
grid.className = "b06-section__grid";
|
grid.className = "b06-section__grid";
|
||||||
const columnCount = renderWidth >= 976 ? 2 : 1;
|
const columnCount = Math.max(
|
||||||
const cardWidth = (renderWidth - (columnCount - 1) * 16) / columnCount;
|
1,
|
||||||
|
Math.floor((renderWidth + CROSS_GRID_GAP) / (CROSS_GRID_MIN_WIDTH + CROSS_GRID_GAP)),
|
||||||
|
);
|
||||||
|
const cardWidth = (renderWidth - (columnCount - 1) * CROSS_GRID_GAP) / columnCount;
|
||||||
if (detail.cross_sections.length) {
|
if (detail.cross_sections.length) {
|
||||||
detail.cross_sections.forEach((section) =>
|
detail.cross_sections.forEach((section) =>
|
||||||
grid.append(
|
grid.append(
|
||||||
|
|||||||
@@ -182,6 +182,10 @@
|
|||||||
max-width: none;
|
max-width: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.b06-cross-card > .b06-section__chart {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.b06-section__heading {
|
.b06-section__heading {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: end;
|
align-items: end;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export function renderB10Payment(root: HTMLElement): void {
|
|||||||
const invoiceSection = section(L("B10_Payment_Invoice_Title"), invoiceBody, true, [
|
const invoiceSection = section(L("B10_Payment_Invoice_Title"), invoiceBody, true, [
|
||||||
createButton({ label: L("B10_Payment_Invoice_Request"), disabled: true }),
|
createButton({ label: L("B10_Payment_Invoice_Request"), disabled: true }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const depositNote = document.createElement("p");
|
const depositNote = document.createElement("p");
|
||||||
depositNote.className = "b10-payment__note";
|
depositNote.className = "b10-payment__note";
|
||||||
depositNote.textContent = L("B10_Payment_Deposit_Note");
|
depositNote.textContent = L("B10_Payment_Deposit_Note");
|
||||||
|
|||||||
@@ -1,20 +1,27 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Add project root to sys.path
|
# Add project root to sys.path
|
||||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||||
|
|
||||||
from B03_FileInput.B03_FileInput_Engine_Analyze import (
|
from B03_FileInput.B03_FileInput_Engine_Analyze import (
|
||||||
|
analyze_las_metadata,
|
||||||
analyze_prj_metadata,
|
analyze_prj_metadata,
|
||||||
analyze_tif_metadata,
|
analyze_tif_metadata,
|
||||||
analyze_las_metadata,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
BASE_DIR = Path("D:/02_Software_Prog/임도설계 및 견적자동화 프로그램 개발")
|
BASE_DIR = Path("D:/02_Software_Prog/임도설계 및 견적자동화 프로그램 개발")
|
||||||
PRJ_PATH = BASE_DIR / "storage/1/3/acb9170b-9ac8-49b3-82a0-51cfa32bb42d/B03_FileInput/input/prj/result.prj"
|
PRJ_PATH = (
|
||||||
TIF_PATH = BASE_DIR / "storage/1/3/acb9170b-9ac8-49b3-82a0-51cfa32bb42d/B03_FileInput/input/tif/result.tif"
|
BASE_DIR / "storage/1/3/acb9170b-9ac8-49b3-82a0-51cfa32bb42d/B03_FileInput/input/prj/result.prj"
|
||||||
LAS_PATH = BASE_DIR / "storage/1/3/acb9170b-9ac8-49b3-82a0-51cfa32bb42d/B03_FileInput/input/las/cloud_merged.las"
|
)
|
||||||
|
TIF_PATH = (
|
||||||
|
BASE_DIR / "storage/1/3/acb9170b-9ac8-49b3-82a0-51cfa32bb42d/B03_FileInput/input/tif/result.tif"
|
||||||
|
)
|
||||||
|
LAS_PATH = (
|
||||||
|
BASE_DIR
|
||||||
|
/ "storage/1/3/acb9170b-9ac8-49b3-82a0-51cfa32bb42d/B03_FileInput/input/las/cloud_merged.las"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def run_tests():
|
def run_tests():
|
||||||
print("--- 1. Testing PRJ Metadata Extraction ---")
|
print("--- 1. Testing PRJ Metadata Extraction ---")
|
||||||
@@ -23,12 +30,20 @@ def run_tests():
|
|||||||
print("PRJ Metadata:")
|
print("PRJ Metadata:")
|
||||||
for k, v in prj_meta.items():
|
for k, v in prj_meta.items():
|
||||||
print(f" {k}: {v}")
|
print(f" {k}: {v}")
|
||||||
|
|
||||||
# Assertions based on PLAN.md expectations
|
# Assertions based on PLAN.md expectations
|
||||||
assert prj_meta.get("epsg") == 5187, f"Expected horizontal EPSG to be 5187, got {prj_meta.get('epsg')}"
|
assert prj_meta.get("epsg") == 5187, (
|
||||||
assert prj_meta.get("crs_status") == "custom_vertical_crs", f"Expected custom_vertical_crs, got {prj_meta.get('crs_status')}"
|
f"Expected horizontal EPSG to be 5187, got {prj_meta.get('epsg')}"
|
||||||
assert prj_meta.get("vertical_crs") is not None, "Expected vertical_crs metadata to be present"
|
)
|
||||||
assert "KNGeoid24" in prj_meta["vertical_crs"]["name"], f"Expected KNGeoid24 in vertical crs name, got {prj_meta['vertical_crs']['name']}"
|
assert prj_meta.get("crs_status") == "custom_vertical_crs", (
|
||||||
|
f"Expected custom_vertical_crs, got {prj_meta.get('crs_status')}"
|
||||||
|
)
|
||||||
|
assert prj_meta.get("vertical_crs") is not None, (
|
||||||
|
"Expected vertical_crs metadata to be present"
|
||||||
|
)
|
||||||
|
assert "KNGeoid24" in prj_meta["vertical_crs"]["name"], (
|
||||||
|
f"Expected KNGeoid24 in vertical crs name, got {prj_meta['vertical_crs']['name']}"
|
||||||
|
)
|
||||||
print("PRJ test passed successfully.")
|
print("PRJ test passed successfully.")
|
||||||
else:
|
else:
|
||||||
print(f"PRJ file not found at {PRJ_PATH}")
|
print(f"PRJ file not found at {PRJ_PATH}")
|
||||||
@@ -39,9 +54,11 @@ def run_tests():
|
|||||||
print("TIF Metadata:")
|
print("TIF Metadata:")
|
||||||
for k, v in tif_meta.items():
|
for k, v in tif_meta.items():
|
||||||
print(f" {k}: {v}")
|
print(f" {k}: {v}")
|
||||||
|
|
||||||
assert tif_meta.get("epsg") == 5187, f"Expected EPSG to be 5187, got {tif_meta.get('epsg')}"
|
assert tif_meta.get("epsg") == 5187, f"Expected EPSG to be 5187, got {tif_meta.get('epsg')}"
|
||||||
assert tif_meta.get("crs_status") == "identified", f"Expected identified, got {tif_meta.get('crs_status')}"
|
assert tif_meta.get("crs_status") == "identified", (
|
||||||
|
f"Expected identified, got {tif_meta.get('crs_status')}"
|
||||||
|
)
|
||||||
assert tif_meta.get("vertical_crs") is None, "Expected no vertical crs for TIF file"
|
assert tif_meta.get("vertical_crs") is None, "Expected no vertical crs for TIF file"
|
||||||
print("TIF test passed successfully.")
|
print("TIF test passed successfully.")
|
||||||
else:
|
else:
|
||||||
@@ -57,14 +74,21 @@ def run_tests():
|
|||||||
print(f" {k}: id={v.get('id')}, num_dimensions={len(v.get('dimensions', []))}")
|
print(f" {k}: id={v.get('id')}, num_dimensions={len(v.get('dimensions', []))}")
|
||||||
else:
|
else:
|
||||||
print(f" {k}: {v}")
|
print(f" {k}: {v}")
|
||||||
|
|
||||||
assert las_meta.get("epsg") == 5187, f"Expected EPSG to be 5187, got {las_meta.get('epsg')}"
|
assert las_meta.get("epsg") == 5187, f"Expected EPSG to be 5187, got {las_meta.get('epsg')}"
|
||||||
assert las_meta.get("crs_status") == "custom_vertical_crs", f"Expected custom_vertical_crs, got {las_meta.get('crs_status')}"
|
assert las_meta.get("crs_status") == "custom_vertical_crs", (
|
||||||
assert las_meta.get("vertical_crs") is not None, "Expected vertical_crs metadata to be present"
|
f"Expected custom_vertical_crs, got {las_meta.get('crs_status')}"
|
||||||
assert "KNGeoid24" in las_meta["vertical_crs"]["name"], f"Expected KNGeoid24 in vertical crs name, got {las_meta['vertical_crs']['name']}"
|
)
|
||||||
|
assert las_meta.get("vertical_crs") is not None, (
|
||||||
|
"Expected vertical_crs metadata to be present"
|
||||||
|
)
|
||||||
|
assert "KNGeoid24" in las_meta["vertical_crs"]["name"], (
|
||||||
|
f"Expected KNGeoid24 in vertical crs name, got {las_meta['vertical_crs']['name']}"
|
||||||
|
)
|
||||||
print("LAS test passed successfully.")
|
print("LAS test passed successfully.")
|
||||||
else:
|
else:
|
||||||
print(f"LAS file not found at {LAS_PATH}")
|
print(f"LAS file not found at {LAS_PATH}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run_tests()
|
run_tests()
|
||||||
|
|||||||
+27
-16
@@ -35,51 +35,57 @@ for rel_path, abs_path in list(all_wiki_files.items()):
|
|||||||
continue
|
continue
|
||||||
if rel_path in ["index", "log", "index.md", "log.md"]:
|
if rel_path in ["index", "log", "index.md", "log.md"]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
with open(abs_path, "r", encoding="utf-8") as f:
|
with open(abs_path, "r", encoding="utf-8") as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
|
|
||||||
line_count = len(lines)
|
line_count = len(lines)
|
||||||
content = "".join(lines)
|
content = "".join(lines)
|
||||||
|
|
||||||
# Rule 14: Max 100 lines
|
# Rule 14: Max 100 lines
|
||||||
if line_count > 100:
|
if line_count > 100:
|
||||||
warnings.append(f"[Line Count] `{rel_path}.md` exceeds 100 lines ({line_count} lines).")
|
warnings.append(f"[Line Count] `{rel_path}.md` exceeds 100 lines ({line_count} lines).")
|
||||||
|
|
||||||
# Check YAML Frontmatter via simple regex
|
# Check YAML Frontmatter via simple regex
|
||||||
frontmatter_match = re.match(r"^---\s*\n(.*?)\n---\s*\n", content, re.DOTALL)
|
frontmatter_match = re.match(r"^---\s*\n(.*?)\n---\s*\n", content, re.DOTALL)
|
||||||
if not frontmatter_match:
|
if not frontmatter_match:
|
||||||
errors.append(f"[Frontmatter] `{rel_path}.md` has no valid YAML frontmatter.")
|
errors.append(f"[Frontmatter] `{rel_path}.md` has no valid YAML frontmatter.")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
fm_text = frontmatter_match.group(1)
|
fm_text = frontmatter_match.group(1)
|
||||||
|
|
||||||
# Simple regex parsing for status & page_id
|
# Simple regex parsing for status & page_id
|
||||||
status_match = re.search(r"^status:\s*(\w+)", fm_text, re.MULTILINE)
|
status_match = re.search(r"^status:\s*(\w+)", fm_text, re.MULTILINE)
|
||||||
page_id_match = re.search(r"^page_id:\s*([^\n\r]+)", fm_text, re.MULTILINE)
|
page_id_match = re.search(r"^page_id:\s*([^\n\r]+)", fm_text, re.MULTILINE)
|
||||||
|
|
||||||
if not status_match:
|
if not status_match:
|
||||||
errors.append(f"[Status] `{rel_path}.md` has no status field in frontmatter.")
|
errors.append(f"[Status] `{rel_path}.md` has no status field in frontmatter.")
|
||||||
else:
|
else:
|
||||||
status = status_match.group(1).strip()
|
status = status_match.group(1).strip()
|
||||||
if status not in ["draft", "stable", "stale"]:
|
if status not in ["draft", "stable", "stale"]:
|
||||||
errors.append(f"[Status] `{rel_path}.md` has invalid status '{status}'. Must be draft, stable, or stale.")
|
errors.append(
|
||||||
|
f"[Status] `{rel_path}.md` has invalid status '{status}'. Must be draft, stable, or stale."
|
||||||
|
)
|
||||||
elif status == "stale":
|
elif status == "stale":
|
||||||
warnings.append(f"[Stale Page] `{rel_path}.md` is marked as stale and needs updates from raw inputs.")
|
warnings.append(
|
||||||
|
f"[Stale Page] `{rel_path}.md` is marked as stale and needs updates from raw inputs."
|
||||||
|
)
|
||||||
|
|
||||||
# Rule 5: page_id required for pages/
|
# Rule 5: page_id required for pages/
|
||||||
if "pages/" in rel_path:
|
if "pages/" in rel_path:
|
||||||
if not page_id_match:
|
if not page_id_match:
|
||||||
errors.append(f"[page_id] `{rel_path}.md` is in pages/ but lacks a 'page_id' field.")
|
errors.append(f"[page_id] `{rel_path}.md` is in pages/ but lacks a 'page_id' field.")
|
||||||
|
|
||||||
# Check for broken wikilinks in content
|
# Check for broken wikilinks in content
|
||||||
links = wikilink_pat.findall(content)
|
links = wikilink_pat.findall(content)
|
||||||
for link in links:
|
for link in links:
|
||||||
link_clean = link.strip().replace("\\", "/").split("#")[0] # ignore anchor for file existence check
|
link_clean = (
|
||||||
|
link.strip().replace("\\", "/").split("#")[0]
|
||||||
|
) # ignore anchor for file existence check
|
||||||
if not link_clean:
|
if not link_clean:
|
||||||
continue
|
continue
|
||||||
found = False
|
found = False
|
||||||
|
|
||||||
# 1. Absolute link from vault root (e.g. concepts/storage_paths)
|
# 1. Absolute link from vault root (e.g. concepts/storage_paths)
|
||||||
if link_clean in all_wiki_files:
|
if link_clean in all_wiki_files:
|
||||||
found = True
|
found = True
|
||||||
@@ -98,7 +104,7 @@ for rel_path, abs_path in list(all_wiki_files.items()):
|
|||||||
resolved = os.path.normpath(os.path.join(curr_dir, link_clean)).replace("\\", "/")
|
resolved = os.path.normpath(os.path.join(curr_dir, link_clean)).replace("\\", "/")
|
||||||
if resolved in all_wiki_files or resolved.replace("pages/", "") in all_wiki_files:
|
if resolved in all_wiki_files or resolved.replace("pages/", "") in all_wiki_files:
|
||||||
found = True
|
found = True
|
||||||
|
|
||||||
if not found:
|
if not found:
|
||||||
errors.append(f"[Broken Link] `{rel_path}.md` contains broken wikilink: [[{link}]]")
|
errors.append(f"[Broken Link] `{rel_path}.md` contains broken wikilink: [[{link}]]")
|
||||||
|
|
||||||
@@ -108,8 +114,13 @@ for rel_path, abs_path in list(all_wiki_files.items()):
|
|||||||
if file_name_no_ext not in index_content:
|
if file_name_no_ext not in index_content:
|
||||||
# check if relative path is in index
|
# check if relative path is in index
|
||||||
rel_path_no_ext = rel_path.replace(".md", "")
|
rel_path_no_ext = rel_path.replace(".md", "")
|
||||||
if rel_path_no_ext not in index_content and rel_path_no_ext.split("/")[-1] not in index_content:
|
if (
|
||||||
warnings.append(f"[Orphan Page] `{rel_path}.md` is not linked or mentioned in index.md.")
|
rel_path_no_ext not in index_content
|
||||||
|
and rel_path_no_ext.split("/")[-1] not in index_content
|
||||||
|
):
|
||||||
|
warnings.append(
|
||||||
|
f"[Orphan Page] `{rel_path}.md` is not linked or mentioned in index.md."
|
||||||
|
)
|
||||||
|
|
||||||
print("=== LINT ERRORS ===")
|
print("=== LINT ERRORS ===")
|
||||||
for e in sorted(list(set(errors))):
|
for e in sorted(list(set(errors))):
|
||||||
|
|||||||
Reference in New Issue
Block a user