Skip to content

Commit

Permalink
feat: allow for literal property definition with state on classes (#1…
Browse files Browse the repository at this point in the history
…1326)

closes #11316

---------

Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
  • Loading branch information
paoloricciuti and dummdidumm committed Apr 29, 2024
1 parent c7bdef5 commit 2d2508a
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/honest-nails-share.md
@@ -0,0 +1,5 @@
---
"svelte": patch
---

feat: allow for literal property definition with state on classes
Expand Up @@ -4,6 +4,7 @@ import * as b from '../../../../utils/builders.js';
import * as assert from '../../../../utils/assert.js';
import { get_prop_source, is_state_source, should_proxy_or_freeze } from '../utils.js';
import { extract_paths } from '../../../../utils/ast.js';
import { regex_invalid_identifier_chars } from '../../../patterns.js';

/** @type {import('../types.js').ComponentVisitors} */
export const javascript_visitors_runes = {
Expand All @@ -20,9 +21,13 @@ export const javascript_visitors_runes = {
for (const definition of node.body) {
if (
definition.type === 'PropertyDefinition' &&
(definition.key.type === 'Identifier' || definition.key.type === 'PrivateIdentifier')
(definition.key.type === 'Identifier' ||
definition.key.type === 'PrivateIdentifier' ||
definition.key.type === 'Literal')
) {
const { type, name } = definition.key;
const type = definition.key.type;
const name = get_name(definition.key);
if (!name) continue;

const is_private = type === 'PrivateIdentifier';
if (is_private) private_ids.push(name);
Expand Down Expand Up @@ -79,9 +84,12 @@ export const javascript_visitors_runes = {
for (const definition of node.body) {
if (
definition.type === 'PropertyDefinition' &&
(definition.key.type === 'Identifier' || definition.key.type === 'PrivateIdentifier')
(definition.key.type === 'Identifier' ||
definition.key.type === 'PrivateIdentifier' ||
definition.key.type === 'Literal')
) {
const name = definition.key.name;
const name = get_name(definition.key);
if (!name) continue;

const is_private = definition.key.type === 'PrivateIdentifier';
const field = (is_private ? private_state : public_state).get(name);
Expand Down Expand Up @@ -160,7 +168,6 @@ export const javascript_visitors_runes = {
);
}
}

continue;
}
}
Expand Down Expand Up @@ -437,3 +444,14 @@ export const javascript_visitors_runes = {
context.next();
}
};

/**
* @param {import('estree').Identifier | import('estree').PrivateIdentifier | import('estree').Literal} node
*/
function get_name(node) {
if (node.type === 'Literal') {
return node.value?.toString().replace(regex_invalid_identifier_chars, '_');
} else {
return node.name;
}
}
2 changes: 2 additions & 0 deletions packages/svelte/src/compiler/phases/patterns.js
Expand Up @@ -15,6 +15,8 @@ export const regex_only_whitespaces = /^[ \t\n\r\f]+$/;
export const regex_not_newline_characters = /[^\n]/g;

export const regex_is_valid_identifier = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/;
// used in replace all to remove all invalid chars from a literal identifier
export const regex_invalid_identifier_chars = /(^[^a-zA-Z_$]|[^a-zA-Z0-9_$])/g;

export const regex_starts_with_vowel = /^[aeiou]/;
export const regex_heading_tags = /^h[1-6]$/;
Expand Down
@@ -0,0 +1,15 @@
import { test } from '../../test';

export default test({
html: `<button>false</button>`,

async test({ assert, target }) {
const btn = target.querySelector('button');

await btn?.click();
assert.htmlEqual(target.innerHTML, `<button>true</button>`);

await btn?.click();
assert.htmlEqual(target.innerHTML, `<button>false</button>`);
}
});
@@ -0,0 +1,12 @@
<script>
class Toggle {
"aria-pressed" = $state(false);
toggle(){
this["aria-pressed"] = !this["aria-pressed"]
}
}
const toggle = new Toggle();
</script>

<button on:click={() => toggle.toggle()}>{toggle["aria-pressed"]}</button>

0 comments on commit 2d2508a

Please sign in to comment.