Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion SCARP-DOCS-ENGINE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ The engine's test build is generated under artifacts/scarp-engine-preview/scarp-

1. **142 pages**: preserve at least 71 English and 71 Hindi source routes; new paired release pages may increase the count, local links, home features, heading anchors, code samples, callouts and both embedded interactive widgets.
2. **Search and releases**: use a full local index with no external provider; verify correct pinned compiler versions and do not invent unshipped commands.
3. **Accessible UI**: test keyboard, focus return, language switching, appearance persistence, 320px reflow, mobile navigation and code/table scrolling. Run axe WCAG A/AA on representative states. Automated tests are not manual screen-reader certification; see Issue #65.
3. **Accessible UI**: test keyboard search-result cycling, release selection, clipboard success/permission denial, focus return, language switching, appearance persistence, 320px reflow, reduced motion, mobile navigation and code/table scrolling. Run axe WCAG A/AA on representative states. Automated tests are not manual screen-reader certification; see Issue #65.
4. **Deploy and offline**: change production build, archive generation, Pages upload, sitemap/live smoke and downloaded offline browser checks together. Confirm complete URL continuity.
5. **Remove VitePress**: only after actual production and offline verification, migrate pure release data out of the old theme, remove its Vue/VitePress files and dependencies, and update older conformance and toolchain tests without weakening them.
6. **Release policy**: no stable documentation version is created by this migration. Keep the existing prerelease release gates.
Expand Down
10 changes: 8 additions & 2 deletions docs/guide/search-and-navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@ The keyboard shortcut shown in the search trigger is part of its accessible name

## Find the right version

A search result may come from a **historical** tutorial. Start with the [seven-stage learning path](/guide/learning-path), [current installation](/guide/installation-alpha6) or [published feature status](/reference/status) to determine the correct compiler version before running an example. The core language reference remains pinned to alpha.1, while newer guides identify their own prereleases.
A search result may come from a **historical** tutorial. Start with the [seven-stage learning path](/guide/learning-path), [latest published compiler downloads](/releases/v0.0.6-alpha.3) or [published feature status](/reference/status) to determine the correct compiler version before running an example. The core language reference remains pinned to alpha.1, while newer guides identify their own prereleases.

For exact commands, compare the [alpha.6 CLI](/tooling/cli-alpha6), [AST inspection](/tooling/inspect-ast-alpha6) and [troubleshooting](/tooling/troubleshooting). Use the [Hindi search help](/hi/guide/search-and-navigation) to read these instructions in हिन्दी.

## When search shows no results

Check the spelling of Scarp keywords, use a shorter term, or switch locale using the language menu. Search is provided by Scarp Docs' generated static full-text index and needs JavaScript enabled to display results. The offline Chromium suite also checks the no-results message and that **Esc** returns focus to the search trigger when opened from that button. A failed local index load is not evidence that a compiler feature does not exist: use the [page navigation](/guide/learning-path) or the [compiler's published release notes](/releases/v0.0.6-alpha.1) instead.
Check the spelling of Scarp keywords, use a shorter term, or switch locale using the language menu. Search is provided by Scarp Docs' generated static full-text index and needs JavaScript enabled to display results. The offline Chromium suite also checks the no-results message and that **Esc** returns focus to the search trigger when opened from that button. A failed local index load is not evidence that a compiler feature does not exist: use the [page navigation](/guide/learning-path) or the [compiler's published release notes](/releases/v0.0.6-alpha.3) instead.

## Keyboard and clipboard accessibility

After results load, press **↓** to focus the first search link or **↑** to focus the last. Use Up/Down to move between links, **Enter** to open one, and **Esc** to close the dialog. Normal **Tab** navigation remains available. Closing a search opened from its trigger restores focus to that trigger.

Use the [version-aware Command Finder](/tooling/command-finder) with the keyboard to select the installed compiler. Older versions explicitly indicate unavailable commands. If **Copy commands** fails or the browser denies clipboard permission, the command block remains keyboard-focusable and can be selected manually. The real Chromium suite tests keyboard navigation, permission denial, 320px layouts and reduced motion. **Automated testing does not replace a manual screen-reader review or constitute WCAG certification.**
10 changes: 8 additions & 2 deletions docs/hi/guide/search-and-navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@ Search button के साथ दिखाई देने वाला **K** s

## सही compiler version चुनें

