feat: add $effect.active rune (#9591)

* chore: add $effect.active rune

* chore: add $effect.active rune
pull/9598/head
Dominic Gannaway 1 year ago committed by GitHub
parent 13aef5245b
commit cf9130613d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
---
'svelte': patch
---
feat: add $effect.active rune

@ -504,6 +504,17 @@ function validate_call_expression(node, scope, path) {
} }
if (rune === '$effect') { if (rune === '$effect') {
const callee = node.callee;
if (
callee.type === 'MemberExpression' &&
callee.property.type === 'Identifier' &&
callee.property.name === 'active'
) {
if (node.arguments.length !== 0) {
error(node, 'invalid-rune-args-length', '$effect.active', [0]);
}
return;
}
if (parent.type !== 'ExpressionStatement') { if (parent.type !== 'ExpressionStatement') {
error(node, 'invalid-effect-location'); error(node, 'invalid-effect-location');
} }

@ -135,7 +135,7 @@ export const javascript_visitors_runes = {
for (const declarator of node.declarations) { for (const declarator of node.declarations) {
const init = declarator.init; const init = declarator.init;
const rune = get_rune(init, state.scope); const rune = get_rune(init, state.scope);
if (!rune) { if (!rune || rune === '$effect') {
if (init != null && is_hoistable_function(init)) { if (init != null && is_hoistable_function(init)) {
const hoistable_function = visit(init); const hoistable_function = visit(init);
state.hoisted.push( state.hoisted.push(
@ -291,5 +291,19 @@ export const javascript_visitors_runes = {
} }
context.next(); context.next();
},
CallExpression(node, { state, next }) {
const rune = get_rune(node, state.scope);
const callee = node.callee;
if (
rune === '$effect' &&
callee.type === 'MemberExpression' &&
callee.property.type === 'Identifier' &&
callee.property.name === 'active'
) {
return b.call('$.effect_active');
}
next();
} }
}; };

@ -35,6 +35,7 @@ import {
EACH_KEYED EACH_KEYED
} from '../../../../../constants.js'; } from '../../../../../constants.js';
import { regex_is_valid_identifier } from '../../../patterns.js'; import { regex_is_valid_identifier } from '../../../patterns.js';
import { javascript_visitors_runes } from './javascript-runes.js';
/** /**
* Serializes each style directive into something like `$.style(element, style_property, value)` * Serializes each style directive into something like `$.style(element, style_property, value)`
@ -2921,5 +2922,6 @@ export const template_visitors = {
...context.state, ...context.state,
node: b.id('$.document') node: b.id('$.document')
}); });
} },
CallExpression: javascript_visitors_runes.CallExpression
}; };

@ -550,7 +550,7 @@ const javascript_visitors_runes = {
for (const declarator of node.declarations) { for (const declarator of node.declarations) {
const rune = get_rune(declarator.init, state.scope); const rune = get_rune(declarator.init, state.scope);
if (!rune) { if (!rune || rune === '$effect') {
declarations.push(/** @type {import('estree').VariableDeclarator} */ (visit(declarator))); declarations.push(/** @type {import('estree').VariableDeclarator} */ (visit(declarator)));
continue; continue;
} }
@ -604,6 +604,20 @@ const javascript_visitors_runes = {
} }
} }
context.next(); context.next();
},
CallExpression(node, { state, next }) {
const rune = get_rune(node, state.scope);
const callee = node.callee;
if (
rune === '$effect' &&
callee.type === 'MemberExpression' &&
callee.property.type === 'Identifier' &&
callee.property.name === 'active'
) {
return b.literal(false);
}
next();
} }
}; };
@ -1579,7 +1593,9 @@ const template_visitors = {
b.stmt(b.call('$.head', b.id('$$payload'), b.arrow([b.id('$$payload')], b.block(body)))) b.stmt(b.call('$.head', b.id('$$payload'), b.arrow([b.id('$$payload')], b.block(body))))
) )
); );
} },
// @ts-ignore: need to extract this out somehow
CallExpression: javascript_visitors_runes.CallExpression
}; };
/** /**

@ -1143,6 +1143,13 @@ function internal_create_effect(type, init, sync, block, schedule) {
return signal; return signal;
} }
/**
* @returns {boolean}
*/
export function effect_active() {
return current_effect ? (current_effect.f & MANAGED) === 0 : false;
}
/** /**
* @param {() => void | (() => void)} init * @param {() => void | (() => void)} init
* @returns {import('./types.js').EffectSignal} * @returns {import('./types.js').EffectSignal}

@ -35,7 +35,8 @@ export {
onDestroy, onDestroy,
pop, pop,
push, push,
reactive_import reactive_import,
effect_active
} from './client/runtime.js'; } from './client/runtime.js';
export * from './client/validate.js'; export * from './client/validate.js';

@ -0,0 +1,15 @@
import { test } from '../../test';
export default test({
ssrHtml: `
<p>false</p>
<p>false</p>
<p>false</p>
`,
html: `
<p>false</p>
<p>true</p>
<p>true</p>
`
});

@ -0,0 +1,11 @@
<script>
const foo = $effect.active();
let bar = $state(false);
$effect.pre(() => {
bar = $effect.active();
});
</script>
<p>{foo}</p>
<p>{bar}</p>
<p>{$effect.active()}</p>
Loading…
Cancel
Save