Skip to content

Commit

Permalink
feat: support <svelte:bounday> (#2598)
Browse files Browse the repository at this point in the history
companion to sveltejs/svelte#14211

test skipped while feature is not merged yet
  • Loading branch information
dummdidumm authored Nov 20, 2024
1 parent a1b4a64 commit 078f9a0
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 8 deletions.
23 changes: 23 additions & 0 deletions packages/language-server/src/plugins/html/dataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,17 @@ const svelteTags: ITagData[] = [
'Named slots allow consumers to target specific areas. They can also have fallback content.'
}
]
},
{
name: 'svelte:boundary',
description:
'Represents a boundary in the application. Can catch errors and show fallback UI',
attributes: [
{
name: 'onerror',
description: 'Called when an error occured within the boundary'
}
]
}
];

Expand Down Expand Up @@ -419,6 +430,18 @@ export const svelteHtmlDataProvider = newHTMLDataProvider('svelte-builtin', {
})) ?? []
});

const originalProvideAttributes =
svelteHtmlDataProvider.provideAttributes.bind(svelteHtmlDataProvider);

svelteHtmlDataProvider.provideAttributes = (tag: string) => {
if (tag === 'svelte:boundary' || tag === 'svelte:options') {
// We don't want the global attributes for these tags
return svelteTags.find((t) => t.name === tag)?.attributes ?? [];
}

return originalProvideAttributes(tag);
};

function isEvent(attr: IAttributeData) {
return attr.name.startsWith('on');
}
Expand Down
8 changes: 6 additions & 2 deletions packages/svelte2tsx/src/htmlxtojsx_v2/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,10 @@ export function convertHtmlxToJsx(
handleSnippet(
str,
node,
element instanceof InlineComponent &&
estreeTypedParent.type === 'InlineComponent'
(element instanceof InlineComponent &&
estreeTypedParent.type === 'InlineComponent') ||
(element instanceof Element &&
element.tagName === 'svelte:boundary')
? element
: undefined
);
Expand Down Expand Up @@ -133,6 +135,7 @@ export function convertHtmlxToJsx(
case 'Title':
case 'Document':
case 'Body':
case 'SvelteBoundary':
case 'Slot':
case 'SlotTemplate':
if (node.name !== '!DOCTYPE') {
Expand Down Expand Up @@ -236,6 +239,7 @@ export function convertHtmlxToJsx(
case 'Head':
case 'Title':
case 'Body':
case 'SvelteBoundary':
case 'Document':
case 'Slot':
case 'SlotTemplate':
Expand Down
23 changes: 17 additions & 6 deletions packages/svelte2tsx/src/htmlxtojsx_v2/nodes/SnippetBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { BaseNode } from '../../interfaces';
import { transform, TransformationArray } from '../utils/node-utils';
import { InlineComponent } from './InlineComponent';
import { IGNORE_POSITION_COMMENT, surroundWithIgnoreComments } from '../../utils/ignore';
import { Element } from './Element';

/**
* Transform #snippet into a function
Expand All @@ -28,7 +29,7 @@ import { IGNORE_POSITION_COMMENT, surroundWithIgnoreComments } from '../../utils
export function handleSnippet(
str: MagicString,
snippetBlock: BaseNode,
component?: InlineComponent
component?: InlineComponent | Element
): void {
const isImplicitProp = component !== undefined;
const endSnippet = str.original.lastIndexOf('{', snippetBlock.end - 1);
Expand Down Expand Up @@ -64,6 +65,7 @@ export function handleSnippet(
if (isImplicitProp) {
str.overwrite(snippetBlock.start, snippetBlock.expression.start, '', { contentOnly: true });
const transforms: TransformationArray = ['('];

if (parameters) {
transforms.push(parameters);
const [start, end] = parameters;
Expand All @@ -74,12 +76,21 @@ export function handleSnippet(
} else {
str.overwrite(snippetBlock.expression.end, startEnd, '', { contentOnly: true });
}

transforms.push(')' + afterParameters);
transforms.push([startEnd, snippetBlock.end]);
component.addImplicitSnippetProp(
[snippetBlock.expression.start, snippetBlock.expression.end],
transforms
);

if (component instanceof InlineComponent) {
component.addImplicitSnippetProp(
[snippetBlock.expression.start, snippetBlock.expression.end],
transforms
);
} else {
component.addAttribute(
[[snippetBlock.expression.start, snippetBlock.expression.end]],
transforms
);
}
} else {
const transforms: TransformationArray = [
'const ',
Expand Down Expand Up @@ -149,7 +160,7 @@ export function handleImplicitChildren(componentNode: BaseNode, component: Inlin
}

export function hoistSnippetBlock(str: MagicString, blockOrEl: BaseNode) {
if (blockOrEl.type === 'InlineComponent') {
if (blockOrEl.type === 'InlineComponent' || blockOrEl.type === 'SvelteBoundary') {
// implicit props, handled in InlineComponent
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{ svelteHTML.createElement("svelte:boundary", { "onerror":e => e,failed:(e) => { async ()/*Ωignore_positionΩ*/ => {
{ svelteHTML.createElement("p", {}); e; }
};return __sveltets_2_any(0)},}); { const $$_sliaFtahTtnenopmoC1C = __sveltets_2_ensureComponent(ComponentThatFails); new $$_sliaFtahTtnenopmoC1C({ target: __sveltets_2_any(), props: {}});}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<svelte:boundary onerror={e => e}>
<ComponentThatFails />
{#snippet failed(e)}
<p>error: {e}</p>
{/snippet}
</svelte:boundary>

0 comments on commit 078f9a0

Please sign in to comment.