Fix diagnostics (#9385)

* simplify a whole bunch of stuff

* delete more unused stuff

* fix diagnostics

* prettier

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/9388/head
Rich Harris 8 months ago committed by GitHub
parent 2aacfad9ae
commit 7bcd33dbe1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -12,9 +12,6 @@
import Message from './Message.svelte';
import { svelteTheme } from './theme.js';
/** @type {import('./types').StartOrEnd | null} */
export let errorLoc = null;
/** @type {import('@codemirror/lint').LintSource | undefined} */
export let diagnostics = undefined;
@ -171,9 +168,6 @@
let marked = false;
/** @type {number | null}*/
let error_line = null;
let updating_externally = false;
/** @type {import('@codemirror/state').Extension[]} */
@ -181,27 +175,15 @@
let cursor_pos = 0;
$: {
if ($cmInstance.view) {
fulfil_module_editor_ready();
}
$: if ($cmInstance.view) {
fulfil_module_editor_ready();
}
$: if ($cmInstance.view && w && h) resize();
$: {
if (marked) {
unmarkText();
marked = false;
}
if (errorLoc) {
markText({ from: errorLoc.character, to: errorLoc.character + 1, className: 'error-loc' });
error_line = errorLoc.line;
} else {
error_line = null;
}
$: if (marked) {
unmarkText();
marked = false;
}
const watcher = EditorView.updateListener.of((viewUpdate) => {

@ -1,66 +1,51 @@
<script>
import { get_repl_context } from '$lib/context.js';
import { get_full_filename } from '$lib/utils.js';
import CodeMirror from '../CodeMirror.svelte';
/** @type {import('$lib/types').StartOrEnd | null} */
export let errorLoc = null;
/** @type {boolean} */
export let autocomplete;
/** @type {any} */ // TODO
export let error;
/** @type {any[]} */ // TODO
export let warnings;
export function focus() {
$module_editor?.focus();
}
const { bundle, handle_change, module_editor, selected, bundling } = get_repl_context();
async function diagnostics() {
/** @type {import('@codemirror/lint').Diagnostic[]} */
const diagnostics = [];
if (!$selected || !$bundle) return diagnostics;
await $bundling;
const filename = get_full_filename($selected);
if (
$bundle.error &&
$bundle.error.filename === filename &&
$bundle.error.start &&
$bundle.error.end
) {
diagnostics.push({
from: $bundle.error.start.character,
to: $bundle.error.end.character,
severity: 'error',
message: $bundle.error.message
});
}
for (const warning of $bundle.warnings) {
if (warning.filename === filename) {
diagnostics.push({
from: warning.start.character,
to: warning.end.character,
severity: 'warning',
message: warning.message
});
}
}
return diagnostics;
}
const { handle_change, module_editor } = get_repl_context();
</script>
<div class="editor-wrapper">
<div class="editor notranslate" translate="no">
<CodeMirror
bind:this={$module_editor}
{errorLoc}
{autocomplete}
diagnostics={$selected && $bundle ? diagnostics : () => []}
diagnostics={() => {
if (error) {
return [
{
severity: 'error',
from: error.position[0],
to: error.position[1],
message: error.message
}
];
}
if (warnings) {
return warnings.map((warning) => ({
severity: 'warning',
from: warning.start.character,
to: warning.end.character,
message: warning.message
}));
}
return [];
}}
on:change={handle_change}
/>
</div>

@ -40,9 +40,9 @@ export default class Compiler {
/**
* @param {import('$lib/types').File} file
* @param {import('svelte/types/compiler').CompileOptions} options
* @param {import('svelte/compiler').CompileOptions} options
* @param {boolean} return_ast
* @returns
* @returns {Promise<import('$lib/workers/workers').CompileMessageData>}
*/
compile(file, options, return_ast) {
return new Promise((fulfil) => {

@ -1,22 +1,15 @@
<script>
import { get_repl_context } from '$lib/context.js';
import { BROWSER } from 'esm-env';
import { marked } from 'marked';
import CodeMirror from '../CodeMirror.svelte';
import AstView from './AstView.svelte';
import Compiler from './Compiler.js';
import CompilerOptions from './CompilerOptions.svelte';
import PaneWithPanel from './PaneWithPanel.svelte';
import Viewer from './Viewer.svelte';
export let svelteUrl;
/** @type {string | null} */
export let status;
/** @type {import('$lib/types').StartOrEnd | null} */
export let sourceErrorLoc = null;
/** @type {import('$lib/types').MessageDetails | null} */
export let runtimeError = null;
@ -35,62 +28,25 @@
/** @type {'light' | 'dark'} */
export let previewTheme;
/**
* @param {import('$lib/types').File} file
* @param {import('svelte/compiler').CompileOptions} options
*/
export async function set(file, options) {
selected_type = file.type;
/** @type {import('../types').File | null} */
export let selected;
if (file.type === 'json') {
/** @type {import('../workers/workers').CompileMessageData | null} */
export let compiled;
$: if (selected) {
if (selected.type === 'json') {
js_editor.set({ code: `/* Select a component to see its compiled code */`, lang: 'js' });
css_editor.set({ code: `/* Select a component to see its compiled code */`, lang: 'css' });
return;
}
if (file.type === 'md') {
markdown = marked(file.source);
return;
}
if (!compiler) return console.error('Compiler not initialized.');
const compiled = await compiler.compile(file, options, showAst);
if (!js_editor) return; // unmounted
js_editor.set({
code: compiled.js,
lang: 'js'
});
css_editor.set({ code: compiled.css, lang: 'css' });
ast = compiled.ast;
}
/**
* @param {import('$lib/types').File} selected
* @param {import('svelte/compiler').CompileOptions} options
*/
export async function update(selected, options) {
if (selected.type === 'json') return;
if (selected.type === 'md') {
} else if (selected.type === 'md') {
markdown = marked(selected.source);
return;
} else if (compiled) {
js_editor.set({ code: compiled.result.js, lang: 'js' });
css_editor.set({ code: compiled.result.css, lang: 'css' });
}
if (!compiler) return console.error('Compiler not initialized.');
const { result, metadata } = await compiler.compile(selected, options, showAst);
js_editor.update({ code: result.js, lang: 'js' });
css_editor.update({ code: result.css, lang: 'css' });
$runes_mode = metadata?.runes;
ast = result.ast;
}
const { module_editor, runes_mode } = get_repl_context();
const compiler = BROWSER ? new Compiler(svelteUrl) : null;
const { module_editor } = get_repl_context();
/** @type {CodeMirror} */
let js_editor;
@ -100,7 +56,6 @@
/** @type {'result' | 'js' | 'css' | 'ast'} */
let view = 'result';
let selected_type = '';
let markdown = '';
/** @type {import('svelte/types/compiler/interfaces').Ast} */
@ -108,7 +63,7 @@
</script>
<div class="view-toggle">
{#if selected_type === 'md'}
{#if selected?.type === 'md'}
<button class="active">Markdown</button>
{:else}
<button class:active={view === 'result'} on:click={() => (view = 'result')}>Result</button>
@ -121,7 +76,7 @@
</div>
<!-- component viewer -->
<div class="tab-content" class:visible={selected_type !== 'md' && view === 'result'}>
<div class="tab-content" class:visible={selected?.type !== 'md' && view === 'result'}>
<Viewer
bind:error={runtimeError}
{status}
@ -133,13 +88,13 @@
</div>
<!-- js output -->
<div class="tab-content" class:visible={selected_type !== 'md' && view === 'js'}>
<div class="tab-content" class:visible={selected?.type !== 'md' && view === 'js'}>
{#if embedded}
<CodeMirror bind:this={js_editor} errorLoc={sourceErrorLoc} readonly />
<CodeMirror bind:this={js_editor} readonly />
{:else}
<PaneWithPanel pos="50%" panel="Compiler options">
<div slot="main">
<CodeMirror bind:this={js_editor} errorLoc={sourceErrorLoc} readonly />
<CodeMirror bind:this={js_editor} readonly />
</div>
<div slot="panel-body">
@ -150,22 +105,22 @@
</div>
<!-- css output -->
<div class="tab-content" class:visible={selected_type !== 'md' && view === 'css'}>
<CodeMirror bind:this={css_editor} errorLoc={sourceErrorLoc} readonly />
<div class="tab-content" class:visible={selected?.type !== 'md' && view === 'css'}>
<CodeMirror bind:this={css_editor} readonly />
</div>
<!-- ast output -->
{#if showAst}
<div class="tab-content" class:visible={selected_type !== 'md' && view === 'ast'}>
<div class="tab-content" class:visible={selected?.type !== 'md' && view === 'ast'}>
<!-- ast view interacts with the module editor, wait for it first -->
{#if $module_editor}
<AstView {ast} autoscroll={selected_type !== 'md' && view === 'ast'} />
<AstView {ast} autoscroll={selected?.type !== 'md' && view === 'ast'} />
{/if}
</div>
{/if}
<!-- markdown output -->
<div class="tab-content" class:visible={selected_type === 'md'}>
<div class="tab-content" class:visible={selected?.type === 'md'}>
<iframe title="Markdown" srcdoc={markdown} />
</div>

@ -11,6 +11,7 @@
import Output from './Output/Output.svelte';
import { set_repl_context } from './context.js';
import { get_full_filename } from './utils.js';
import Compiler from './Output/Compiler.js';
export let packagesUrl = 'https://unpkg.com';
export let svelteUrl = `${BROWSER ? location.origin : ''}/svelte`;
@ -64,32 +65,6 @@
$files = $files.map((val) => ({ ...val, modified: false }));
}
/** @param {{ files: import('./types').File[], css?: string }} data */
export function update(data) {
$files = data.files;
const matched_file = data.files.find((file) => get_full_filename(file) === $selected_name);
$selected_name = matched_file ? get_full_filename(matched_file) : 'App.svelte';
injectedCSS = data.css ?? '';
if (matched_file) {
$module_editor?.update({
code: matched_file.source,
lang: matched_file.type
});
$output?.update?.(matched_file, $compile_options);
$module_editor?.clearEditorState();
}
populate_editor_state();
dispatch('change', { files: $files });
}
/** @type {ReturnType<typeof createEventDispatcher<{ change: { files: import('./types').File[] } }>>} */
const dispatch = createEventDispatcher();
@ -135,9 +110,6 @@
/** @type {ReplContext['module_editor']} */
const module_editor = writable(null);
/** @type {ReplContext['output']} */
const output = writable(null);
/** @type {ReplContext['toggleable']} */
const toggleable = writable(false);
@ -160,7 +132,6 @@
compile_options,
cursor_pos,
module_editor,
output,
toggleable,
runes_mode,
@ -206,8 +177,6 @@
$module_editor?.clearEditorState();
}
$output?.set($selected, $compile_options);
is_select_changing = false;
}
@ -273,16 +242,30 @@
}
}
$: if ($output && $selected) {
$output?.update?.($selected, $compile_options);
const compiler = BROWSER ? new Compiler(svelteUrl) : null;
/** @type {import('./workers/workers').CompileMessageData | null} */
let compiled = null;
/**
* @param {import('./types').File | null} $selected
* @param {import('svelte/compiler').CompileOptions} $compile_options
*/
async function recompile($selected, $compile_options) {
if (!compiler || !$selected) return;
if ($selected.type === 'svelte' || $selected.type === 'js') {
compiled = await compiler.compile($selected, $compile_options, false);
$runes_mode = compiled.metadata?.runes ?? false;
}
}
$: recompile($selected, $compile_options);
$: mobile = width < 540;
$: $toggleable = mobile && orientation === 'columns';
/** @type {import('./types').StartOrEnd} */
let sourceErrorLoc;
let width = 0;
let show_output = false;
@ -342,13 +325,15 @@
>
<section slot="a">
<ComponentSelector show_modified={showModified} on:add on:remove />
<ModuleEditor errorLoc={sourceErrorLoc} {autocomplete} />
<ModuleEditor
{autocomplete}
error={compiled?.result.error}
warnings={compiled?.result.warnings ?? []}
/>
</section>
<section slot="b" style="height: 100%;">
<Output
bind:this={$output}
{svelteUrl}
status={status_visible ? status : null}
{embedded}
{relaxed}
@ -356,6 +341,8 @@
{injectedCSS}
{showAst}
{previewTheme}
selected={$selected}
{compiled}
/>
</section>
</SplitPane>

@ -47,7 +47,6 @@ export type ReplState = {
cursor_pos: number;
toggleable: boolean;
module_editor: import('./CodeMirror.svelte').default | null;
output: import('./Output/Output.svelte').default | null;
runes_mode: boolean;
};
@ -62,7 +61,6 @@ export type ReplContext = {
cursor_pos: Writable<ReplState['cursor_pos']>;
toggleable: Writable<ReplState['toggleable']>;
module_editor: Writable<ReplState['module_editor']>;
output: Writable<ReplState['output']>;
runes_mode: Writable<ReplState['runes_mode']>;
EDITOR_STATE_MAP: Map<string, EditorState>;

@ -62,15 +62,17 @@ function compile({ id, source, options, return_ast }) {
generate: options.generate
});
const { js, css, metadata } = compiled;
const { js, css, warnings, metadata } = compiled;
return {
id,
result: {
js: js.code,
css: css?.code || `/* Add a <sty` + `le> tag to see compiled CSS */`
},
metadata
css: css?.code || `/* Add a <sty` + `le> tag to see compiled CSS */`,
error: null,
warnings,
metadata
}
};
} else if (options.filename.endsWith('.svelte.js')) {
const compiled = svelte.compileModule(source, {
@ -83,9 +85,11 @@ function compile({ id, source, options, return_ast }) {
id,
result: {
js: compiled.js.code,
css
},
metadata: compiled.metadata
css,
error: null,
warnings: compiled.warnings,
metadata: compiled.metadata
}
};
}
}
@ -94,7 +98,10 @@ function compile({ id, source, options, return_ast }) {
id,
result: {
js: `// Select a component, or a '.svelte.js' module that uses runes, to see compiled output`,
css
css,
error: null,
warnings: [],
metadata: null
}
};
} catch (err) {
@ -105,7 +112,13 @@ function compile({ id, source, options, return_ast }) {
id,
result: {
js: message,
css: message
css: message,
error: {
message: err.message,
position: err.position
},
warnings: [],
metadata: null
}
};
}

Loading…
Cancel
Save