@litsx/babel-preset-litsx 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,754 @@
1
+ import {
2
+ createPropertyConfig,
3
+ createPropertyValue,
4
+ mergePropertyConfig,
5
+ } from "./transform-litsx-properties.js";
6
+
7
+ let t;
8
+
9
+ export function setStaticHoistsBabelTypes(types) {
10
+ t = types;
11
+ }
12
+
13
+ function isLightDomHoist(statement) {
14
+ if (!t.isExpressionStatement(statement)) return false;
15
+ if (!t.isCallExpression(statement.expression)) return false;
16
+ if (!t.isIdentifier(statement.expression.callee, { name: "__litsx_static_lightDom" })) {
17
+ return false;
18
+ }
19
+ if (statement.expression.arguments.length !== 0) {
20
+ throw new Error("^lightDom() does not accept arguments.");
21
+ }
22
+ return true;
23
+ }
24
+
25
+ function createStaticHoistGetter(name, symbolId, expression) {
26
+ const getter = t.classMethod(
27
+ "get",
28
+ t.identifier(name),
29
+ [],
30
+ t.blockStatement([
31
+ t.returnStatement(
32
+ t.callExpression(
33
+ t.memberExpression(t.thisExpression(), t.identifier("__litsxStatic")),
34
+ [
35
+ t.cloneNode(symbolId),
36
+ t.arrowFunctionExpression([], expression),
37
+ ]
38
+ )
39
+ ),
40
+ ])
41
+ );
42
+ getter.static = true;
43
+ return getter;
44
+ }
45
+
46
+ function resolveStaticHoistExpression(expression) {
47
+ return t.callExpression(
48
+ t.memberExpression(t.thisExpression(), t.identifier("__litsxResolveStaticValue")),
49
+ [t.cloneNode(expression)]
50
+ );
51
+ }
52
+
53
+ function createPropertiesHoistResolver(propertiesStatic, staticProps, expression) {
54
+ const mergedProperties = propertiesStatic.map((property) => t.cloneNode(property));
55
+ if (staticProps.length > 0) {
56
+ mergeStaticPropsIntoProperties(mergedProperties, staticProps);
57
+ }
58
+
59
+ return t.callExpression(
60
+ t.memberExpression(t.thisExpression(), t.identifier("__litsxMergeProperties")),
61
+ [
62
+ t.objectExpression(mergedProperties),
63
+ resolveStaticHoistExpression(expression),
64
+ ]
65
+ );
66
+ }
67
+
68
+ function createStylesHoistResolver(staticStyles, expression) {
69
+ const resolvedExpression = resolveStaticHoistExpression(expression);
70
+ if (staticStyles.length === 0) {
71
+ return resolvedExpression;
72
+ }
73
+
74
+ const baseStyles =
75
+ staticStyles.length === 1
76
+ ? t.cloneNode(staticStyles[0])
77
+ : t.arrayExpression(staticStyles.map((style) => t.cloneNode(style)));
78
+
79
+ return t.logicalExpression("||", resolvedExpression, baseStyles);
80
+ }
81
+
82
+ function getStaticPropsExpression(statement) {
83
+ if (!t.isExpressionStatement(statement)) return null;
84
+ if (!t.isCallExpression(statement.expression)) return null;
85
+ const isLegacyStaticProps = t.isIdentifier(statement.expression.callee, { name: "staticProps" });
86
+ const isHoistedProperties = t.isIdentifier(
87
+ statement.expression.callee,
88
+ { name: "__litsx_static_properties" }
89
+ );
90
+ if (
91
+ !isLegacyStaticProps &&
92
+ !isHoistedProperties
93
+ ) {
94
+ return null;
95
+ }
96
+ if (statement.expression.arguments.length !== 1) return null;
97
+
98
+ const [argument] = statement.expression.arguments;
99
+ if (isHoistedProperties && (t.isFunctionExpression(argument) || t.isArrowFunctionExpression(argument))) {
100
+ throw new Error("^properties(...) only accepts an object literal with static Lit property options.");
101
+ }
102
+
103
+ if (!t.isObjectExpression(argument)) {
104
+ throw new Error("^properties(...) only accepts an object literal with static Lit property options.");
105
+ }
106
+
107
+ return isHoistedProperties ? {
108
+ __litsxHoistedProperties: true,
109
+ expression: t.cloneNode(argument),
110
+ } : t.cloneNode(argument);
111
+ }
112
+
113
+ function getStaticPropertyName(node) {
114
+ if (t.isIdentifier(node)) return node.name;
115
+ if (t.isStringLiteral(node)) return node.value;
116
+ return null;
117
+ }
118
+
119
+ function normalizeStaticPropOverrideValue(value) {
120
+ if (
121
+ t.isIdentifier(value) &&
122
+ ["String", "Number", "Boolean", "Object", "Array", "Date"].includes(value.name)
123
+ ) {
124
+ return createPropertyConfig(t.identifier(value.name));
125
+ }
126
+
127
+ if (t.isObjectExpression(value)) {
128
+ const typeProperty = value.properties.find(
129
+ (prop) =>
130
+ t.isObjectProperty(prop) &&
131
+ t.isIdentifier(prop.key, { name: "type" }) &&
132
+ t.isIdentifier(prop.value)
133
+ );
134
+
135
+ const attributeProperty = value.properties.find(
136
+ (prop) =>
137
+ t.isObjectProperty(prop) &&
138
+ t.isIdentifier(prop.key, { name: "attribute" }) &&
139
+ t.isBooleanLiteral(prop.value) &&
140
+ prop.value.value === false
141
+ );
142
+
143
+ return createPropertyConfig(typeProperty ? typeProperty.value : null, {
144
+ attribute: attributeProperty ? false : undefined,
145
+ });
146
+ }
147
+
148
+ throw new Error(
149
+ "^properties(...) values must be Lit property option objects or constructor references."
150
+ );
151
+ }
152
+
153
+ function mergeStaticPropertyObject(targetNode, overrideObject) {
154
+ if (!t.isObjectProperty(targetNode) || !t.isObjectExpression(targetNode.value)) {
155
+ return;
156
+ }
157
+
158
+ overrideObject.properties.forEach((property) => {
159
+ if (!t.isObjectProperty(property) && !t.isObjectMethod(property)) {
160
+ throw new Error("^properties(...) only accepts plain object members.");
161
+ }
162
+
163
+ const keyName = getStaticPropertyName(property.key);
164
+ if (!keyName) {
165
+ throw new Error("^properties(...) property option names must be static identifiers or strings.");
166
+ }
167
+
168
+ const existing = targetNode.value.properties.find(
169
+ (candidate) =>
170
+ (t.isObjectProperty(candidate) || t.isObjectMethod(candidate)) &&
171
+ getStaticPropertyName(candidate.key) === keyName
172
+ );
173
+
174
+ if (existing) {
175
+ const nextNode = t.cloneNode(property);
176
+ const index = targetNode.value.properties.indexOf(existing);
177
+ targetNode.value.properties.splice(index, 1, nextNode);
178
+ } else {
179
+ targetNode.value.properties.push(t.cloneNode(property));
180
+ }
181
+ });
182
+ }
183
+
184
+ function mergeStaticPropsIntoProperties(propertiesStatic, staticProps) {
185
+ const propertyMap = new Map();
186
+
187
+ propertiesStatic.forEach((propertyNode) => {
188
+ if (!t.isObjectProperty(propertyNode)) return;
189
+ const keyName = getStaticPropertyName(propertyNode.key);
190
+ if (!keyName) return;
191
+ propertyMap.set(keyName, propertyNode);
192
+ });
193
+
194
+ staticProps.forEach((optionsObject) => {
195
+ optionsObject.properties.forEach((property) => {
196
+ if (!t.isObjectProperty(property)) {
197
+ throw new Error("^properties(...) only accepts plain object properties.");
198
+ }
199
+
200
+ const keyName = getStaticPropertyName(property.key);
201
+ if (!keyName) {
202
+ throw new Error("^properties(...) property names must be static identifiers or strings.");
203
+ }
204
+
205
+ const existing = propertyMap.get(keyName);
206
+ const normalized = normalizeStaticPropOverrideValue(property.value);
207
+
208
+ if (!existing) {
209
+ const node = t.objectProperty(
210
+ t.identifier(keyName),
211
+ createPropertyValue(normalized, false)
212
+ );
213
+ if (t.isObjectExpression(property.value)) {
214
+ mergeStaticPropertyObject(node, property.value);
215
+ }
216
+ propertiesStatic.push(node);
217
+ propertyMap.set(keyName, node);
218
+ return;
219
+ }
220
+
221
+ mergePropertyConfig(
222
+ { node: existing },
223
+ normalized,
224
+ false
225
+ );
226
+
227
+ if (t.isObjectExpression(property.value)) {
228
+ mergeStaticPropertyObject(existing, property.value);
229
+ }
230
+ });
231
+ });
232
+ }
233
+
234
+ function normalizeStylesTemplate(argument, functionPath) {
235
+ if (t.isTemplateLiteral(argument)) {
236
+ if (
237
+ !argument.expressions.every((expression) =>
238
+ isStaticStylesExpression(expression, functionPath)
239
+ )
240
+ ) {
241
+ return null;
242
+ }
243
+ return t.templateLiteral(
244
+ argument.quasis,
245
+ argument.expressions.map((expression) =>
246
+ wrapStaticStylesInterpolation(expression)
247
+ )
248
+ );
249
+ }
250
+
251
+ if (t.isStringLiteral(argument)) {
252
+ return t.templateLiteral(
253
+ [t.templateElement({ raw: argument.value, cooked: argument.value }, true)],
254
+ []
255
+ );
256
+ }
257
+
258
+ if (isStaticStylesExpression(argument, functionPath)) {
259
+ return t.templateLiteral(
260
+ [
261
+ t.templateElement({ raw: "", cooked: "" }, false),
262
+ t.templateElement({ raw: "", cooked: "" }, true),
263
+ ],
264
+ [wrapStaticStylesInterpolation(argument)]
265
+ );
266
+ }
267
+
268
+ return null;
269
+ }
270
+
271
+ function wrapStaticStylesInterpolation(expression) {
272
+ if (
273
+ t.isTaggedTemplateExpression(expression) &&
274
+ t.isIdentifier(expression.tag, { name: "css" })
275
+ ) {
276
+ return expression;
277
+ }
278
+
279
+ if (t.isNumericLiteral(expression)) {
280
+ return expression;
281
+ }
282
+
283
+ return t.callExpression(
284
+ t.identifier("unsafeCSS"),
285
+ [expression]
286
+ );
287
+ }
288
+
289
+ function getStaticStylesExpression(statement, functionPath) {
290
+ if (!t.isExpressionStatement(statement)) return null;
291
+ if (!t.isCallExpression(statement.expression)) return null;
292
+ const isLegacyStaticStyles = t.isIdentifier(statement.expression.callee, { name: "staticStyles" });
293
+ const isHoistedStyles = t.isIdentifier(statement.expression.callee, { name: "__litsx_static_styles" });
294
+ if (
295
+ !isLegacyStaticStyles &&
296
+ !isHoistedStyles
297
+ ) {
298
+ return null;
299
+ }
300
+ if (statement.expression.arguments.length !== 1) return null;
301
+
302
+ const [argument] = statement.expression.arguments;
303
+
304
+ if (isHoistedStyles && (t.isFunctionExpression(argument) || t.isArrowFunctionExpression(argument))) {
305
+ throw new Error("^styles(...) only accepts static values. Move dynamic values to useStyle(...) or CSS custom properties.");
306
+ }
307
+
308
+ const template = normalizeStylesTemplate(
309
+ argument,
310
+ functionPath
311
+ );
312
+ if (!template) {
313
+ throw new Error("^styles(...) only accepts static values. Move dynamic values to useStyle(...) or CSS custom properties.");
314
+ }
315
+
316
+ const expression = t.taggedTemplateExpression(t.identifier("css"), template);
317
+ return isHoistedStyles
318
+ ? { __litsxHoistedStyles: true, expression }
319
+ : expression;
320
+ }
321
+
322
+ function getStaticHoistExpression(statement, functionPath) {
323
+ if (!t.isExpressionStatement(statement)) return null;
324
+ if (!t.isCallExpression(statement.expression)) return null;
325
+ if (!t.isIdentifier(statement.expression.callee)) return null;
326
+
327
+ const calleeName = statement.expression.callee.name;
328
+ if (!calleeName.startsWith("__litsx_static_")) {
329
+ return null;
330
+ }
331
+
332
+ const name = calleeName.slice("__litsx_static_".length);
333
+ if (!name || name === "properties" || name === "styles") {
334
+ return null;
335
+ }
336
+
337
+ if (statement.expression.arguments.length !== 1) {
338
+ throw new Error(`^${name}(...) expects exactly one argument.`);
339
+ }
340
+
341
+ const [argument] = statement.expression.arguments;
342
+ if (name === "expose") {
343
+ if (t.isObjectExpression(argument)) {
344
+ return {
345
+ name,
346
+ expression: t.cloneNode(argument),
347
+ };
348
+ }
349
+
350
+ throw new Error("^expose(...) only accepts an object literal.");
351
+ }
352
+
353
+ if (t.isFunctionExpression(argument) || t.isArrowFunctionExpression(argument)) {
354
+ throw new Error(`^${name}(...) only accepts a direct static value.`);
355
+ }
356
+
357
+ if (!isStaticStylesExpression(argument, functionPath)) {
358
+ throw new Error(`^${name}(...) only accepts a direct static value.`);
359
+ }
360
+
361
+ return {
362
+ name,
363
+ expression: t.cloneNode(argument),
364
+ };
365
+ }
366
+
367
+ function createExposeHoistMembers(expression) {
368
+ const { methodsExpression } = normalizeExposeHoistExpression(expression);
369
+
370
+ return methodsExpression.properties.map((property) =>
371
+ createExposeClassMethod(property)
372
+ );
373
+ }
374
+
375
+ function normalizeExposeHoistExpression(expression) {
376
+ if (t.isObjectExpression(expression)) {
377
+ return {
378
+ methodsExpression: t.cloneNode(expression),
379
+ };
380
+ }
381
+
382
+ throw new Error("^expose(...) only accepts an object literal.");
383
+ }
384
+
385
+ function createExposeClassMethod(property) {
386
+ const method = normalizeExposePropertyToClassMethod(property);
387
+ method.static = true;
388
+ return method;
389
+ }
390
+
391
+ function normalizeExposePropertyToClassMethod(property) {
392
+ if (t.isSpreadElement(property)) {
393
+ throw new Error("^expose(...) does not accept spread elements.");
394
+ }
395
+
396
+ if (t.isObjectMethod(property)) {
397
+ if (property.kind !== "method") {
398
+ throw new Error("^expose(...) only accepts plain methods.");
399
+ }
400
+
401
+ return t.classMethod(
402
+ "method",
403
+ t.cloneNode(property.key),
404
+ property.params.map((param) => t.cloneNode(param)),
405
+ t.cloneNode(property.body),
406
+ property.computed
407
+ );
408
+ }
409
+
410
+ if (!t.isObjectProperty(property)) {
411
+ throw new Error("^expose(...) only accepts plain methods.");
412
+ }
413
+
414
+ const value = property.value;
415
+ if (!t.isFunctionExpression(value) && !t.isArrowFunctionExpression(value)) {
416
+ throw new Error("^expose(...) values must be functions.");
417
+ }
418
+
419
+ const body = t.isBlockStatement(value.body)
420
+ ? t.cloneNode(value.body)
421
+ : t.blockStatement([t.returnStatement(t.cloneNode(value.body))]);
422
+
423
+ const method = t.classMethod(
424
+ "method",
425
+ t.cloneNode(property.key),
426
+ value.params.map((param) => t.cloneNode(param)),
427
+ body,
428
+ property.computed
429
+ );
430
+ method.async = value.async;
431
+ method.generator = value.generator || false;
432
+ return method;
433
+ }
434
+
435
+ export function assertStaticHoistsStayTopLevel(functionPath) {
436
+ functionPath.traverse({
437
+ CallExpression(callPath) {
438
+ if (!t.isIdentifier(callPath.node.callee)) return;
439
+ if (!callPath.node.callee.name.startsWith("__litsx_static_")) return;
440
+
441
+ const statementParent = callPath.parentPath;
442
+ const blockParent = statementParent?.parentPath;
443
+
444
+ if (
445
+ statementParent?.isExpressionStatement() &&
446
+ blockParent?.isBlockStatement() &&
447
+ blockParent.node === functionPath.node.body
448
+ ) {
449
+ return;
450
+ }
451
+
452
+ const macroName = callPath.node.callee.name.slice("__litsx_static_".length);
453
+ throw callPath.buildCodeFrameError(
454
+ `^${macroName}(...) must appear as a top-level statement in the component body.`
455
+ );
456
+ },
457
+ });
458
+ }
459
+
460
+ function containsUnsafeCssCall(node) {
461
+ if (!node || typeof node !== "object") return false;
462
+ if (
463
+ t.isCallExpression(node) &&
464
+ t.isIdentifier(node.callee, { name: "unsafeCSS" })
465
+ ) {
466
+ return true;
467
+ }
468
+
469
+ return Object.values(node).some((value) => {
470
+ if (Array.isArray(value)) {
471
+ return value.some((entry) => containsUnsafeCssCall(entry));
472
+ }
473
+ return containsUnsafeCssCall(value);
474
+ });
475
+ }
476
+
477
+ function isStaticStylesExpression(node, functionPath, seenBindings = new Set()) {
478
+ if (
479
+ t.isStringLiteral(node) ||
480
+ t.isNumericLiteral(node) ||
481
+ t.isBooleanLiteral(node) ||
482
+ t.isNullLiteral(node) ||
483
+ t.isBigIntLiteral?.(node)
484
+ ) {
485
+ return true;
486
+ }
487
+
488
+ if (t.isTemplateLiteral(node)) {
489
+ return node.expressions.every((expression) =>
490
+ isStaticStylesExpression(expression, functionPath, seenBindings)
491
+ );
492
+ }
493
+
494
+ if (t.isIdentifier(node)) {
495
+ return isStaticStylesIdentifier(node, functionPath, seenBindings);
496
+ }
497
+
498
+ if (t.isUnaryExpression(node)) {
499
+ return isStaticStylesExpression(node.argument, functionPath, seenBindings);
500
+ }
501
+
502
+ if (t.isBinaryExpression(node) || t.isLogicalExpression(node)) {
503
+ return (
504
+ isStaticStylesExpression(node.left, functionPath, seenBindings) &&
505
+ isStaticStylesExpression(node.right, functionPath, seenBindings)
506
+ );
507
+ }
508
+
509
+ if (t.isConditionalExpression(node)) {
510
+ return (
511
+ isStaticStylesExpression(node.test, functionPath, seenBindings) &&
512
+ isStaticStylesExpression(node.consequent, functionPath, seenBindings) &&
513
+ isStaticStylesExpression(node.alternate, functionPath, seenBindings)
514
+ );
515
+ }
516
+
517
+ if (t.isArrayExpression(node)) {
518
+ return node.elements.every((element) =>
519
+ element == null || isStaticStylesExpression(element, functionPath, seenBindings)
520
+ );
521
+ }
522
+
523
+ if (t.isObjectExpression(node)) {
524
+ return node.properties.every((property) => {
525
+ if (t.isObjectProperty(property)) {
526
+ return (
527
+ (!property.computed ||
528
+ isStaticStylesExpression(property.key, functionPath, seenBindings)) &&
529
+ isStaticStylesExpression(property.value, functionPath, seenBindings)
530
+ );
531
+ }
532
+ return false;
533
+ });
534
+ }
535
+
536
+ if (t.isMemberExpression(node)) {
537
+ return (
538
+ isStaticStylesExpression(node.object, functionPath, seenBindings) &&
539
+ (!node.computed ||
540
+ isStaticStylesExpression(node.property, functionPath, seenBindings))
541
+ );
542
+ }
543
+
544
+ if (t.isCallExpression(node)) {
545
+ return (
546
+ isStaticStylesExpression(node.callee, functionPath, seenBindings) &&
547
+ node.arguments.every((argument) =>
548
+ t.isSpreadElement(argument)
549
+ ? false
550
+ : isStaticStylesExpression(argument, functionPath, seenBindings)
551
+ )
552
+ );
553
+ }
554
+
555
+ if (t.isTaggedTemplateExpression(node)) {
556
+ return (
557
+ isStaticStylesExpression(node.tag, functionPath, seenBindings) &&
558
+ isStaticStylesExpression(node.quasi, functionPath, seenBindings)
559
+ );
560
+ }
561
+
562
+ return false;
563
+ }
564
+
565
+ function isStaticStylesIdentifier(node, functionPath, seenBindings) {
566
+ const binding = functionPath?.scope
567
+ ? functionPath.scope.getBinding(node.name)
568
+ : null;
569
+
570
+ if (!binding) {
571
+ return false;
572
+ }
573
+
574
+ if (binding.path.findParent((parent) => parent === functionPath)) {
575
+ return false;
576
+ }
577
+
578
+ if (
579
+ binding.path.isImportSpecifier() ||
580
+ binding.path.isImportDefaultSpecifier() ||
581
+ binding.path.isImportNamespaceSpecifier()
582
+ ) {
583
+ return true;
584
+ }
585
+
586
+ if (binding.path.isVariableDeclarator()) {
587
+ if (binding.kind !== "const" || !binding.path.node.init) {
588
+ return false;
589
+ }
590
+
591
+ if (seenBindings.has(binding)) {
592
+ return true;
593
+ }
594
+
595
+ seenBindings.add(binding);
596
+ return isStaticStylesExpression(binding.path.node.init, functionPath, seenBindings);
597
+ }
598
+
599
+ if (binding.path.isFunctionDeclaration() || binding.path.isClassDeclaration()) {
600
+ return true;
601
+ }
602
+
603
+ return false;
604
+ }
605
+
606
+ export function processStaticHoists({
607
+ functionPath,
608
+ node,
609
+ renderStatements,
610
+ programPath,
611
+ propertiesStatic,
612
+ classMembers,
613
+ options = {},
614
+ getOrCreateModuleStaticHoistSymbol,
615
+ }) {
616
+ const staticStyles = [];
617
+ const staticProps = [];
618
+ const staticHoists = [];
619
+ let lightDomRequested = options.defaultDomMode === "light";
620
+
621
+ if (t.isBlockStatement(node.body)) {
622
+ for (let index = renderStatements.length - 1; index >= 0; index -= 1) {
623
+ const propertyOptions = getStaticPropsExpression(renderStatements[index]);
624
+ if (propertyOptions) {
625
+ if (propertyOptions.__litsxHoistedProperties) {
626
+ staticHoists.unshift({
627
+ name: "properties",
628
+ expression: propertyOptions.expression,
629
+ });
630
+ } else {
631
+ staticProps.unshift(propertyOptions);
632
+ }
633
+ renderStatements.splice(index, 1);
634
+ continue;
635
+ }
636
+
637
+ const cssExpression = getStaticStylesExpression(renderStatements[index], functionPath);
638
+ if (!cssExpression) continue;
639
+ if (cssExpression.__litsxHoistedStyles) {
640
+ staticHoists.unshift({
641
+ name: "styles",
642
+ expression: cssExpression.expression,
643
+ });
644
+ } else {
645
+ staticStyles.unshift(cssExpression);
646
+ }
647
+ renderStatements.splice(index, 1);
648
+ }
649
+
650
+ for (let index = renderStatements.length - 1; index >= 0; index -= 1) {
651
+ if (isLightDomHoist(renderStatements[index])) {
652
+ lightDomRequested = true;
653
+ renderStatements.splice(index, 1);
654
+ }
655
+ }
656
+
657
+ for (let index = renderStatements.length - 1; index >= 0; index -= 1) {
658
+ const hoistExpression = getStaticHoistExpression(renderStatements[index], functionPath);
659
+ if (!hoistExpression) continue;
660
+ staticHoists.unshift(hoistExpression);
661
+ renderStatements.splice(index, 1);
662
+ }
663
+ }
664
+
665
+ if (lightDomRequested && staticHoists.some((entry) => entry.name === "shadowRootOptions")) {
666
+ throw new Error("^lightDom() cannot be combined with ^shadowRootOptions(...).");
667
+ }
668
+
669
+ if (staticProps.length > 0) {
670
+ mergeStaticPropsIntoProperties(propertiesStatic, staticProps);
671
+ }
672
+
673
+ const hasHoistedProperties = staticHoists.some((entry) => entry.name === "properties");
674
+ if (propertiesStatic.length > 0 && !hasHoistedProperties) {
675
+ const classProperties = t.classProperty(
676
+ t.identifier("properties"),
677
+ t.objectExpression(propertiesStatic),
678
+ null,
679
+ [],
680
+ false
681
+ );
682
+
683
+ classProperties.static = true;
684
+ classMembers.push(classProperties);
685
+ }
686
+
687
+ const hasHoistedStyles = staticHoists.some((entry) => entry.name === "styles");
688
+ if (staticStyles.length > 0 && !hasHoistedStyles) {
689
+ const stylesProperty = t.classProperty(
690
+ t.identifier("styles"),
691
+ staticStyles.length === 1 ? staticStyles[0] : t.arrayExpression(staticStyles),
692
+ null,
693
+ [],
694
+ false
695
+ );
696
+ stylesProperty.static = true;
697
+ classMembers.push(stylesProperty);
698
+ }
699
+
700
+ const hoistSymbolDeclarations = [];
701
+ let needsStaticHoistsMixin = false;
702
+ const hoistMembers = staticHoists.flatMap((hoist) => {
703
+ if (hoist.name === "expose") {
704
+ return createExposeHoistMembers(hoist.expression);
705
+ }
706
+
707
+ needsStaticHoistsMixin = true;
708
+ const { symbolId, declaration } = getOrCreateModuleStaticHoistSymbol(programPath, hoist.name);
709
+ if (declaration) {
710
+ hoistSymbolDeclarations.push(declaration);
711
+ const symbolMap = programPath.getData("__litsxStaticHoistSymbols");
712
+ if (symbolMap?.has(hoist.name)) {
713
+ symbolMap.set(hoist.name, { symbolId, declaration: null });
714
+ }
715
+ }
716
+
717
+ if (hoist.name === "properties") {
718
+ return createStaticHoistGetter(
719
+ "properties",
720
+ symbolId,
721
+ createPropertiesHoistResolver(propertiesStatic, staticProps, hoist.expression)
722
+ );
723
+ }
724
+
725
+ if (hoist.name === "styles") {
726
+ return createStaticHoistGetter(
727
+ "styles",
728
+ symbolId,
729
+ createStylesHoistResolver(staticStyles, hoist.expression)
730
+ );
731
+ }
732
+
733
+ return createStaticHoistGetter(
734
+ hoist.name,
735
+ symbolId,
736
+ resolveStaticHoistExpression(hoist.expression)
737
+ );
738
+ });
739
+
740
+ return {
741
+ lightDomRequested,
742
+ hoistMembers,
743
+ hoistSymbolDeclarations,
744
+ needsStaticHoistsMixin,
745
+ needsCss:
746
+ staticStyles.length > 0 ||
747
+ staticHoists.some((entry) => entry.name === "styles"),
748
+ needsUnsafeCss:
749
+ staticStyles.some(containsUnsafeCssCall) ||
750
+ staticHoists.some(
751
+ (entry) => entry.name === "styles" && containsUnsafeCssCall(entry.expression)
752
+ ),
753
+ };
754
+ }