Skip to content

Commit 7992d2e

Browse files
Merge 2581ca3 into 07fc037
2 parents 07fc037 + 2581ca3 commit 7992d2e

6 files changed

Lines changed: 21 additions & 369 deletions

File tree

.changeset/cyan-teachers-agree.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@lit/ts-transformers': major
3+
---
4+
5+
Remove transform for deprecated usage of queryAssignedNodes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'@lit/reactive-element': major
3+
---
4+
5+
Delete deprecated queryAssignedNodes behavior and arguments.
6+
7+
Migrate deprecated usage with a selector argument to use
8+
`@queryAssignedElements`. E.g.: `@queryAssignedNodes('list', true, '.item')` to
9+
`@queryAssignedElements({slot: '', flatten: false, selector: '.item'})`.

packages/reactive-element/src/decorators/query-assigned-nodes.ts

Lines changed: 6 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
*/
1313

1414
import {decorateProperty} from './base.js';
15-
import {queryAssignedElements} from './query-assigned-elements.js';
1615

1716
import type {ReactiveElement} from '../reactive-element.js';
1817

@@ -51,80 +50,17 @@ type TSDecoratorReturnType = void | any;
5150
* }
5251
* ```
5352
*
54-
* Note the type of this property should be annotated as `Array<Node>`.
53+
* Note the type of this property should be annotated as `Array<Node>`. Use the
54+
* queryAssignedElements decorator to list only elements, and optionally filter
55+
* the element list using a CSS selector.
5556
*
5657
* @category Decorator
5758
*/
5859
export function queryAssignedNodes(
5960
options?: QueryAssignedNodesOptions
60-
): TSDecoratorReturnType;
61-
62-
/**
63-
* A property decorator that converts a class property into a getter that
64-
* returns the `assignedNodes` of the given named `slot`.
65-
*
66-
* Example usage:
67-
* ```ts
68-
* class MyElement {
69-
* @queryAssignedNodes('list', true, '.item')
70-
* listItems!: Array<HTMLElement>;
71-
*
72-
* render() {
73-
* return html`
74-
* <slot name="list"></slot>
75-
* `;
76-
* }
77-
* }
78-
* ```
79-
*
80-
* Note the type of this property should be annotated as `Array<Node>` if used
81-
* without a `selector` or `Array<HTMLElement>` if a selector is provided.
82-
* Use {@linkcode queryAssignedElements @queryAssignedElements} to list only
83-
* elements, and optionally filter the element list using a CSS selector.
84-
*
85-
* @param slotName A string name of the slot.
86-
* @param flatten A boolean which when true flattens the assigned nodes,
87-
* meaning any assigned nodes that are slot elements are replaced with their
88-
* assigned nodes.
89-
* @param selector A CSS selector used to filter the elements returned.
90-
*
91-
* @category Decorator
92-
* @deprecated Prefer passing in a single options object, i.e. `{slot: 'list'}`.
93-
* If using `selector` please use `@queryAssignedElements`.
94-
* `@queryAssignedNodes('', false, '.item')` is functionally identical to
95-
* `@queryAssignedElements({slot: '', flatten: false, selector: '.item'})` or
96-
* `@queryAssignedElements({selector: '.item'})`.
97-
*/
98-
export function queryAssignedNodes(
99-
slotName?: string,
100-
flatten?: boolean,
101-
selector?: string
102-
): TSDecoratorReturnType;
103-
104-
export function queryAssignedNodes(
105-
slotOrOptions?: string | QueryAssignedNodesOptions,
106-
flatten?: boolean,
107-
selector?: string
108-
) {
109-
// Normalize the overloaded arguments.
110-
let slot = slotOrOptions;
111-
let assignedNodesOptions: AssignedNodesOptions;
112-
if (typeof slotOrOptions === 'object') {
113-
slot = slotOrOptions.slot;
114-
assignedNodesOptions = slotOrOptions;
115-
} else {
116-
assignedNodesOptions = {flatten};
117-
}
118-
119-
// For backwards compatibility, queryAssignedNodes with a selector behaves
120-
// exactly like queryAssignedElements with a selector.
121-
if (selector) {
122-
return queryAssignedElements({
123-
slot: slot as string,
124-
flatten,
125-
selector,
126-
});
127-
}
61+
): TSDecoratorReturnType {
62+
const slot = options?.slot;
63+
const assignedNodesOptions = options;
12864

12965
return decorateProperty({
13066
descriptor: (_name: PropertyKey) => ({

packages/reactive-element/src/test/decorators/queryAssignedNodes_test.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,9 @@ const flush =
2424
class D extends RenderingElement {
2525
@queryAssignedNodes() defaultAssigned!: Node[];
2626

27-
// Testing backwards compatible deprecated API.
28-
@queryAssignedNodes('footer', true) _footerAssigned!: Node[];
2927
@queryAssignedNodes({slot: 'footer', flatten: true})
3028
footerAssigned!: Node[];
3129

32-
// Testing backwards compatible deprecated API.
33-
@queryAssignedNodes('footer', true, '.item')
34-
_footerAssignedItems!: HTMLElement[];
35-
// Legacy selector can be transformed into queryAssignedElements.
3630
@queryAssignedElements({slot: 'footer', flatten: true, selector: '.item'})
3731
footerAssignedItems!: HTMLElement[];
3832

@@ -166,41 +160,34 @@ const flush =
166160
// Note, `defaultAssigned` does `flatten` so we test that the property
167161
// reflects current state and state when nodes are added or removed to
168162
// the light DOM of the element containing the element under test.
169-
assert.deepEqual(el.assignedNodesEl._footerAssigned, []);
170163
assert.deepEqual(el.assignedNodesEl.footerAssigned, []);
171164
const child1 = document.createElement('div');
172165
const child2 = document.createElement('div');
173166
el.append(child1, child2);
174167
flush();
175-
assert.deepEqual(el.assignedNodesEl._footerAssigned, [child1, child2]);
176168
assert.deepEqual(el.assignedNodesEl.footerAssigned, [child1, child2]);
177169
child2.remove();
178170
flush();
179-
assert.deepEqual(el.assignedNodesEl._footerAssigned, [child1]);
180171
assert.deepEqual(el.assignedNodesEl.footerAssigned, [child1]);
181172
});
182173

183174
test('returns assignedNodes for slot filtered by selector', () => {
184175
// Note, `defaultAssigned` does `flatten` so we test that the property
185176
// reflects current state and state when nodes are added or removed to
186177
// the light DOM of the element containing the element under test.
187-
assert.deepEqual(el.assignedNodesEl._footerAssignedItems, []);
188178
assert.deepEqual(el.assignedNodesEl.footerAssignedItems, []);
189179
const child1 = document.createElement('div');
190180
const child2 = document.createElement('div');
191181
child2.classList.add('item');
192182
el.append(child1, child2);
193183
flush();
194-
assert.deepEqual(el.assignedNodesEl._footerAssignedItems, [child2]);
195184
assert.deepEqual(el.assignedNodesEl.footerAssignedItems, [child2]);
196185
child2.remove();
197186
flush();
198-
assert.deepEqual(el.assignedNodesEl._footerAssignedItems, []);
199187
assert.deepEqual(el.assignedNodesEl.footerAssignedItems, []);
200188
});
201189

202190
test('returns assignedNodes for slot that contains text nodes filtered by selector', () => {
203-
assert.deepEqual(el.assignedNodesEl._footerAssignedItems, []);
204191
assert.deepEqual(el.assignedNodesEl.footerAssignedItems, []);
205192
const child1 = document.createElement('div');
206193
const child2 = document.createElement('div');
@@ -213,11 +200,9 @@ const flush =
213200
el.appendChild(child2);
214201
el.appendChild(text2);
215202
flush();
216-
assert.deepEqual(el.assignedNodesEl._footerAssignedItems, [child2]);
217203
assert.deepEqual(el.assignedNodesEl.footerAssignedItems, [child2]);
218204
el.removeChild(child2);
219205
flush();
220-
assert.deepEqual(el.assignedNodesEl._footerAssignedItems, []);
221206
assert.deepEqual(el.assignedNodesEl.footerAssignedItems, []);
222207
});
223208

packages/ts-transformers/src/internal/decorators/query-assigned-nodes.ts

Lines changed: 0 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,8 @@
44
* SPDX-License-Identifier: BSD-3-Clause
55
*/
66

7-
import ts from 'typescript';
8-
97
import {QueryAssignedElementsVisitor} from './query-assigned-elements.js';
108

11-
import type {LitClassContext} from '../lit-class-context.js';
12-
139
/**
1410
* Transform:
1511
*
@@ -23,202 +19,8 @@ import type {LitClassContext} from '../lit-class-context.js';
2319
* ?.querySelector('slot[name=list]')
2420
* ?.assignedNodes() ?? [];
2521
* }
26-
*
27-
* Falls back on transforming the legacy queryAssignedNodes API.
2822
*/
2923
export class QueryAssignedNodesVisitor extends QueryAssignedElementsVisitor {
3024
override readonly decoratorName = 'queryAssignedNodes';
3125
override slottedQuery = 'assignedNodes';
32-
33-
private readonly legacyVisitor: QueryAssignedLegacyNodesVisitor;
34-
35-
constructor(context: ts.TransformationContext) {
36-
super(context);
37-
this.legacyVisitor = new QueryAssignedLegacyNodesVisitor(context);
38-
}
39-
40-
override visit(
41-
litClassContext: LitClassContext,
42-
property: ts.ClassElement,
43-
decorator: ts.Decorator
44-
) {
45-
if (this.legacyVisitor.visit(litClassContext, property, decorator)) {
46-
return;
47-
}
48-
super.visit(litClassContext, property, decorator);
49-
}
50-
}
51-
52-
class QueryAssignedLegacyNodesVisitor {
53-
private readonly _factory: ts.NodeFactory;
54-
55-
constructor({factory}: ts.TransformationContext) {
56-
this._factory = factory;
57-
}
58-
59-
/**
60-
* Modified `visit` to keep support for the deprecated legacy
61-
* `queryAssignedNodes` decorator. Returns a boolean to notify if it was
62-
* successfully applied.
63-
*/
64-
visit(
65-
litClassContext: LitClassContext,
66-
property: ts.ClassElement,
67-
decorator: ts.Decorator
68-
): boolean {
69-
if (!ts.isPropertyDeclaration(property)) {
70-
return false;
71-
}
72-
if (!ts.isCallExpression(decorator.expression)) {
73-
return false;
74-
}
75-
if (!ts.isIdentifier(property.name)) {
76-
return false;
77-
}
78-
const name = property.name.text;
79-
const [arg0, arg1, arg2] = decorator.expression.arguments;
80-
if (arg0 && !ts.isStringLiteral(arg0)) {
81-
// Detection for new queryAssignedNodes API.
82-
return false;
83-
}
84-
const slotName =
85-
arg0 !== undefined && ts.isStringLiteral(arg0) ? arg0.text : '';
86-
const flatten = arg1?.kind === ts.SyntaxKind.TrueKeyword;
87-
const selector =
88-
arg2 !== undefined && ts.isStringLiteral(arg2) ? arg2.text : '';
89-
litClassContext.litFileContext.replaceAndMoveComments(
90-
property,
91-
this._createQueryAssignedNodesGetter(name, slotName, flatten, selector)
92-
);
93-
return true;
94-
}
95-
96-
private _createQueryAssignedNodesGetter(
97-
name: string,
98-
slotName: string,
99-
flatten: boolean,
100-
selector: string
101-
) {
102-
const factory = this._factory;
103-
104-
const slotSelector = `slot${
105-
slotName ? `[name=${slotName}]` : ':not([name])'
106-
}`;
107-
108-
// {flatten: true}
109-
const assignedNodesOptions = flatten
110-
? [
111-
factory.createObjectLiteralExpression(
112-
[
113-
factory.createPropertyAssignment(
114-
factory.createIdentifier('flatten'),
115-
factory.createTrue()
116-
),
117-
],
118-
false
119-
),
120-
]
121-
: [];
122-
123-
// this.renderRoot?.querySelector(<selector>)?.assignedNodes(<options>)
124-
const assignedNodes = factory.createCallChain(
125-
factory.createPropertyAccessChain(
126-
factory.createCallChain(
127-
factory.createPropertyAccessChain(
128-
factory.createPropertyAccessExpression(
129-
factory.createThis(),
130-
factory.createIdentifier('renderRoot')
131-
),
132-
factory.createToken(ts.SyntaxKind.QuestionDotToken),
133-
factory.createIdentifier('querySelector')
134-
),
135-
undefined,
136-
undefined,
137-
[factory.createStringLiteral(slotSelector)]
138-
),
139-
factory.createToken(ts.SyntaxKind.QuestionDotToken),
140-
factory.createIdentifier('assignedNodes')
141-
),
142-
undefined,
143-
undefined,
144-
assignedNodesOptions
145-
);
146-
147-
const returnExpression = !selector
148-
? assignedNodes
149-
: // <assignedNodes>?.filter((node) =>
150-
// node.nodeType === Node.ELEMENT_NODE &&
151-
// node.matches(<selector>)
152-
factory.createCallChain(
153-
factory.createPropertyAccessChain(
154-
assignedNodes,
155-
factory.createToken(ts.SyntaxKind.QuestionDotToken),
156-
factory.createIdentifier('filter')
157-
),
158-
undefined,
159-
undefined,
160-
[
161-
factory.createArrowFunction(
162-
undefined,
163-
undefined,
164-
[
165-
factory.createParameterDeclaration(
166-
undefined,
167-
undefined,
168-
factory.createIdentifier('node'),
169-
undefined,
170-
undefined,
171-
undefined
172-
),
173-
],
174-
undefined,
175-
factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
176-
factory.createBinaryExpression(
177-
factory.createBinaryExpression(
178-
factory.createPropertyAccessExpression(
179-
factory.createIdentifier('node'),
180-
factory.createIdentifier('nodeType')
181-
),
182-
factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
183-
factory.createPropertyAccessExpression(
184-
factory.createIdentifier('Node'),
185-
factory.createIdentifier('ELEMENT_NODE')
186-
)
187-
),
188-
factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
189-
factory.createCallExpression(
190-
factory.createPropertyAccessExpression(
191-
factory.createIdentifier('node'),
192-
factory.createIdentifier('matches')
193-
),
194-
undefined,
195-
[factory.createStringLiteral(selector)]
196-
)
197-
)
198-
),
199-
]
200-
);
201-
202-
// { return <returnExpression> }
203-
const getterBody = factory.createBlock(
204-
[
205-
factory.createReturnStatement(
206-
factory.createBinaryExpression(
207-
returnExpression,
208-
factory.createToken(ts.SyntaxKind.QuestionQuestionToken),
209-
factory.createArrayLiteralExpression([], false)
210-
)
211-
),
212-
],
213-
true
214-
);
215-
216-
return factory.createGetAccessorDeclaration(
217-
undefined,
218-
factory.createIdentifier(name),
219-
[],
220-
undefined,
221-
getterBody
222-
);
223-
}
22426
}

0 commit comments

Comments
 (0)