ripple 0.3.0 → 0.3.2

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.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#802](https://github.com/Ripple-TS/ripple/pull/802)
8
+ [`42524c9`](https://github.com/Ripple-TS/ripple/commit/42524c9551b1950d7f7a0336ce396fc312b6fe51)
9
+ Thanks [@leonidaz](https://github.com/leonidaz)! - Editor support for
10
+ #ripple.style
11
+
12
+ - Updated dependencies
13
+ [[`42524c9`](https://github.com/Ripple-TS/ripple/commit/42524c9551b1950d7f7a0336ce396fc312b6fe51)]:
14
+ - ripple@0.3.2
15
+
16
+ ## 0.3.1
17
+
18
+ ### Patch Changes
19
+
20
+ - [#799](https://github.com/Ripple-TS/ripple/pull/799)
21
+ [`87c2078`](https://github.com/Ripple-TS/ripple/commit/87c20780f6f6f7339cf94b9a9d08e028533df0a2)
22
+ Thanks [@leonidaz](https://github.com/leonidaz)! - Fix imports for removed
23
+ functions
24
+
25
+ - Updated dependencies
26
+ [[`87c2078`](https://github.com/Ripple-TS/ripple/commit/87c20780f6f6f7339cf94b9a9d08e028533df0a2)]:
27
+ - ripple@0.3.1
28
+
3
29
  ## 0.3.0
4
30
 
5
31
  ### Minor 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.0",
6
+ "version": "0.3.2",
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.0"
108
+ "ripple": "0.3.2"
109
109
  }
110
110
  }
@@ -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
  }
@@ -547,9 +547,38 @@ const visitors = {
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
 
@@ -4591,6 +4655,16 @@ function create_tsx_with_typescript_support(comments) {
4591
4655
  context.visit(node.value.body);
4592
4656
  }
4593
4657
  },
4658
+ ParenthesizedExpression(node, context) {
4659
+ if (!node.loc) {
4660
+ base_tsx.ParenthesizedExpression?.(node, context);
4661
+ return;
4662
+ }
4663
+ const loc = /** @type {AST.SourceLocation} */ (node.loc);
4664
+ context.location(loc.start.line, loc.start.column);
4665
+ base_tsx.ParenthesizedExpression?.(node, context);
4666
+ context.location(loc.end.line, loc.end.column);
4667
+ },
4594
4668
  TSAsExpression(node, context) {
4595
4669
  if (!node.loc) {
4596
4670
  base_tsx.TSAsExpression?.(node, context);
@@ -1557,6 +1557,14 @@ export function convert_source_map_to_mappings(
1557
1557
  }
1558
1558
  return;
1559
1559
  } else if (node.type === 'ParenthesizedExpression') {
1560
+ if (node.metadata.forceMapping && node.loc) {
1561
+ const mapping = get_mapping_from_node(node, src_to_gen_map, gen_line_offsets);
1562
+ if (node.metadata.skipParenthesisMapping) {
1563
+ mapping.generatedOffsets[0] = mapping.generatedOffsets[0] + 1; // Skip the opening parenthesis
1564
+ mapping.generatedLengths[0] = mapping.generatedLengths[0] - 2; // Skip both parentheses
1565
+ }
1566
+ mappings.push(mapping);
1567
+ }
1560
1568
  // Visit the wrapped expression
1561
1569
  if (node.expression) {
1562
1570
  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
- }
@@ -80,12 +80,7 @@ export { switch_block as switch } from './switch.js';
80
80
 
81
81
  export { template, append, text } from './template.js';
82
82
 
83
- export {
84
- ripple_array,
85
- ripple_array_from,
86
- ripple_array_of,
87
- ripple_array_from_async,
88
- } from '../../array.js';
83
+ export { ripple_array } from '../../array.js';
89
84
 
90
85
  export { ripple_object } from '../../object.js';
91
86
 
@@ -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}