ripple 0.3.1 → 0.3.3

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # ripple
2
2
 
3
+ ## 0.3.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#804](https://github.com/Ripple-TS/ripple/pull/804)
8
+ [`cd1073f`](https://github.com/Ripple-TS/ripple/commit/cd1073f7cc8085c8b200ada4faf77b2c35b10c6c)
9
+ Thanks [@leonidaz](https://github.com/leonidaz)! - Editor support for
10
+ #ripple.server
11
+
12
+ - Updated dependencies
13
+ [[`cd1073f`](https://github.com/Ripple-TS/ripple/commit/cd1073f7cc8085c8b200ada4faf77b2c35b10c6c)]:
14
+ - ripple@0.3.3
15
+
16
+ ## 0.3.2
17
+
18
+ ### Patch Changes
19
+
20
+ - [#802](https://github.com/Ripple-TS/ripple/pull/802)
21
+ [`42524c9`](https://github.com/Ripple-TS/ripple/commit/42524c9551b1950d7f7a0336ce396fc312b6fe51)
22
+ Thanks [@leonidaz](https://github.com/leonidaz)! - Editor support for
23
+ #ripple.style
24
+
25
+ - Updated dependencies
26
+ [[`42524c9`](https://github.com/Ripple-TS/ripple/commit/42524c9551b1950d7f7a0336ce396fc312b6fe51)]:
27
+ - ripple@0.3.2
28
+
3
29
  ## 0.3.1
4
30
 
5
31
  ### Patch Changes
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Ripple is an elegant TypeScript UI framework",
4
4
  "license": "MIT",
5
5
  "author": "Dominic Gannaway",
6
- "version": "0.3.1",
6
+ "version": "0.3.3",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index-client.js",
9
9
  "main": "src/runtime/index-client.js",
@@ -105,6 +105,6 @@
105
105
  "vscode-languageserver-types": "^3.17.5"
106
106
  },
107
107
  "peerDependencies": {
108
- "ripple": "0.3.1"
108
+ "ripple": "0.3.3"
109
109
  }
110
110
  }
@@ -2,7 +2,12 @@ export const IDENTIFIER_OBFUSCATION_PREFIX = '_$_';
2
2
  export const RIPPLE_NAMESPACE_IDENTIFIER =
3
3
  IDENTIFIER_OBFUSCATION_PREFIX + encode_utf16_char('#') + 'ripple';
4
4
  export const STYLE_IDENTIFIER = IDENTIFIER_OBFUSCATION_PREFIX + encode_utf16_char('#') + 'style';
5
- export const SERVER_IDENTIFIER = IDENTIFIER_OBFUSCATION_PREFIX + encode_utf16_char('#') + 'server';
5
+ export const SERVER_IDENTIFIER =
6
+ IDENTIFIER_OBFUSCATION_PREFIX +
7
+ encode_utf16_char('#') +
8
+ 'ripple' +
9
+ encode_utf16_char('.') +
10
+ 'server';
6
11
  export const CSS_HASH_IDENTIFIER = IDENTIFIER_OBFUSCATION_PREFIX + 'hash';
7
12
 
8
13
  const DECODE_UTF16_REGEX = /_u([0-9a-fA-F]{4})_/g;
@@ -633,8 +633,13 @@ const visitors = {
633
633
  },
634
634
 
635
635
  StyleIdentifier(node, context) {
636
+ const component = is_inside_component(context, true);
636
637
  const parent = context.path.at(-1);
637
638
 
639
+ if (component) {
640
+ component.metadata.styleIdentifierPresent = true;
641
+ }
642
+
638
643
  // #ripple.style must only be used for property access (e.g., #ripple.style.className)
639
644
  if (!parent || parent.type !== 'MemberExpression' || parent.object !== node) {
640
645
  error(
@@ -748,20 +753,20 @@ const visitors = {
748
753
  if (topScopedClasses.size > 0) {
749
754
  node.metadata.topScopedClasses = topScopedClasses;
750
755
  }
756
+ }
751
757
 
752
- if (metadata.styleClasses.size > 0) {
753
- node.metadata.styleClasses = metadata.styleClasses;
758
+ if (metadata.styleClasses.size > 0) {
759
+ node.metadata.styleClasses = metadata.styleClasses;
754
760
 
755
- for (const [className, property] of metadata.styleClasses) {
756
- if (!topScopedClasses?.has(className)) {
757
- error(
758
- `CSS class ".${className}" does not exist as a stand-alone class in ${node.id?.name ? node.id.name : "this component's"} <style> block`,
759
- context.state.analysis.module.filename,
760
- property,
761
- context.state.loose ? context.state.analysis.errors : undefined,
762
- context.state.analysis.comments,
763
- );
764
- }
761
+ for (const [className, property] of metadata.styleClasses) {
762
+ if (!topScopedClasses?.has(className)) {
763
+ error(
764
+ `CSS class ".${className}" does not exist as a stand-alone class in ${node.id?.name ? node.id.name : "this component's"} <style> block`,
765
+ context.state.analysis.module.filename,
766
+ property,
767
+ context.state.loose ? context.state.analysis.errors : undefined,
768
+ context.state.analysis.comments,
769
+ );
765
770
  }
766
771
  }
767
772
  }
@@ -541,15 +541,44 @@ const visitors = {
541
541
  },
542
542
 
543
543
  ServerIdentifier(node, context) {
544
- const id = b.id(SERVER_IDENTIFIER);
544
+ const id = b.id(SERVER_IDENTIFIER, /** @type {AST.NodeWithLocation} */ (node));
545
545
  id.metadata.source_name = '#ripple.server';
546
- return { ...node, ...id };
546
+ return id;
547
547
  },
548
548
 
549
549
  StyleIdentifier(node, context) {
550
- const id = b.id(STYLE_IDENTIFIER);
551
- id.metadata.source_name = '#ripple.style';
552
- return { ...node, ...id };
550
+ if (context.state.to_ts) {
551
+ const namespace_alias = set_hidden_import_from_ripple(
552
+ RIPPLE_NAMESPACE_IDENTIFIER,
553
+ context,
554
+ true,
555
+ );
556
+
557
+ // IMPORTANT! only add location to the ParenthesizedExpression
558
+ // otherwise it will cause partial #ripple mapping
559
+ const namespace_parens = b.parenthesized(
560
+ b.ts_as(b.id(namespace_alias), b.ts_type_reference(b.id('RippleNamespaceWithStyle'))),
561
+ slice_loc_info(/** @type {AST.NodeWithLocation} */ (node), 0, '#ripple'.length),
562
+ );
563
+ namespace_parens.metadata = {
564
+ ...namespace_parens.metadata,
565
+ forceMapping: true,
566
+ skipParenthesisMapping: true,
567
+ };
568
+
569
+ return b.member(
570
+ namespace_parens,
571
+ b.id(
572
+ 'style',
573
+ slice_loc_info(/** @type {AST.NodeWithLocation} */ (node), '#ripple.'.length),
574
+ ),
575
+ false,
576
+ false,
577
+ /** @type {AST.NodeWithLocation} */ (node),
578
+ );
579
+ }
580
+
581
+ return { ...node, ...b.id(STYLE_IDENTIFIER) };
553
582
  },
554
583
 
555
584
  ImportDeclaration(node, context) {
@@ -1928,10 +1957,14 @@ const visitors = {
1928
1957
  var_method_type = 'const';
1929
1958
  }
1930
1959
 
1931
- if (node.css !== null && node.metadata.styleIdentifierPresent) {
1960
+ if (node.metadata.styleIdentifierPresent) {
1932
1961
  /** @type {AST.Property[]} */
1933
1962
  const properties = [];
1934
- if (node.metadata.topScopedClasses && node.metadata.topScopedClasses.size > 0) {
1963
+ if (
1964
+ node.css !== null &&
1965
+ node.metadata.topScopedClasses &&
1966
+ node.metadata.topScopedClasses.size > 0
1967
+ ) {
1935
1968
  const hash = b[var_method_type](b.id(CSS_HASH_IDENTIFIER), b.literal(node.css.hash));
1936
1969
  style_statements.push(hash);
1937
1970
  for (const [className] of node.metadata.topScopedClasses) {
@@ -1947,6 +1980,37 @@ const visitors = {
1947
1980
  );
1948
1981
  }
1949
1982
  }
1983
+ if (context.state.to_ts) {
1984
+ const namespace_alias = set_hidden_import_from_ripple(
1985
+ RIPPLE_NAMESPACE_IDENTIFIER,
1986
+ context,
1987
+ true,
1988
+ );
1989
+
1990
+ // This will create a type that we'll use for type casting #ripple.style access, e.g.
1991
+ // type RippleNamespaceWithStyle = Omit<typeof _$__u0023_ripple, 'style'> & { style: typeof _$__u0023_style };
1992
+ const ripple_type_alias = b.ts_type_alias(
1993
+ b.id('RippleNamespaceWithStyle'),
1994
+ b.ts_intersection_type([
1995
+ b.ts_type_reference(
1996
+ b.id('Omit'),
1997
+ b.ts_type_parameter_instantiation([
1998
+ b.ts_type_query(b.id(namespace_alias)),
1999
+ b.ts_literal_type(b.literal('style')),
2000
+ ]),
2001
+ ),
2002
+ b.ts_type_literal([
2003
+ b.ts_property_signature(
2004
+ b.id('style'),
2005
+ b.ts_type_annotation(b.ts_type_query(b.id(STYLE_IDENTIFIER))),
2006
+ ),
2007
+ ]),
2008
+ ]),
2009
+ );
2010
+ style_statements.push(
2011
+ /** @type {AST.Statement} */ (/** @type {unknown} */ (ripple_type_alias)),
2012
+ );
2013
+ }
1950
2014
  style_statements.push(b[var_method_type](b.id(STYLE_IDENTIFIER), b.object(properties)));
1951
2015
  }
1952
2016
 
@@ -2652,8 +2716,10 @@ const visitors = {
2652
2716
  );
2653
2717
  value.loc = node.loc;
2654
2718
 
2655
- const server_identifier = b.id(SERVER_IDENTIFIER);
2656
- server_identifier.loc = node.loc;
2719
+ const server_identifier = b.id(
2720
+ SERVER_IDENTIFIER,
2721
+ slice_loc_info(/** @type {AST.NodeWithLocation} */ (node), 0, '#ripple.server'.length),
2722
+ );
2657
2723
  // Add source_name to properly map longer generated back to '#ripple.server'
2658
2724
  server_identifier.metadata.source_name = '#ripple.server';
2659
2725
 
@@ -4591,6 +4657,16 @@ function create_tsx_with_typescript_support(comments) {
4591
4657
  context.visit(node.value.body);
4592
4658
  }
4593
4659
  },
4660
+ ParenthesizedExpression(node, context) {
4661
+ if (!node.loc) {
4662
+ base_tsx.ParenthesizedExpression?.(node, context);
4663
+ return;
4664
+ }
4665
+ const loc = /** @type {AST.SourceLocation} */ (node.loc);
4666
+ context.location(loc.start.line, loc.start.column);
4667
+ base_tsx.ParenthesizedExpression?.(node, context);
4668
+ context.location(loc.end.line, loc.end.column);
4669
+ },
4594
4670
  TSAsExpression(node, context) {
4595
4671
  if (!node.loc) {
4596
4672
  base_tsx.TSAsExpression?.(node, context);
@@ -422,22 +422,6 @@ export function convert_source_map_to_mappings(
422
422
  loc: node.loc,
423
423
  metadata: {},
424
424
  };
425
-
426
- if (node.metadata.source_name === '#ripple') {
427
- // Suppress the private-identifier parse diagnostic while the user is
428
- // still typing a namespace access like `#ripple.` for completions.
429
- token.metadata.suppressedDiagnostics = [18016];
430
- }
431
-
432
- if (
433
- node.metadata.source_name === '#ripple.server' ||
434
- node.metadata.source_name === '#ripple.style'
435
- ) {
436
- // Let TextMate own the coloring for these namespace forms.
437
- // Their dedicated AST nodes otherwise cause semantic tokens to repaint
438
- // the full '#ripple.server' / '#ripple.style' span after TS attaches.
439
- token.mappingData = { ...mapping_data, semantic: false };
440
- }
441
425
  } else {
442
426
  token = {
443
427
  source: node.name,
@@ -445,12 +429,6 @@ export function convert_source_map_to_mappings(
445
429
  loc: node.loc,
446
430
  metadata: {},
447
431
  };
448
- if (node.name === '#ripple') {
449
- // Suppress the private-identifier parse diagnostic while the user is
450
- // still typing a namespace access like `#ripple.` for completions.
451
- token.metadata.suppressedDiagnostics = [18016];
452
- }
453
- // No transformation - source and generated names are the same
454
432
  }
455
433
 
456
434
  if (node.metadata?.is_component) {
@@ -1557,6 +1535,14 @@ export function convert_source_map_to_mappings(
1557
1535
  }
1558
1536
  return;
1559
1537
  } else if (node.type === 'ParenthesizedExpression') {
1538
+ if (node.metadata.forceMapping && node.loc) {
1539
+ const mapping = get_mapping_from_node(node, src_to_gen_map, gen_line_offsets);
1540
+ if (node.metadata.skipParenthesisMapping) {
1541
+ mapping.generatedOffsets[0] = mapping.generatedOffsets[0] + 1; // Skip the opening parenthesis
1542
+ mapping.generatedLengths[0] = mapping.generatedLengths[0] - 2; // Skip both parentheses
1543
+ }
1544
+ mappings.push(mapping);
1545
+ }
1560
1546
  // Visit the wrapped expression
1561
1547
  if (node.expression) {
1562
1548
  visit(node.expression);
@@ -42,6 +42,7 @@ interface BaseNodeMetaData {
42
42
  has_return?: boolean;
43
43
  is_reactive?: boolean;
44
44
  lone_return?: boolean;
45
+ forceMapping?: boolean;
45
46
  }
46
47
 
47
48
  interface FunctionMetaData extends BaseNodeMetaData {
@@ -54,8 +55,8 @@ interface FunctionMetaData extends BaseNodeMetaData {
54
55
  // Strip parent, loc, and range from TSESTree nodes to match @sveltejs/acorn-typescript output
55
56
  // acorn-typescript uses start/end instead of range, and loc is optional
56
57
  type AcornTSNode<T> = Omit<T, 'parent' | 'loc' | 'range' | 'expression'> & {
57
- start: number;
58
- end: number;
58
+ start?: number;
59
+ end?: number;
59
60
  loc?: AST.SourceLocation;
60
61
  range?: AST.BaseNode['range'];
61
62
  metadata: BaseNodeMetaData;
@@ -168,12 +169,16 @@ declare module 'estree' {
168
169
  Text: TextNode;
169
170
  JSXEmptyExpression: ESTreeJSX.JSXEmptyExpression;
170
171
  ParenthesizedExpression: ParenthesizedExpression;
172
+ TSAsExpression: TSAsExpression;
171
173
  }
172
174
 
173
175
  // Missing estree type
174
176
  interface ParenthesizedExpression extends AST.BaseNode {
175
177
  type: 'ParenthesizedExpression';
176
178
  expression: AST.Expression;
179
+ metadata: BaseNodeMetaData & {
180
+ skipParenthesisMapping?: boolean;
181
+ };
177
182
  }
178
183
 
179
184
  interface Comment {
@@ -425,6 +430,8 @@ declare module 'estree' {
425
430
 
426
431
  export type RippleAttribute = AST.Attribute | AST.SpreadAttribute | AST.RefAttribute;
427
432
 
433
+ export type RippleStatement = AST.Statement | TSESTree.Statement;
434
+
428
435
  export type NodeWithChildren = AST.Element | AST.TsxCompat;
429
436
 
430
437
  export namespace CSS {
@@ -938,28 +938,3 @@ export function flatten_switch_consequent(consequent) {
938
938
  export function get_ripple_namespace_call_name(name) {
939
939
  return name == null ? null : (RIPPLE_NAMESPACE_CALL_NAME[name] ?? null);
940
940
  }
941
-
942
- /**
943
- * @param {AST.MemberExpression} member
944
- * @returns {boolean}
945
- */
946
- export function is_property_part_of_ripple_namespace(member) {
947
- /** @type {AST.MemberExpression | null} */
948
- let current = member;
949
-
950
- while (current !== null) {
951
- const source_name = current.object.metadata?.source_name;
952
- if (get_ripple_namespace_call_name(source_name) !== null) {
953
- return true;
954
- }
955
-
956
- const parent = current.metadata?.path?.at(-1);
957
- if (parent?.type !== 'MemberExpression' || parent.object !== current) {
958
- break;
959
- }
960
-
961
- current = parent;
962
- }
963
-
964
- return false;
965
- }
@@ -402,6 +402,189 @@ export function member(object, property, computed = false, optional = false, loc
402
402
  return set_location(node, loc_info);
403
403
  }
404
404
 
405
+ /**
406
+ * @param {AST.Expression} expression
407
+ * @param {AST.Node} type_annotation
408
+ * @param {AST.NodeWithLocation} [loc_info]
409
+ * @returns {AST.TSAsExpression}
410
+ */
411
+ export function ts_as(expression, type_annotation, loc_info) {
412
+ const node = /** @type {AST.TSAsExpression} */ ({
413
+ type: 'TSAsExpression',
414
+ expression,
415
+ typeAnnotation: type_annotation,
416
+ metadata: { path: [] },
417
+ });
418
+
419
+ return set_location(node, loc_info);
420
+ }
421
+
422
+ /**
423
+ * @param {AST.Expression} expression
424
+ * @param {AST.NodeWithLocation} [loc_info]
425
+ * @returns {AST.ParenthesizedExpression}
426
+ */
427
+ export function parenthesized(expression, loc_info) {
428
+ const node = /** @type {AST.ParenthesizedExpression} */ ({
429
+ type: 'ParenthesizedExpression',
430
+ expression,
431
+ metadata: { path: [] },
432
+ });
433
+
434
+ return set_location(node, loc_info);
435
+ }
436
+
437
+ /**
438
+ * @param {AST.Identifier | AST.MemberExpression} expr_name
439
+ * @param {AST.Node | null} [type_arguments]
440
+ * @param {AST.NodeWithLocation} [loc_info]
441
+ * @returns {AST.TSTypeQuery}
442
+ */
443
+ export function ts_type_query(expr_name, type_arguments = null, loc_info) {
444
+ const node = /** @type {AST.TSTypeQuery} */ ({
445
+ type: 'TSTypeQuery',
446
+ exprName: expr_name,
447
+ typeArguments: type_arguments,
448
+ metadata: { path: [] },
449
+ });
450
+
451
+ return set_location(node, loc_info);
452
+ }
453
+
454
+ /**
455
+ * @param {AST.Node[]} params
456
+ * @param {AST.NodeWithLocation} [loc_info]
457
+ * @returns {AST.TSTypeParameterInstantiation}
458
+ */
459
+ export function ts_type_parameter_instantiation(params, loc_info) {
460
+ const node = /** @type {AST.TSTypeParameterInstantiation} */ ({
461
+ type: 'TSTypeParameterInstantiation',
462
+ params,
463
+ metadata: { path: [] },
464
+ });
465
+
466
+ return set_location(node, loc_info);
467
+ }
468
+
469
+ /**
470
+ * @param {AST.Identifier | AST.Node} type_name
471
+ * @param {AST.Node | null} [type_arguments]
472
+ * @param {AST.NodeWithLocation} [loc_info]
473
+ * @returns {AST.TSTypeReference}
474
+ */
475
+ export function ts_type_reference(type_name, type_arguments = null, loc_info) {
476
+ const node = /** @type {AST.TSTypeReference} */ ({
477
+ type: 'TSTypeReference',
478
+ typeName: type_name,
479
+ typeArguments: type_arguments,
480
+ metadata: { path: [] },
481
+ });
482
+
483
+ return set_location(node, loc_info);
484
+ }
485
+
486
+ /**
487
+ * @param {AST.Literal} literal_node
488
+ * @param {AST.NodeWithLocation} [loc_info]
489
+ * @returns {AST.TSLiteralType}
490
+ */
491
+ export function ts_literal_type(literal_node, loc_info) {
492
+ const node = /** @type {AST.TSLiteralType} */ ({
493
+ type: 'TSLiteralType',
494
+ literal: literal_node,
495
+ metadata: { path: [] },
496
+ });
497
+
498
+ return set_location(node, loc_info);
499
+ }
500
+
501
+ /**
502
+ * @param {AST.Node[]} types
503
+ * @param {AST.NodeWithLocation} [loc_info]
504
+ * @returns {AST.TSIntersectionType}
505
+ */
506
+ export function ts_intersection_type(types, loc_info) {
507
+ const node = /** @type {AST.TSIntersectionType} */ ({
508
+ type: 'TSIntersectionType',
509
+ types,
510
+ metadata: { path: [] },
511
+ });
512
+
513
+ return set_location(node, loc_info);
514
+ }
515
+
516
+ /**
517
+ * @param {AST.Node} type_annotation
518
+ * @param {AST.NodeWithLocation} [loc_info]
519
+ * @returns {AST.TSTypeAnnotation}
520
+ */
521
+ export function ts_type_annotation(type_annotation, loc_info) {
522
+ const node = /** @type {AST.TSTypeAnnotation} */ ({
523
+ type: 'TSTypeAnnotation',
524
+ typeAnnotation: type_annotation,
525
+ metadata: { path: [] },
526
+ });
527
+
528
+ return set_location(node, loc_info);
529
+ }
530
+
531
+ /**
532
+ * @param {AST.Expression} key
533
+ * @param {AST.Node | null} type_annotation
534
+ * @param {AST.NodeWithLocation} [loc_info]
535
+ * @returns {AST.TSPropertySignature}
536
+ */
537
+ export function ts_property_signature(key, type_annotation = null, loc_info) {
538
+ const node = /** @type {AST.TSPropertySignature} */ ({
539
+ type: 'TSPropertySignature',
540
+ key,
541
+ accessibility: undefined,
542
+ computed: false,
543
+ optional: false,
544
+ readonly: false,
545
+ static: false,
546
+ kind: 'init',
547
+ typeAnnotation: type_annotation,
548
+ metadata: { path: [] },
549
+ });
550
+
551
+ return set_location(node, loc_info);
552
+ }
553
+
554
+ /**
555
+ * @param {AST.Node[]} members
556
+ * @param {AST.NodeWithLocation} [loc_info]
557
+ * @returns {AST.TSTypeLiteral}
558
+ */
559
+ export function ts_type_literal(members, loc_info) {
560
+ const node = /** @type {AST.TSTypeLiteral} */ ({
561
+ type: 'TSTypeLiteral',
562
+ members,
563
+ metadata: { path: [] },
564
+ });
565
+
566
+ return set_location(node, loc_info);
567
+ }
568
+
569
+ /**
570
+ * @param {AST.Identifier} id
571
+ * @param {AST.Node} type_annotation
572
+ * @param {AST.NodeWithLocation} [loc_info]
573
+ * @returns {AST.TSTypeAliasDeclaration}
574
+ */
575
+ export function ts_type_alias(id, type_annotation, loc_info) {
576
+ const node = /** @type {AST.TSTypeAliasDeclaration} */ ({
577
+ type: 'TSTypeAliasDeclaration',
578
+ id,
579
+ typeParameters: undefined,
580
+ typeAnnotation: type_annotation,
581
+ declare: false,
582
+ metadata: { path: [] },
583
+ });
584
+
585
+ return set_location(node, loc_info);
586
+ }
587
+
405
588
  /**
406
589
  * @param {string} path
407
590
  * @returns {AST.Identifier | AST.MemberExpression}
@@ -519,8 +519,7 @@ export component App() {
519
519
  });
520
520
 
521
521
  it('parses bare #ripple in loose mode for autocomplete recovery', () => {
522
- const source = `
523
- export component App() {
522
+ const source = `export component App() {
524
523
  #ripple
525
524
  }
526
525
  `;
@@ -536,6 +535,6 @@ export component App() {
536
535
  mapping.lengths[0] === '#ripple'.length,
537
536
  );
538
537
 
539
- expect(mapping?.data.customData.suppressedDiagnostics).toContain(18016);
538
+ expect(mapping).toBeDefined();
540
539
  });
541
540
  });
package/types/index.d.ts CHANGED
@@ -545,6 +545,8 @@ export function bindFiles<V extends FileList>(
545
545
  setter?: SetFunction<V>,
546
546
  ): (node: HTMLInputElement) => void;
547
547
 
548
+ type ServerBlock = {};
549
+
548
550
  export interface RippleNamespace {
549
551
  array: RippleArrayCallable;
550
552
  object: RippleObjectCallable;
@@ -559,7 +561,8 @@ export interface RippleNamespace {
559
561
  untrack: typeof untrack;
560
562
  track: typeof track;
561
563
  trackSplit: typeof trackSplit;
562
- style: Record<string, string>; // Placeholder for style-related runtime class names (e.g., #ripple.style.someClass)
564
+ style: Record<string, string>;
565
+ server: ServerBlock;
563
566
  }
564
567
 
565
568
  export declare const ripple_namespace: RippleNamespace;