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
51 changes: 37 additions & 14 deletions playwright/app.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,28 @@ const ensurePanelToolsVisible = async (page: Page, panelName: 'component' | 'sty
}
}

const ensureDiagnosticsDrawerOpen = async (page: Page) => {
const toggle = page.locator('#diagnostics-toggle')
const isExpanded = await toggle.getAttribute('aria-expanded')

if (isExpanded !== 'true') {
await toggle.click()
}

await expect(page.locator('#diagnostics-drawer')).toBeVisible()
}

const ensureDiagnosticsDrawerClosed = async (page: Page) => {
const toggle = page.locator('#diagnostics-toggle')
const isExpanded = await toggle.getAttribute('aria-expanded')

if (isExpanded === 'true') {
await page.locator('#diagnostics-close').click()
}

await expect(page.locator('#diagnostics-drawer')).toBeHidden()
}

const expectCollapseButtonState = async (
page: Page,
panelName: 'component' | 'styles' | 'preview',
Expand Down Expand Up @@ -383,7 +405,7 @@ test('react mode typecheck loads types without malformed URL fetches', async ({
await page.locator('#render-mode').selectOption('react')
await page.getByRole('button', { name: 'Typecheck' }).click()

await page.locator('#diagnostics-toggle').click()
await ensureDiagnosticsDrawerOpen(page)
await expect(page.locator('#diagnostics-component')).toContainText(
'No TypeScript errors found.',
)
Expand Down Expand Up @@ -558,7 +580,7 @@ test('style compilation errors populate styles diagnostics scope', async ({ page
/diagnostics-toggle--error/,
)

await page.locator('#diagnostics-toggle').click()
await ensureDiagnosticsDrawerOpen(page)
await expect(page.locator('#diagnostics-styles')).toContainText(
'Style compilation failed.',
)
Expand Down Expand Up @@ -627,6 +649,7 @@ test('clearing styles keeps diagnostics error state but resets status styling',
)

const dialog = page.locator('#clear-confirm-dialog')
await ensureDiagnosticsDrawerClosed(page)
await page.getByLabel('Clear styles source').click()
await expect(dialog).toHaveAttribute('open', '')
await dialog.getByRole('button', { name: 'Clear' }).click()
Expand Down Expand Up @@ -659,7 +682,7 @@ test('clear component diagnostics removes type errors and restores rendered stat
)
await expect(page.locator('#status')).toHaveText(/Rendered \(Type errors: [1-9]\d*\)/)

await page.locator('#diagnostics-toggle').click()
await ensureDiagnosticsDrawerOpen(page)
await page.locator('#diagnostics-clear-component').click()

await expect(page.locator('#diagnostics-component')).toContainText(
Expand All @@ -685,7 +708,7 @@ test('clear all diagnostics removes style compile diagnostics', async ({ page })
/diagnostics-toggle--error/,
)

await page.locator('#diagnostics-toggle').click()
await ensureDiagnosticsDrawerOpen(page)
await expect(page.locator('#diagnostics-styles')).toContainText(
'Style compilation failed.',
)
Expand Down Expand Up @@ -713,7 +736,7 @@ test('clear styles diagnostics removes style compile diagnostics', async ({ page
/diagnostics-toggle--error/,
)

await page.locator('#diagnostics-toggle').click()
await ensureDiagnosticsDrawerOpen(page)
await expect(page.locator('#diagnostics-styles')).toContainText(
'Style compilation failed.',
)
Expand All @@ -740,7 +763,7 @@ test('typecheck success reports ok diagnostics state in button and drawer', asyn
await expect(page.locator('#diagnostics-toggle')).toHaveClass(/diagnostics-toggle--ok/)
await expect(page.locator('#diagnostics-toggle')).toHaveText('Diagnostics')

await page.locator('#diagnostics-toggle').click()
await ensureDiagnosticsDrawerOpen(page)
await expect(page.locator('#diagnostics-component')).toContainText(
'No TypeScript errors found.',
)
Expand All @@ -766,7 +789,7 @@ test('typecheck error reports diagnostics count in button and details in drawer'
)
await expect(page.locator('#diagnostics-toggle')).toHaveText(/Diagnostics \([1-9]\d*\)/)

await page.locator('#diagnostics-toggle').click()
await expect(page.locator('#diagnostics-drawer')).toBeVisible()
await expect(page.locator('#diagnostics-component')).toContainText('TypeScript found')
await expect(page.locator('#diagnostics-component')).toContainText('TS')
})
Expand All @@ -787,7 +810,7 @@ test('component diagnostics rows navigate editor to reported line', async ({ pag
await expect(page.locator('#diagnostics-toggle')).toHaveClass(
/diagnostics-toggle--error/,
)
await page.locator('#diagnostics-toggle').click()
await ensureDiagnosticsDrawerOpen(page)

const targetDiagnostic = page
.locator('#diagnostics-component .diagnostic-line-button[data-diagnostic-line="2"]')
Expand Down Expand Up @@ -817,7 +840,7 @@ test('component diagnostics support arrow navigation and enter jump', async ({
/diagnostics-toggle--error/,
)

await page.locator('#diagnostics-toggle').click()
await ensureDiagnosticsDrawerOpen(page)

const firstDiagnostic = page
.locator('#diagnostics-component .diagnostic-line-button')
Expand Down Expand Up @@ -854,7 +877,7 @@ test('component lint error reports diagnostics count and details', async ({ page
)
await expect(page.locator('#diagnostics-toggle')).toHaveText(/Diagnostics \([1-9]\d*\)/)

await page.locator('#diagnostics-toggle').click()
await expect(page.locator('#diagnostics-drawer')).toBeVisible()
await expect(page.locator('#diagnostics-component')).toContainText(
'Biome reported issues.',
)
Expand All @@ -874,7 +897,7 @@ test('styles diagnostics rows navigate editor to reported line', async ({ page }
await expect(page.locator('#diagnostics-toggle')).toHaveClass(
/diagnostics-toggle--error/,
)
await page.locator('#diagnostics-toggle').click()
await ensureDiagnosticsDrawerOpen(page)

const targetDiagnostic = page
.locator('#diagnostics-styles .diagnostic-line-button[data-diagnostic-line="3"]')
Expand Down Expand Up @@ -904,7 +927,7 @@ test('clear component diagnostics resets rendered lint-issue status pill', async
await expect(page.locator('#status')).toHaveText(/Rendered \(Lint issues: [1-9]\d*\)/)
await expect(page.locator('#status')).toHaveClass(/status--error/)

await page.locator('#diagnostics-toggle').click()
await ensureDiagnosticsDrawerOpen(page)
await page.locator('#diagnostics-clear-component').click()

await expect(page.locator('#diagnostics-component')).toContainText(
Expand Down Expand Up @@ -932,7 +955,7 @@ test('component lint ignores unused App View and render bindings', async ({ page

await runComponentLint(page)

await page.locator('#diagnostics-toggle').click()
await ensureDiagnosticsDrawerOpen(page)
await expect(page.locator('#diagnostics-component')).toContainText(
'No Biome issues found.',
)
Expand Down Expand Up @@ -1018,7 +1041,7 @@ test('changing css dialect resets diagnostics after lint and typecheck runs', as
)
await expect(page.locator('#diagnostics-toggle')).toHaveText('Diagnostics')

await page.locator('#diagnostics-toggle').click()
await ensureDiagnosticsDrawerOpen(page)
await expect(page.locator('#diagnostics-component')).toContainText(
'No diagnostics yet.',
)
Expand Down
22 changes: 17 additions & 5 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,11 @@ const typeDiagnostics = createTypeDiagnosticsController({
incrementTypeDiagnosticsRuns,
decrementTypeDiagnosticsRuns,
getActiveTypeDiagnosticsRuns,
onIssuesDetected: ({ issueCount }) => {
if (issueCount > 0) {
setDiagnosticsDrawerOpen(true)
}
},
})

const lintDiagnostics = createLintDiagnosticsController({
Expand All @@ -515,6 +520,11 @@ const lintDiagnostics = createLintDiagnosticsController({
setComponentDiagnostics: setTypeDiagnosticsDetails,
setStyleDiagnostics: setStyleDiagnosticsDetails,
setStatus,
onIssuesDetected: ({ issueCount }) => {
if (issueCount > 0) {
setDiagnosticsDrawerOpen(true)
}
},
})

let activeComponentLintAbortController = null
Expand Down Expand Up @@ -544,7 +554,7 @@ const syncLintPendingState = () => {
setLintDiagnosticsPending(componentLintPending || stylesLintPending)
}

const runComponentLint = async () => {
const runComponentLint = async ({ userInitiated = false } = {}) => {
activeComponentLintAbortController?.abort()
const controller = new AbortController()
activeComponentLintAbortController = controller
Expand All @@ -557,6 +567,7 @@ const runComponentLint = async () => {
try {
const result = await lintDiagnostics.lintComponent({
signal: controller.signal,
userInitiated,
})
if (result) {
lastComponentLintIssueCount = result.issueCount
Expand All @@ -570,7 +581,7 @@ const runComponentLint = async () => {
}
}

const runStylesLint = async () => {
const runStylesLint = async ({ userInitiated = false } = {}) => {
activeStylesLintAbortController?.abort()
const controller = new AbortController()
activeStylesLintAbortController = controller
Expand All @@ -583,6 +594,7 @@ const runStylesLint = async () => {
try {
const result = await lintDiagnostics.lintStyles({
signal: controller.signal,
userInitiated,
})
if (result) {
lastStylesLintIssueCount = result.issueCount
Expand Down Expand Up @@ -901,17 +913,17 @@ if (diagnosticsClearAll) {
}
if (typecheckButton) {
typecheckButton.addEventListener('click', () => {
typeDiagnostics.triggerTypeDiagnostics()
typeDiagnostics.triggerTypeDiagnostics({ userInitiated: true })
})
}
if (lintComponentButton) {
lintComponentButton.addEventListener('click', () => {
void runComponentLint()
void runComponentLint({ userInitiated: true })
})
}
if (lintStylesButton) {
lintStylesButton.addEventListener('click', () => {
void runStylesLint()
void runStylesLint({ userInitiated: true })
})
}
renderButton.addEventListener('click', renderPreview)
Expand Down
23 changes: 21 additions & 2 deletions src/modules/lint-diagnostics.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ export const createLintDiagnosticsController = ({
setComponentDiagnostics,
setStyleDiagnostics,
setStatus,
onIssuesDetected = () => {},
}) => {
let biomeWorkspacePromise = null
let componentLintRunId = 0
Expand Down Expand Up @@ -296,7 +297,7 @@ export const createLintDiagnosticsController = ({
}
}

const lintComponent = async ({ signal } = {}) => {
const lintComponent = async ({ signal, userInitiated = false } = {}) => {
componentLintRunId += 1
const runId = componentLintRunId

Expand Down Expand Up @@ -331,6 +332,15 @@ export const createLintDiagnosticsController = ({
: 'Rendered',
summary.level === 'error' ? 'error' : 'neutral',
)

if (userInitiated && summary.lines.length > 0) {
onIssuesDetected({
kind: 'lint',
scope: 'component',
issueCount: summary.lines.length,
})
}

return {
issueCount: summary.lines.length,
}
Expand All @@ -356,7 +366,7 @@ export const createLintDiagnosticsController = ({
}
}

const lintStyles = async ({ signal } = {}) => {
const lintStyles = async ({ signal, userInitiated = false } = {}) => {
stylesLintRunId += 1
const runId = stylesLintRunId

Expand Down Expand Up @@ -403,6 +413,15 @@ export const createLintDiagnosticsController = ({
: 'Rendered',
summary.level === 'error' ? 'error' : 'neutral',
)

if (userInitiated && summary.lines.length > 0) {
onIssuesDetected({
kind: 'lint',
scope: 'styles',
issueCount: summary.lines.length,
})
}

return {
issueCount: summary.lines.length,
}
Expand Down
15 changes: 12 additions & 3 deletions src/modules/type-diagnostics.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ export const createTypeDiagnosticsController = ({
incrementTypeDiagnosticsRuns,
decrementTypeDiagnosticsRuns,
getActiveTypeDiagnosticsRuns,
onIssuesDetected = () => {},
}) => {
let typeCheckRunId = 0
let typeScriptCompiler = null
Expand Down Expand Up @@ -840,7 +841,7 @@ export const createTypeDiagnosticsController = ({
.filter(diagnostic => !shouldIgnoreTypeDiagnostic(diagnostic))
}

const runTypeDiagnostics = async runId => {
const runTypeDiagnostics = async (runId, { userInitiated = false } = {}) => {
incrementTypeDiagnosticsRuns()
setTypeDiagnosticsPending(false)
setTypecheckButtonLoading(true)
Expand Down Expand Up @@ -879,6 +880,14 @@ export const createTypeDiagnosticsController = ({
level: 'error',
})
setStatus(`Rendered (Type errors: ${errors.length})`, 'error')

if (userInitiated) {
onIssuesDetected({
kind: 'type',
scope: 'component',
issueCount: errors.length,
})
}
}

if (isRenderedStatus()) {
Expand Down Expand Up @@ -911,9 +920,9 @@ export const createTypeDiagnosticsController = ({
}
}

const triggerTypeDiagnostics = () => {
const triggerTypeDiagnostics = ({ userInitiated = false } = {}) => {
typeCheckRunId += 1
void runTypeDiagnostics(typeCheckRunId)
void runTypeDiagnostics(typeCheckRunId, { userInitiated })
}

const scheduleTypeRecheck = () => {
Expand Down
2 changes: 1 addition & 1 deletion src/styles/diagnostics.css
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@
top: auto;
right: 12px;
left: 12px;
bottom: 68px;
bottom: 12px;
width: auto;
max-height: 58vh;
}
Expand Down
Loading