Search परिणाम में कोई **पुराना** tutorial भी हो सकता है। Code चलाने से पहले [सात-चरण वाला learning path](/hi/guide/learning-path), [नवीनतम installation](/hi/guide/installation-alpha6) और [प्रकाशित feature status](/hi/reference/status) देखें। मुख्य language reference alpha.1 पर आधारित है; नई सुविधाएँ अपने अलग प्रकाशित compiler releases से सत्यापित हैं।
Search परिणाम में कोई **पुराना** tutorial भी हो सकता है। Code चलाने से पहले [सात-चरण वाला learning path](/hi/guide/learning-path), [नवीनतम प्रकाशित compiler डाउनलोड](/hi/releases/v0.0.6-alpha.3) और [प्रकाशित feature status](/hi/reference/status) देखें। मुख्य language reference alpha.1 पर आधारित है; नई सुविधाएँ अपने अलग प्रकाशित compiler releases से सत्यापित हैं।

सही CLI command पहचानने के लिए [alpha.6 CLI](/hi/tooling/cli-alpha6), [AST inspection](/hi/tooling/inspect-ast-alpha6) तथा [troubleshooting](/hi/tooling/troubleshooting) पढ़ें। [English search help](/guide/search-and-navigation) भी उपलब्ध है।

## कोई परिणाम न मिले तो

Keyword की spelling जाँचें, छोटा शब्द खोजें या भाषा बदलें। Local search को परिणाम दिखाने के लिए browser में JavaScript चाहिए, क्योंकि index static website से लोड होता है। Offline Chromium परीक्षण में कोई परिणाम न मिलने वाला संदेश और search button से खोलने के बाद **Esc** दबाने पर keyboard focus वापस आने की भी जाँच होती है। Search विफल होने से यह सिद्ध **नहीं** होता कि compiler में कोई सुविधा नहीं है। ऐसे में [learning path](/hi/guide/learning-path) या [प्रकाशित compiler release](/hi/releases/v0.0.6-alpha.1) से सीधे आगे बढ़ें।
Keyword की spelling जाँचें, छोटा शब्द खोजें या भाषा बदलें। Local search को परिणाम दिखाने के लिए browser में JavaScript चाहिए, क्योंकि index static website से लोड होता है। Offline Chromium परीक्षण में कोई परिणाम न मिलने वाला संदेश और search button से खोलने के बाद **Esc** दबाने पर keyboard focus वापस आने की भी जाँच होती है। Search विफल होने से यह सिद्ध **नहीं** होता कि compiler में कोई सुविधा नहीं है। ऐसे में [learning path](/hi/guide/learning-path) या [प्रकाशित compiler release](/hi/releases/v0.0.6-alpha.3) से सीधे आगे बढ़ें।

## Keyboard और clipboard accessibility

Search में परिणाम आने के बाद **↓** से पहला link, **↑** से आखिरी link चुन सकते हैं। परिणामों में ↑/↓ से आगे-पीछे जाएँ; **Enter** से link खोलें। **Tab** से भी सामान्य क्रम में चल सकते हैं और **Esc** से search बंद कर सकते हैं। Search button से खोलने पर बंद करने के बाद focus उसी button पर लौटता है।

[Version-aware Command Finder](/hi/tooling/command-finder) में keyboard से compiler version चुन सकते हैं। पुराने version में अनुपलब्ध commands का स्पष्ट हिन्दी संदेश मिलता है। **कॉपी करें** काम न करे या browser permission मना कर दे, तो command text चयन के लिए उपलब्ध रहता है। स्वचालित Chromium परीक्षण keyboard, अनुमति-अस्वीकृति, 320px layout और reduced-motion की जाँच करते हैं; इन्हें **manual screen-reader या पूर्ण WCAG certification** न समझें।
4 changes: 3 additions & 1 deletion scripts/lib/hindi-search-policy.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { LATEST_RELEASE } from './command-finder.ts'

