$props.id()

pull/15185/head
adiguba 2 years ago
parent 8aa7dfd078
commit 74daf21e48

@ -573,7 +573,7 @@ Unrecognised compiler option %keypath%
### props_duplicate
```
Cannot use `$props()` more than once
Cannot use `%rune%` more than once
```
### props_illegal_name
@ -597,7 +597,7 @@ Declaring or accessing a prop starting with `$$` is illegal (they are reserved f
### props_invalid_placement
```
`$props()` can only be used at the top level of components as a variable declaration initializer
`%rune%` can only be used at the top level of components as a variable declaration initializer
```
### reactive_declaration_cycle

@ -120,7 +120,7 @@ This turned out to be buggy and unpredictable, particularly when working with de
## props_duplicate
> Cannot use `$props()` more than once
> Cannot use `%rune%` more than once
## props_illegal_name
@ -136,7 +136,7 @@ This turned out to be buggy and unpredictable, particularly when working with de
## props_invalid_placement
> `$props()` can only be used at the top level of components as a variable declaration initializer
> `%rune%` can only be used at the top level of components as a variable declaration initializer
## reactive_declaration_cycle

@ -339,6 +339,8 @@ declare namespace $effect {
declare function $props(): any;
declare namespace $props {
export function id(): string;
// prevent intellisense from being unhelpful
/** @deprecated */
export const apply: never;
@ -500,5 +502,3 @@ declare namespace $host {
/** @deprecated */
export const toString: never;
}
declare const $$uid: string;

@ -279,12 +279,13 @@ export function module_illegal_default_export(node) {
}
/**
* Cannot use `$props()` more than once
* Cannot use `%rune%` more than once
* @param {null | number | NodeLike} node
* @param {string} rune
* @returns {never}
*/
export function props_duplicate(node) {
e(node, 'props_duplicate', `Cannot use \`$props()\` more than once\nhttps://svelte.dev/e/props_duplicate`);
export function props_duplicate(node, rune) {
e(node, 'props_duplicate', `Cannot use \`${rune}\` more than once\nhttps://svelte.dev/e/props_duplicate`);
}
/**
@ -315,12 +316,13 @@ export function props_invalid_pattern(node) {
}
/**
* `$props()` can only be used at the top level of components as a variable declaration initializer
* `%rune%` can only be used at the top level of components as a variable declaration initializer
* @param {null | number | NodeLike} node
* @param {string} rune
* @returns {never}
*/
export function props_invalid_placement(node) {
e(node, 'props_invalid_placement', `\`$props()\` can only be used at the top level of components as a variable declaration initializer\nhttps://svelte.dev/e/props_invalid_placement`);
export function props_invalid_placement(node, rune) {
e(node, 'props_invalid_placement', `\`${rune}\` can only be used at the top level of components as a variable declaration initializer\nhttps://svelte.dev/e/props_invalid_placement`);
}
/**

@ -220,7 +220,7 @@ function get_component_name(filename) {
return name[0].toUpperCase() + name.slice(1);
}
const RESERVED = ['$$props', '$$restProps', '$$slots', '$$uid'];
const RESERVED = ['$$props', '$$restProps', '$$slots'];
/**
* @param {Program} ast
@ -416,11 +416,11 @@ export function analyze_component(root, source, options) {
immutable: runes || options.immutable,
exports: [],
uses_props: false,
props_id: null,
uses_rest_props: false,
uses_slots: false,
uses_component_bindings: false,
uses_render_tags: false,
uses_uid: false,
needs_context: false,
needs_props: false,
event_directive_node: null,

@ -55,7 +55,7 @@ export function CallExpression(node, context) {
case '$props':
if (context.state.has_props_rune) {
e.props_duplicate(node);
e.props_duplicate(node, rune);
}
context.state.has_props_rune = true;
@ -65,7 +65,7 @@ export function CallExpression(node, context) {
context.state.ast_type !== 'instance' ||
context.state.scope !== context.state.analysis.instance.scope
) {
e.props_invalid_placement(node);
e.props_invalid_placement(node, rune);
}
if (node.arguments.length > 0) {
@ -74,6 +74,28 @@ export function CallExpression(node, context) {
break;
case '$props.id':
if (context.state.analysis.props_id) {
e.props_duplicate(node, rune);
}
if (
parent.type !== 'VariableDeclarator' ||
parent.id.type !== 'Identifier' ||
context.state.ast_type !== 'instance' ||
context.state.scope !== context.state.analysis.instance.scope
) {
e.props_invalid_placement(node, rune);
}
if (node.arguments.length > 0) {
e.rune_invalid_arguments(node, rune);
}
context.state.analysis.props_id = parent.id;
break;
case '$state':
case '$state.raw':
case '$derived':

@ -35,10 +35,6 @@ export function Identifier(node, context) {
context.state.analysis.uses_slots = true;
}
if (node.name === '$$uid') {
context.state.analysis.uses_uid = true;
}
if (context.state.analysis.runes) {
if (
is_rune(node.name) &&

@ -562,8 +562,9 @@ export function client_component(analysis, options) {
component_block.body.unshift(b.stmt(b.call('$.check_target', b.id('new.target'))));
}
if (analysis.uses_uid) {
component_block.body.unshift(b.const('$$uid', b.call('$.create_uid')));
if (analysis.props_id) {
// need to be placed on first line of the component for hydration
component_block.body.unshift(b.const(analysis.props_id, b.call('$.create_uid')));
}
if (state.events.size > 0) {

@ -42,6 +42,11 @@ export function VariableDeclaration(node, context) {
continue;
}
if (rune === '$props.id') {
// skip
continue;
}
if (rune === '$props') {
/** @type {string[]} */
const seen = ['$$slots', '$$events', '$$legacy'];

@ -129,6 +129,12 @@ export function build_template_chunk(
if (value.right.value === null) {
value = { ...value, right: b.literal('') };
}
} else if (
state.analysis.props_id &&
value.type === 'Identifier' &&
value.name === state.analysis.props_id.name
) {
// do nothing ($props.id() is never null/undefined)
} else {
value = b.logical('??', value, b.literal(''));
}

@ -244,8 +244,11 @@ export function server_component(analysis, options) {
.../** @type {Statement[]} */ (template.body)
]);
if (analysis.uses_uid) {
component_block.body.unshift(b.const('$$uid', b.call('$.create_uid', b.id('$$payload'))));
if (analysis.props_id) {
// need to be placed on first line of the component for hydration
component_block.body.unshift(
b.const(analysis.props_id, b.call('$.create_uid', b.id('$$payload')))
);
}
let should_inject_context = dev || analysis.needs_context;

@ -24,6 +24,11 @@ export function VariableDeclaration(node, context) {
continue;
}
if (rune === '$props.id') {
// skip
continue;
}
if (rune === '$props') {
let has_rest = false;
// remove $bindable() from props declaration
@ -156,6 +161,10 @@ export function VariableDeclaration(node, context) {
}
}
if (declarations.length === 0) {
return b.empty;
}
return {
...node,
declarations

@ -44,14 +44,14 @@ export interface ComponentAnalysis extends Analysis {
exports: Array<{ name: string; alias: string | null }>;
/** Whether the component uses `$$props` */
uses_props: boolean;
/** The component ID variable name, if any */
props_id: Identifier | null;
/** Whether the component uses `$$restProps` */
uses_rest_props: boolean;
/** Whether the component uses `$$slots` */
uses_slots: boolean;
uses_component_bindings: boolean;
uses_render_tags: boolean;
/** Whether the component uses `$$uid` */
uses_uid: boolean;
needs_context: boolean;
needs_props: boolean;
/** Set to the first event directive (on:x) found on a DOM element in the code */

@ -433,6 +433,7 @@ const RUNES = /** @type {const} */ ([
'$state.raw',
'$state.snapshot',
'$props',
'$props.id',
'$bindable',
'$derived',
'$derived.by',

@ -2995,6 +2995,8 @@ declare namespace $effect {
declare function $props(): any;
declare namespace $props {
export function id(): string;
// prevent intellisense from being unhelpful
/** @deprecated */
export const apply: never;
@ -3157,6 +3159,4 @@ declare namespace $host {
export const toString: never;
}
declare const $$uid: string;
//# sourceMappingURL=index.d.ts.map

Loading…
Cancel
Save