@@ -53,21 +53,17 @@ const SAFETY_DOCS_EXCLUDE: &[&str] = &["generated", "language"];
5353/// [`Config::qualification_plan_dir`], the section it belongs to.
5454const MATRIX_FILE : & str = "traceability-matrix.mdx" ;
5555
56- /// Where the safety manual declares the path it is served under. The matrix
57- /// links from that base rather than relatively, because
58- /// starlight-links-validator skips relative links: a relative one here would
59- /// go unchecked, and could rot into a dead anchor unnoticed.
60- const SAFETY_SITE_CONFIG : & str = "docs/safety/src/safety-site-config.mjs" ;
61-
6256const REPO_URL : & str = env ! ( "CARGO_PKG_REPOSITORY" ) ;
6357
6458struct SpecPage {
6559 /// Repository-relative path with `/` separators, for error messages.
6660 file : String ,
6761 /// From the frontmatter.
6862 title : String ,
69- /// URL of the page from the site base, for linking its anchors from the
70- /// matrix. See [`SAFETY_SITE_CONFIG`] for why it isn't relative.
63+ /// URL of the page from the site root, for linking its anchors from the
64+ /// matrix. Not relative, because starlight-links-validator skips relative
65+ /// links: one here would go unchecked and could rot into a dead anchor.
66+ /// remark-base-links.mjs adds the site base at build time.
7167 base : String ,
7268 /// The specification index heads its section; every other page nests
7369 /// under one.
@@ -104,11 +100,10 @@ impl TestRef {
104100
105101pub fn generate ( cfg : & Config ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
106102 let root = crate :: root_dir ( ) ;
107- let base = safety_base ( & root) ?;
108- let mut spec_pages = scan_spec_pages ( & root. join ( SPEC_DIR ) , & base) ?;
109- spec_pages. extend ( scan_property_type_pages ( & root, & base) ?) ;
110- let reference_pages = scan_reference_pages ( cfg, & root, & base) ?;
111- let safety_pages = scan_safety_pages ( & root, & base) ?;
103+ let mut spec_pages = scan_spec_pages ( & root. join ( SPEC_DIR ) ) ?;
104+ spec_pages. extend ( scan_property_type_pages ( & root) ?) ;
105+ let reference_pages = scan_reference_pages ( cfg, & root) ?;
106+ let safety_pages = scan_safety_pages ( & root) ?;
112107
113108 let mut refs = Vec :: new ( ) ;
114109 for kind in TEST_ROOTS {
@@ -132,7 +127,7 @@ pub fn generate(cfg: &Config) -> Result<(), Box<dyn std::error::Error>> {
132127 }
133128 }
134129
135- write_matrix ( cfg, & root, & base , & spec_pages, & reference_pages, & safety_pages, & tests_by_id)
130+ write_matrix ( cfg, & root, & spec_pages, & reference_pages, & safety_pages, & tests_by_id)
136131}
137132
138133/// Validate the parsed pages and test references, returning one message per
@@ -266,19 +261,6 @@ fn parse_spec_page(file: &str, text: &str) -> (SpecPage, Option<String>) {
266261 ( page, slug)
267262}
268263
269- /// The path the safety manual is served under, with leading and trailing `/`.
270- fn safety_base ( repo_root : & Path ) -> Result < String , Box < dyn std:: error:: Error > > {
271- let path = repo_root. join ( SAFETY_SITE_CONFIG ) ;
272- let text = std:: fs:: read_to_string ( & path) . context ( format ! ( "error reading {path:?}" ) ) ?;
273- let value = text
274- . lines ( )
275- . find_map ( |line| line. trim ( ) . strip_prefix ( "export const SAFETY_DOCS_BASE_PATH =" ) )
276- . map ( |value| value. trim ( ) . trim_end_matches ( ';' ) . trim ( ) . trim_matches ( '"' ) )
277- . ok_or_else ( || anyhow:: anyhow!( "{SAFETY_SITE_CONFIG}: no SAFETY_DOCS_BASE_PATH" ) ) ?;
278- let trimmed = value. trim_matches ( '/' ) ;
279- Ok ( if trimmed. is_empty ( ) { "/" . to_string ( ) } else { format ! ( "/{trimmed}/" ) } )
280- }
281-
282264/// Repository-relative path with `/` separators.
283265fn repo_relative ( path : & Path , repo_root : & Path ) -> String {
284266 let relative = path. strip_prefix ( repo_root) . unwrap_or ( path) . to_string_lossy ( ) . into_owned ( ) ;
@@ -289,7 +271,7 @@ fn repo_relative(path: &Path, repo_root: &Path) -> String {
289271 }
290272}
291273
292- fn scan_spec_pages ( dir : & Path , base : & str ) -> Result < Vec < SpecPage > , Box < dyn std:: error:: Error > > {
274+ fn scan_spec_pages ( dir : & Path ) -> Result < Vec < SpecPage > , Box < dyn std:: error:: Error > > {
293275 let mut paths: Vec < std:: path:: PathBuf > = std:: fs:: read_dir ( dir)
294276 . context ( format ! ( "error reading {dir:?}" ) ) ?
295277 . filter_map ( |e| Some ( e. ok ( ) ?. path ( ) ) )
@@ -311,11 +293,8 @@ fn scan_spec_pages(dir: &Path, base: &str) -> Result<Vec<SpecPage>, Box<dyn std:
311293 }
312294 // The index page is served at the root of the specification.
313295 page. top_level = stem == "index" ;
314- page. base = if page. top_level {
315- format ! ( "{base}language/" )
316- } else {
317- format ! ( "{base}language/{stem}/" )
318- } ;
296+ page. base =
297+ if page. top_level { format ! ( "/language/" ) } else { format ! ( "/language/{stem}/" ) } ;
319298 if !page. draft {
320299 pages. push ( page) ;
321300 }
@@ -327,10 +306,7 @@ fn scan_spec_pages(dir: &Path, base: &str) -> Result<Vec<SpecPage>, Box<dyn std:
327306/// their anchors. Pages marked `notInSC: true` cover the full language only, so
328307/// they carry no requirements; the rest are served in the safety manual under
329308/// `reference/property-types/`.
330- fn scan_property_type_pages (
331- root : & Path ,
332- base : & str ,
333- ) -> Result < Vec < SpecPage > , Box < dyn std:: error:: Error > > {
309+ fn scan_property_type_pages ( root : & Path ) -> Result < Vec < SpecPage > , Box < dyn std:: error:: Error > > {
334310 let dir = root. join ( PROPERTY_TYPES_DIR ) ;
335311 let mut paths: Vec < std:: path:: PathBuf > = std:: fs:: read_dir ( & dir)
336312 . context ( format ! ( "error reading {dir:?}" ) ) ?
@@ -348,7 +324,7 @@ fn scan_property_type_pages(
348324 if page. not_in_sc || page. anchors . is_empty ( ) || page. draft {
349325 continue ;
350326 }
351- page. base = format ! ( "{base} reference/property-types/{stem}/" ) ;
327+ page. base = format ! ( "/ reference/property-types/{stem}/" ) ;
352328 pages. push ( page) ;
353329 }
354330 Ok ( pages)
@@ -359,7 +335,6 @@ fn scan_property_type_pages(
359335fn scan_reference_pages (
360336 cfg : & Config ,
361337 repo_root : & Path ,
362- base : & str ,
363338) -> Result < Vec < SpecPage > , Box < dyn std:: error:: Error > > {
364339 let mut pages = Vec :: new ( ) ;
365340 for entry in walkdir:: WalkDir :: new ( cfg. reference_dir ( ) ) . sort_by_file_name ( ) {
@@ -379,7 +354,7 @@ fn scan_reference_pages(
379354 // couldn't link to the anchors it just found.
380355 let slug = slug
381356 . ok_or_else ( || anyhow:: anyhow!( "{file}: generated page carries anchors but no slug" ) ) ?;
382- page. base = format ! ( "{base} {slug}/" ) ;
357+ page. base = format ! ( "/ {slug}/" ) ;
383358 pages. push ( page) ;
384359 }
385360 Ok ( pages)
@@ -394,10 +369,7 @@ fn safety_page_slug(relative: &str) -> &str {
394369}
395370
396371/// Parse the handwritten safety-manual pages for their anchors.
397- fn scan_safety_pages (
398- repo_root : & Path ,
399- base : & str ,
400- ) -> Result < Vec < SpecPage > , Box < dyn std:: error:: Error > > {
372+ fn scan_safety_pages ( repo_root : & Path ) -> Result < Vec < SpecPage > , Box < dyn std:: error:: Error > > {
401373 let dir = repo_root. join ( SAFETY_DOCS_DIR ) ;
402374 let mut pages = Vec :: new ( ) ;
403375 for entry in walkdir:: WalkDir :: new ( & dir)
@@ -428,7 +400,7 @@ fn scan_safety_pages(
428400 }
429401 let relative = repo_relative ( path, & dir) ;
430402 let slug = slug. unwrap_or_else ( || safety_page_slug ( & relative) . to_string ( ) ) ;
431- page. base = format ! ( "{base} {slug}/" ) ;
403+ page. base = format ! ( "/ {slug}/" ) ;
432404 pages. push ( page) ;
433405 }
434406 Ok ( pages)
@@ -484,7 +456,6 @@ fn git_head(repo_root: &Path) -> String {
484456fn write_matrix (
485457 cfg : & Config ,
486458 repo_root : & Path ,
487- base : & str ,
488459 spec_pages : & [ SpecPage ] ,
489460 reference_pages : & [ SpecPage ] ,
490461 safety_pages : & [ SpecPage ] ,
@@ -512,7 +483,7 @@ description: Mapping between the requirement paragraphs of the Language Specific
512483slug: qualification-plan/traceability-matrix
513484---
514485
515- Each requirement paragraph in the [Language Specification]({base} language/), the [SC API Reference]({base} reference/), and the other chapters of this manual carries a unique identifier,
486+ Each requirement paragraph in the [Language Specification](/ language/), the [SC API Reference](/ reference/), and the other chapters of this manual carries a unique identifier,
516487shown as a `[sls.…]` badge at the end of the paragraph.
517488A test case declares which requirements it verifies by listing their identifiers in `//#sls.…` comments.
518489This matrix lists every requirement paragraph with the test cases that declare it.
0 commit comments