Skip to content

Commit

Permalink
Merge pull request #6 from chialab/svelte-5
Browse files Browse the repository at this point in the history
Add support for Svelte 5
  • Loading branch information
edoardocavazza authored Jul 4, 2024
2 parents 111dc16 + a96f7b9 commit 9349bf6
Show file tree
Hide file tree
Showing 14 changed files with 2,366 additions and 2,648 deletions.
5 changes: 5 additions & 0 deletions .changeset/fair-moons-cough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@chialab/plasma': minor
---

Add support for Svelte 5.
5 changes: 4 additions & 1 deletion .github/workflows/lint_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,13 @@ jobs:
- name: Install project dependencies
run: yarn install

- name: Install browser
run: ./node_modules/.bin/playwright install chromium --with-deps

- name: Fetch build artifacts
uses: actions/download-artifact@v3
with:
name: Plasma

- name: Run tests
run: yarn test
run: yarn test --browser chromium
16 changes: 8 additions & 8 deletions docs/guide/status.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Status

| Framework | Base wrapper | Properties | Events | Slots | Typings |
| --------- | :----------: | :--------: | :----: | :---: | :-----: |
| Angular | 🚧 | 🚧 | 🚧 | 🚧 | 🚧 |
| Astro | 🚧 | 🚧 | 🚧 | 🚧 | 🚧 |
| Preact ||||||
| React ||||||
| Svelte ||||||
| Vue | 🚧 | 🚧 | 🚧 | 🚧 | 🚧 |
| Framework | Version | Base wrapper | Properties | Events | Slots | Typings |
| --------- | :-----: | :----------: | :--------: | :----: | :---: | :-----: |
| Angular | 🚧 | 🚧 | 🚧 | 🚧 | 🚧 | 🚧 |
| Astro | 🚧 | 🚧 | 🚧 | 🚧 | 🚧 | 🚧 |
| Preact | 10 | |||||
| React | 18 | |||||
| Svelte | 5 | |||||
| Vue | 🚧 | 🚧 | 🚧 | 🚧 | 🚧 | 🚧 |
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,26 +59,29 @@
"@chialab/prettier-config": "^1.2.0",
"@custom-elements-manifest/analyzer": "^0.9.0",
"@sveltejs/vite-plugin-svelte": "^3.0.1",
"@testing-library/svelte": "^5.1.0",
"@types/prompts": "^2.4.9",
"@types/react": "^18.2.39",
"@types/react-dom": "^18.2.17",
"@vitest/browser": "^1.6.0",
"chalk": "^5.3.0",
"commander": "^12.0.0",
"esbuild": "^0.20.0",
"esbuild": "^0.23.0",
"eslint": "^8.0.0",
"jsdom": "^24.0.0",
"listr2": "^7.0.2",
"playwright": "^1.44.1",
"preact": "^10.19.2",
"prettier": "^3.0.0",
"prompts": "^2.4.0",
"publint": "^0.2.5",
"react": "^18.2.0",
"react-dom": "^18.0.0",
"rimraf": "^5.0.0",
"svelte": "^4.2.7",
"svelte": "^5.0.0-next.0",
"typescript": "^5.0.0",
"vite": "^5.0.4",
"vitepress": "^1.0.0-rc.45",
"vitepress": "^1.0.0",
"vitest": "^1.0.0"
}
}
10 changes: 5 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ export async function transform<F extends Frameworks>(
: never
) {
switch (framework) {
case Frameworks.Svelte:
return transformSvelte(entry, options);
case Frameworks.React:
return transformReact(entry, options);
case Frameworks.Preact:
return transformPreact(entry, options);
return transformPreact(entry, options as PreactTransformOptions);
case Frameworks.React:
return transformReact(entry, options as ReactTransformOptions);
case Frameworks.Svelte:
return transformSvelte(entry, options as SvelteTransformOptions);
default:
throw new Error(`Unsupported framework: ${framework}`);
}
Expand Down
95 changes: 33 additions & 62 deletions src/svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ export interface SvelteTransformOptions {
* The output directory to write the converted components to.
*/
outdir: string;

/**
* The style entrypoint.
*/
styleEntrypoint?: string;
}

function getAttributes(tagName: string) {
Expand Down Expand Up @@ -183,78 +188,44 @@ export function generateSvelteComponent(entry: Entry, options: SvelteTransformOp
}
slots.push('<slot />');

const markup = definition.extend
? `<${definition.extend}
bind:this={__ref}
is="${definition.name}"
use:__forwardEvents
{...$$restProps}
>${slots.join('')}</${definition.extend}>`
: `<${definition.name}
bind:this={__ref}
use:__forwardEvents
const markup = `<!-- svelte-ignore attribute_avoid_is -->
<${definition.extend ?? definition.name}${
definition.extend
? `
is="${definition.name}"`
: ''
}
{...$$restProps}
>${slots.join('')}</${definition.name}>`;
use:__sync={{
${props.map((propName) => `${propName},`).join('\n ')}
}}
>${slots.join('')}</${definition.extend ?? definition.name}>`;

return `<script>
import { onMount, bubble, listen, get_current_component } from 'svelte/internal';
import '${options.entrypoint}';
let __ref;
let __mounted = false;
let __component = get_current_component();
let __boundEvents = [];
let __listeners = [];
let __on = __component.$on;
let __state = {
${props.map((propName) => `'${propName}': undefined,`).join('\n ')}
};
onMount(() => {
__mounted = true;
return () => {
__mounted = false;
};
});
__component.$on = (event, ...args) => {
if (__mounted) {
__listeners.push(listen(__ref, event, __forward));
} else {
__boundEvents.push(event);
}
return __on.call(__component, event, ...args);
};
function __assign(props) {
for (const key in props) {
if (props[key] !== undefined || __state[key] !== undefined) {
__state[key] = __ref[key] = props[key];
}
}
import '${options.entrypoint}';${
options.styleEntrypoint
? `
import '${options.styleEntrypoint}';`
: ''
}
function __forward(event) {
bubble(__component, event);
}
function __forwardEvents() {
while (__boundEvents.length) {
__listeners.push(listen(__ref, __boundEvents.pop(), __forward));
}
function __sync(node, props) {
const state = {};
const assign = (node, props) => {
for (const key in props)
if (props[key] !== undefined || state[key] !== undefined)
node[key] = state[key] = props[key];
};
return () => {
__listeners.forEach((unlisten) => unlisten());
assign(node, props);
return {
update(newProps) {
assign(node, newProps);
},
};
}
${props.map((propName) => `export let ${propName} = undefined;`).join('\n ')}
$: __ref && __mounted && __assign({
${props.map((propName) => `${propName},`).join('\n ')}
});
</script>
${markup}`;
Expand Down
6 changes: 3 additions & 3 deletions test/__snapshots__/svelte-element.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Element > mount component 1`] = `"<test-element data-attr="test" :scope="test-element" :defined="" stringprop="test" booleanprop="" numericprop="1"><span class="text">test</span><span class="boolean">true</span><span class="number">1</span><span class="object">{"test":true}</span></test-element>"`;
exports[`Element > mount component 1`] = `"<test-element data-attr="test" :scope="test-element" :defined="" stringprop="test" booleanprop="" numericprop="1"><!----><!----><span class="text">test</span><span class="boolean">true</span><span class="number">1</span><span class="object">{"test":true}</span></test-element>"`;

exports[`Element > mount component 2`] = `"<test-element data-attr="test" :scope="test-element" :defined="" stringprop="changed" booleanprop="" numericprop="1"><span class="text">changed</span><span class="boolean">true</span><span class="number">1</span><span class="object">{"test":true}</span></test-element>"`;
exports[`Element > mount component 2`] = `"<test-element data-attr="test" :scope="test-element" :defined="" stringprop="changed" booleanprop="" numericprop="1"><!----><!----><span class="text">changed</span><span class="boolean">true</span><span class="number">1</span><span class="object">{"test":true}</span></test-element>"`;

exports[`Element > named slot 1`] = `"<test-element :scope="test-element" :defined="">Hello<span class="text"></span><span class="number"></span><span class="object"></span><i slot="icon">icon</i></test-element>"`;
exports[`Element > named slot 1`] = `"<test-element :scope="test-element" :defined=""><!---->Hello<!----><span class="text"></span><span class="number"></span><span class="object"></span><i slot="icon">icon</i></test-element>"`;
4 changes: 2 additions & 2 deletions test/__snapshots__/svelte-link.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Link > mount component 1`] = `"<a is="test-link" data-attr="test" :scope="test-link" :defined="" stringprop="test" booleanprop="" numericprop="1"><span class="text">test</span><span class="boolean">true</span><span class="number">1</span><span class="object">{"test":true}</span></a>"`;
exports[`Link > mount component 1`] = `"<a is="test-link" data-attr="test" :scope="test-link" :defined="" stringprop="test" booleanprop="" numericprop="1"><!----><!----><span class="text">test</span><span class="boolean">true</span><span class="number">1</span><span class="object">{"test":true}</span></a>"`;

exports[`Link > mount component 2`] = `"<a is="test-link" data-attr="test" :scope="test-link" :defined="" stringprop="changed" booleanprop="" numericprop="1"><span class="text">changed</span><span class="boolean">true</span><span class="number">1</span><span class="object">{"test":true}</span></a>"`;
exports[`Link > mount component 2`] = `"<a is="test-link" data-attr="test" :scope="test-link" :defined="" stringprop="changed" booleanprop="" numericprop="1"><!----><!----><span class="text">changed</span><span class="boolean">true</span><span class="number">1</span><span class="object">{"test":true}</span></a>"`;
75 changes: 17 additions & 58 deletions test/src/svelte/TestElement.svelte
Original file line number Diff line number Diff line change
@@ -1,58 +1,19 @@
<script>
import { onMount, bubble, listen, get_current_component } from 'svelte/internal';
import 'plasma-test';
let __ref;
let __mounted = false;
let __component = get_current_component();
let __boundEvents = [];
let __listeners = [];
let __on = __component.$on;
let __state = {
'stringProp': undefined,
'booleanProp': undefined,
'numericProp': undefined,
'objectProp': undefined,
'defaultValue': undefined,
};
onMount(() => {
__mounted = true;
return () => {
__mounted = false;
function __sync(node, props) {
const state = {};
const assign = (node, props) => {
for (const key in props)
if (props[key] !== undefined || state[key] !== undefined)
node[key] = state[key] = props[key];
};
});
__component.$on = (event, ...args) => {
if (__mounted) {
__listeners.push(listen(__ref, event, __forward));
} else {
__boundEvents.push(event);
}
return __on.call(__component, event, ...args);
};
function __assign(props) {
for (const key in props) {
if (props[key] !== undefined || __state[key] !== undefined) {
__state[key] = __ref[key] = props[key];
}
}
}
function __forward(event) {
bubble(__component, event);
}
function __forwardEvents() {
while (__boundEvents.length) {
__listeners.push(listen(__ref, __boundEvents.pop(), __forward));
}
return () => {
__listeners.forEach((unlisten) => unlisten());
assign(node, props);
return {
update(newProps) {
assign(node, newProps);
},
};
}
Expand All @@ -61,18 +22,16 @@
export let numericProp = undefined;
export let objectProp = undefined;
export let defaultValue = undefined;
</script>

$: __ref && __mounted && __assign({
<!-- svelte-ignore attribute_avoid_is -->
<test-element
{...$$restProps}
use:__sync={{
stringProp,
booleanProp,
numericProp,
objectProp,
defaultValue,
});
</script>

<test-element
bind:this={__ref}
use:__forwardEvents
{...$$restProps}
}}
><slot name="icon" /><slot /></test-element>
Loading

0 comments on commit 9349bf6

Please sign in to comment.