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

@ -1,66 +1,51 @@
<script> <script>
import { get_repl_context } from '$lib/context.js'; import { get_repl_context } from '$lib/context.js';
import { get_full_filename } from '$lib/utils.js';
import CodeMirror from '../CodeMirror.svelte'; import CodeMirror from '../CodeMirror.svelte';
/** @type {import('$lib/types').StartOrEnd | null} */
export let errorLoc = null;
/** @type {boolean} */ /** @type {boolean} */
export let autocomplete; export let autocomplete;
/** @type {any} */ // TODO
export let error;
/** @type {any[]} */ // TODO
export let warnings;
export function focus() { export function focus() {
$module_editor?.focus(); $module_editor?.focus();
} }
const { bundle, handle_change, module_editor, selected, bundling } = get_repl_context(); const { handle_change, module_editor } = 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;
}
</script> </script>
<div class="editor-wrapper"> <div class="editor-wrapper">
<div class="editor notranslate" translate="no"> <div class="editor notranslate" translate="no">
<CodeMirror <CodeMirror
bind:this={$module_editor} bind:this={$module_editor}
{errorLoc}
{autocomplete} {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} on:change={handle_change}
/> />
</div> </div>

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

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

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

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

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

Loading…
Cancel
Save