diff --git a/protocol/types.d.ts b/protocol/types.d.ts index b056c78..5bf5a7e 100644 --- a/protocol/types.d.ts +++ b/protocol/types.d.ts @@ -45,7 +45,6 @@ export interface PanelState { isLoading?: boolean; formatLoading?: boolean; hasParseErrors?: boolean; - blockedByMetaschema?: boolean; noFileSelected?: boolean; } diff --git a/test/vscode/extension.test.ts b/test/vscode/extension.test.ts index 558ebe7..4a92c79 100644 --- a/test/vscode/extension.test.ts +++ b/test/vscode/extension.test.ts @@ -198,7 +198,7 @@ suite('Extension Test Suite', () => { const vscodeJsonDiagnostics = diagnostics.filter(diagnostic => diagnostic.source === 'json' || diagnostic.source === 'JSON'); - assert.strictEqual(vscodeJsonDiagnostics.length, 0, + assert.strictEqual(vscodeJsonDiagnostics.length, 0, 'VS Code built-in JSON validation should be disabled'); const sourcemetaDiagnostics = diagnostics.filter(diagnostic => @@ -207,4 +207,37 @@ suite('Extension Test Suite', () => { assert.ok(sourcemetaDiagnostics.length > 0, 'Sourcemeta Studio should still report metaschema errors'); }); + + test('Should run linter even when metaschema validation fails', async function() { + this.timeout(15000); + + const extension = vscode.extensions.getExtension('sourcemeta.sourcemeta-studio'); + if (extension && !extension.isActive) { + await extension.activate(); + } + + const fixtureDir = path.join(__dirname, '..', '..', '..', 'test', 'vscode', 'fixtures'); + const schemaPath = path.join(fixtureDir, 'invalid-metaschema.json'); + + const document = await vscode.workspace.openTextDocument(vscode.Uri.file(schemaPath)); + await vscode.window.showTextDocument(document); + + await vscode.commands.executeCommand('sourcemeta-studio.openPanel'); + + await new Promise(resolve => setTimeout(resolve, 5000)); + + const diagnostics = vscode.languages.getDiagnostics(document.uri); + + const metaschemaDiagnostics = diagnostics.filter(diagnostic => + diagnostic.source === 'Sourcemeta Studio (Metaschema)'); + + const lintDiagnostics = diagnostics.filter(diagnostic => + diagnostic.source === 'Sourcemeta Studio (Lint)'); + + assert.ok(metaschemaDiagnostics.length > 0, + 'Should have metaschema errors for invalid schema'); + + assert.ok(lintDiagnostics.length > 0, + 'Should still have lint diagnostics even when metaschema fails'); + }); }); diff --git a/vscode/src/extension.ts b/vscode/src/extension.ts index 6797de2..7e8e5a5 100644 --- a/vscode/src/extension.ts +++ b/vscode/src/extension.ts @@ -123,11 +123,6 @@ function handleWebviewMessage(message: WebviewToExtensionMessage): void { return; } - if (currentPanelState.blockedByMetaschema) { - vscode.window.showErrorMessage('Cannot format schema: Metaschema validation failed. Fix metaschema errors first.'); - return; - } - // Send format loading state only, preserve existing lint/metaschema state panelManager.updateContent({ ...currentPanelState, @@ -273,44 +268,17 @@ async function updatePanelContent(): Promise { diagnosticManager.clearDiagnostics(lastActiveTextEditor.document.uri); } - // Run metaschema first, if metaschema reports errors, block other commands try { const version = await commandExecutor.getVersion(); cachedCliVersion = version; - const metaschemaRawResult = await commandExecutor.metaschema(fileInfo.absolutePath); - const metaschemaResult = parseMetaschemaResult(metaschemaRawResult.output, metaschemaRawResult.exitCode); - - if (metaschemaResult.errors && metaschemaResult.errors.length > 0) { - const blockedState: PanelState = { - fileInfo, - cliVersion: cachedCliVersion, - extensionVersion, - lintResult: { raw: '', health: null, errors: [] }, - formatResult: { output: '', exitCode: null }, - metaschemaResult, - isLoading: false, - hasParseErrors: hasJsonParseErrors({ raw: '', health: null }, metaschemaResult), - blockedByMetaschema: true - }; - currentPanelState = blockedState; - panelManager.updateContent(blockedState); - - if (lastActiveTextEditor) { - diagnosticManager.updateMetaschemaDiagnostics( - lastActiveTextEditor.document.uri, - metaschemaResult.errors - ); - } - - return; - } - - const [lintOutput, formatResult] = await Promise.all([ + const [metaschemaRawResult, lintOutput, formatResult] = await Promise.all([ + commandExecutor.metaschema(fileInfo.absolutePath), commandExecutor.lint(fileInfo.absolutePath), commandExecutor.formatCheck(fileInfo.absolutePath) ]); + const metaschemaResult = parseMetaschemaResult(metaschemaRawResult.output, metaschemaRawResult.exitCode); const lintResult = parseLintResult(lintOutput); const parseErrors = hasJsonParseErrors(lintResult, metaschemaResult); @@ -323,8 +291,7 @@ async function updatePanelContent(): Promise { formatResult, metaschemaResult, isLoading: false, - hasParseErrors: parseErrors, - blockedByMetaschema: false + hasParseErrors: parseErrors }; currentPanelState = finalState; panelManager.updateContent(finalState); diff --git a/webview/src/App.tsx b/webview/src/App.tsx index e2bb0fb..5dafc68 100644 --- a/webview/src/App.tsx +++ b/webview/src/App.tsx @@ -38,13 +38,6 @@ function App() { }; }, []); - useEffect(() => { - if (state?.blockedByMetaschema) { - setActiveTab('metaschema'); - setActiveTabInState('metaschema'); - } - }, [state?.blockedByMetaschema]); - const handleTabChange = (tab: TabType) => { setActiveTab(tab); setActiveTabInState(tab); @@ -61,10 +54,9 @@ function App() { return (
- @@ -76,8 +68,8 @@ function App() { ) : ( <> - {activeTab === 'lint' && } - {activeTab === 'format' && } + {activeTab === 'lint' && } + {activeTab === 'format' && } {activeTab === 'metaschema' && } )} diff --git a/webview/src/components/FormatTab.tsx b/webview/src/components/FormatTab.tsx index 2a71f60..e22e7b2 100644 --- a/webview/src/components/FormatTab.tsx +++ b/webview/src/components/FormatTab.tsx @@ -7,11 +7,10 @@ export interface FormatTabProps { formatResult: CommandResult; fileInfo: FileInfo | null; hasParseErrors?: boolean | undefined; - blocked?: boolean | undefined; noFileSelected?: boolean | undefined; } -export function FormatTab({ formatResult, fileInfo, hasParseErrors, blocked, noFileSelected }: FormatTabProps) { +export function FormatTab({ formatResult, fileInfo, hasParseErrors, noFileSelected }: FormatTabProps) { const handleFormatSchema = () => { formatSchema(); }; @@ -49,22 +48,6 @@ export function FormatTab({ formatResult, fileInfo, hasParseErrors, blocked, noF ); } - if (blocked) { - return ( -
-
- -
-
- Cannot Format Schema -
-
- Metaschema validation failed. Fix the metaschema errors first before attempting to format. -
-
- ); - } - if (isYaml) { return (
diff --git a/webview/src/components/HealthBar.tsx b/webview/src/components/HealthBar.tsx index d4a54b4..0c6326f 100644 --- a/webview/src/components/HealthBar.tsx +++ b/webview/src/components/HealthBar.tsx @@ -3,16 +3,15 @@ import type { LintResult } from '../../../protocol/types'; export interface HealthBarProps { lintResult: LintResult; isLoading?: boolean | undefined; - blockedByMetaschema?: boolean | undefined; noFileSelected?: boolean | undefined; } -export function HealthBar({ lintResult, isLoading, blockedByMetaschema, noFileSelected }: HealthBarProps) { +export function HealthBar({ lintResult, isLoading, noFileSelected }: HealthBarProps) { const errorCount = lintResult.errors?.length || 0; - + let health: number; - if (noFileSelected || blockedByMetaschema) { + if (noFileSelected) { health = 0; } else if (lintResult.health !== null && lintResult.health !== undefined) { health = lintResult.health; @@ -21,22 +20,20 @@ export function HealthBar({ lintResult, isLoading, blockedByMetaschema, noFileSe } else { health = 0; } - + const getHealthColor = (health: number): string => { if (health >= 80) return 'var(--success)'; if (health >= 50) return 'var(--warning)'; return 'var(--error)'; }; - const showUnknown = !blockedByMetaschema && !noFileSelected && (isLoading || (lintResult.health === null && lintResult.errors === undefined)); + const showUnknown = !noFileSelected && (isLoading || (lintResult.health === null && lintResult.errors === undefined)); return (
Schema Health: {noFileSelected ? ( N/A - ) : blockedByMetaschema ? ( - N/A ) : showUnknown ? ( ?% ) : ( diff --git a/webview/src/components/LintTab.tsx b/webview/src/components/LintTab.tsx index d0cbf67..d2976c4 100644 --- a/webview/src/components/LintTab.tsx +++ b/webview/src/components/LintTab.tsx @@ -1,15 +1,14 @@ import type { LintResult, Position } from '../../../protocol/types'; import { goToPosition } from '../message'; import { RawOutput } from './RawOutput'; -import { CheckCircle, AlertCircle, FileQuestion } from 'lucide-react'; +import { CheckCircle, FileQuestion } from 'lucide-react'; export interface LintTabProps { lintResult: LintResult; - blocked?: boolean | undefined; noFileSelected?: boolean | undefined; } -export function LintTab({ lintResult, blocked, noFileSelected }: LintTabProps) { +export function LintTab({ lintResult, noFileSelected }: LintTabProps) { const handleGoToPosition = (position: Position) => { goToPosition(position); }; @@ -30,21 +29,6 @@ export function LintTab({ lintResult, blocked, noFileSelected }: LintTabProps) { ); } - if (blocked) { - return ( -
-
- -
-
Cannot Lint Schema
-
- Metaschema validation failed. Fix the metaschema errors first before running lint. - Check the Metaschema tab for more details. -
-
- ); - } - return (
{errors.length === 0 ? ( diff --git a/webview/src/components/Tabs.tsx b/webview/src/components/Tabs.tsx index 379b92c..23aabba 100644 --- a/webview/src/components/Tabs.tsx +++ b/webview/src/components/Tabs.tsx @@ -20,7 +20,6 @@ export function Tabs({ activeTab, onTabChange, state }: TabsProps) { const lintStatus = calculateLintStatus(state.lintResult.errors?.length || 0, state.lintResult.health, state.isLoading, state.noFileSelected); const formatStatus = calculateFormatStatus(state.formatResult.exitCode, state.formatLoading, state.fileInfo?.isYaml, state.noFileSelected); const metaschemaStatus = calculateMetaschemaStatus(state.metaschemaResult.exitCode, state.isLoading, state.noFileSelected); - const lintDisabled = !!state.blockedByMetaschema; const Tab = ({ id, @@ -50,8 +49,8 @@ export function Tabs({ activeTab, onTabChange, state }: TabsProps) { return (
- - + +
);