/** Guard user-facing language consistency without importing the VitePress app. */
interface SearchTranslationBlock {
[key: string]: string | Record<string, string> | undefined
Expand Down Expand Up @@ -89,7 +91,7 @@ export function validateHindiLocalSearch(
for (const marker of [
'Ctrl+K','⌘+K','Enter','Esc',
']('+localePrefix+'/guide/learning-path)',
']('+localePrefix+'/guide/installation-alpha6)',
']('+localePrefix+'/releases/'+LATEST_RELEASE+')',
']('+localePrefix+'/reference/status)',
']('+localePrefix+'/tooling/cli-alpha6)'
]) {
Expand Down
61 changes: 55 additions & 6 deletions scripts/scarp-site/browser-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,45 @@ async function testLocale(
assert.match(await widget.locator('pre').innerText(),
/scarp inspect symbols --json FILE\.srp/)
assert.equal(await widget.locator('pre').getAttribute('tabindex'),'0')
await widget.locator('#scarp-release').selectOption('v0.0.5-alpha.1')
assert.equal(await widget.locator('pre').count(),0)
// Use the real keyboard to change release choices, not only selectOption.
const releaseChoice=widget.locator('#scarp-release')
await releaseChoice.focus()
await releaseChoice.press('Home')
assert.equal(await releaseChoice.inputValue(),'v0.0.5-alpha.1')
await widget.locator('pre').waitFor({state:'detached'})
assert.match(await widget.locator('.finder-result').innerText(),/v0\.0\.6-alpha\.1/)
await widget.locator('#scarp-release').selectOption(LATEST_RELEASE)
await releaseChoice.press('End')
assert.equal(await releaseChoice.inputValue(),LATEST_RELEASE)
await widget.locator('pre').waitFor({state:'visible'})
assert.equal(await widget.locator('.finder-result').getAttribute('aria-live'),'polite')
assertions++

// Deterministic in-page clipboard stubs: no OS permissions or external APIs.
// Literal browser-side JS avoids injecting tsx/esbuild __name helpers
// that do not exist inside Playwright's isolated page runtime.
await page.evaluate(`Object.defineProperty(navigator,'clipboard',{
configurable:true,
value:{writeText(value){window.__scarpCopied=value;return Promise.resolve()}}
})`)
const copy=widget.locator('.finder-result button')
await copy.focus()
await page.keyboard.press('Enter')
await page.waitForFunction("window.__scarpCopied?.includes('scarp inspect symbols')")
assert.match(await page.evaluate("window.__scarpCopied || ''"),
/scarp inspect symbols --json FILE\.srp/)
await page.getByRole('button',{name:lang==='hi'?'कॉपी हो गया':'Copied'}).waitFor()
await page.evaluate(`Object.defineProperty(navigator,'clipboard',{
configurable:true,
value:{writeText(){return Promise.reject(new DOMException('Denied','NotAllowedError'))}}
})`)
await copy.click()
await page.getByRole('button',{
name:lang==='hi'
?'कॉपी नहीं हो पाया। Command text चुनकर स्वयं कॉपी करें।'
:'Copy failed. Select the command text manually.'
}).waitFor()
assert.equal(await widget.locator('pre').getAttribute('tabindex'),'0',
lang+': command text must remain selectable after clipboard denial')
assertions++

const theme=page.locator('#theme-toggle')
Expand All @@ -117,8 +151,18 @@ async function testLocale(
const searchInput=page.locator('#search-query')
assert.equal(await searchInput.evaluate(node=>document.activeElement===node),true)
await searchInput.fill('funcra')
await page.locator('#search-results li a').first().waitFor({state:'visible',timeout:15000})
assert.ok((await page.locator('#search-results li a').first().getAttribute('href'))?.startsWith(prefix))
const results=page.locator('#search-results li a')
await results.first().waitFor({state:'visible',timeout:15000})
assert.ok((await results.first().getAttribute('href'))?.startsWith(prefix))
await searchInput.press('ArrowDown')
assert.equal(await results.first().evaluate(node=>document.activeElement===node),true,
lang+': ArrowDown must focus the first search result')
await page.keyboard.press('ArrowUp')
assert.equal(await results.last().evaluate(node=>document.activeElement===node),true,
lang+': ArrowUp must cycle through search results')
await page.keyboard.press('ArrowDown')
assert.equal(await results.first().evaluate(node=>document.activeElement===node),true)
await searchInput.focus()
await searchInput.fill('zzqvkpwmntrxhfbjkldsrp9776')
await page.getByRole('status').getByText(
lang==='hi'?'कोई परिणाम नहीं मिला':'No results found',{exact:true}).waitFor()
Expand Down Expand Up @@ -158,6 +202,11 @@ async function mobile(
await page.locator('#search-query').waitFor({state:'visible'})
await page.keyboard.press('Escape')
assert.deepEqual(outside,[])
await page.setViewportSize({width:320,height:800})
await page.emulateMedia({reducedMotion:'reduce'})
assert.equal(await page.evaluate(()=>matchMedia('(prefers-reduced-motion: reduce)').matches),true)
const narrowOverflow=await page.evaluate(()=>document.documentElement.scrollWidth-window.innerWidth)
assert.ok(narrowOverflow<=2,lang+': 320px layout overflow '+narrowOverflow)
const audit=await auditOfflineAccessibility(page,lang+'-engine-mobile',
join(previewRoot,'audit-results'))
assert.ok(audit.passes>0)
Expand All @@ -175,7 +224,7 @@ try{
await mobile(browser,origin,locale)
}
console.log('PASS: '+assertions+
' Scarp-owned engine Chromium tests: translated routes, local search, theme, CLI, 375px navigation and axe WCAG A/AA scans')
' Scarp-owned engine Chromium tests: keyboard search, clipboard success/denial, release selector, bilingual UI, 320px reflow, reduced motion and axe A/AA scans')
}catch(error){
console.error('FAIL: Scarp-owned engine Chromium: '+String(error))
process.exitCode=1
Expand Down
15 changes: 15 additions & 0 deletions scripts/scarp-site/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,21 @@ function installSearch():void {
else open.focus({preventScroll:true})
})
input.addEventListener('input',()=>{void refresh()})
// Arrow navigation keeps search results reachable without a mouse. Ordinary
// Tab/Shift+Tab remain available, and Enter uses the native link behavior.
dialog.addEventListener('keydown', event=>{
if(event.key!=='ArrowDown'&&event.key!=='ArrowUp')return
const target=event.target
if(target!==input&&!(target instanceof Node&&output.contains(target)))return
const links=[...output.querySelectorAll<HTMLAnchorElement>('a[href]')]
if(!links.length)return
const index=links.findIndex(link=>link===target)
const direction=event.key==='ArrowDown'?1:-1
const next=index<0?(direction===1?0:links.length-1):
(index+direction+links.length)%links.length
event.preventDefault()
links[next]?.focus()
})
document.addEventListener('keydown',event=>{
// Search inputs may consume Escape to clear their own value. The explicit
// handler guarantees the dialog always closes and restores trigger focus.
Expand Down
9 changes: 8 additions & 1 deletion scripts/test-hindi-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { localSearchOptions } from '../docs/.vitepress/local-search.ts'
import { LATEST_RELEASE } from './lib/command-finder.ts'
import {
validateHindiLocalSearch,
type SearchLocalizationOptions,
Expand Down Expand Up @@ -64,6 +65,12 @@ mutatePage('no local provider','config',"provider: 'local'","provider: 'algolia'
mutatePage('no search options','config',"options: localSearchOptions","options: {}")
mutatePage('missing Hindi sidebar','config',"link: '/hi/guide/search-and-navigation'","link: '/hi/guide/missing'")
mutatePage('missing theme access label','config',"langMenuLabel: 'भाषा बदलें'","langMenuLabel: 'Language'")
// Both the download link and release-notes fallback mention the latest tag.
const withoutLatest=pages.english.replaceAll('](/releases/'+LATEST_RELEASE+')',
'](/releases/v0.0.5-alpha.1)')
assert.notEqual(withoutLatest,pages.english,'latest release link must exist')
assert.ok(validateHindiLocalSearch(localSearchOptions,{...pages,english:withoutLatest}).length>0,
'removing all current release links must fail the localized-search policy')
mutatePage('missing Hindi shortcut','hindi','Ctrl+K','Alt+K')
mutatePage('missing English shortcut','english','⌘+K','Ctrl+J')
mutatePage('missing Hindi crosslink','hindi','](/guide/search-and-navigation)','](/hi/guide/search-and-navigation)')
Expand All @@ -72,4 +79,4 @@ mutatePage('missing Hindi intro link','hindiIntro','](/hi/guide/search-and-navig
mutatePage('missing README Hindi path','readme','docs/hi/guide/search-and-navigation.md','docs/hi/guide/not-found.md')
assert.ok(validateHindiLocalSearch(localSearchOptions,{...pages,hindi:pages.hindi.replace(/[\u0900-\u097f]/gu,'')}).length,
'Hindi locale cannot silently become untranslated')
console.log('PASS: 17 negative regressions for Hindi search UI, locale navigation, language parity and keyboard access')
console.log('PASS: 18 negative regressions for Hindi search UI, locale navigation, current release, language parity and keyboard access')
Loading