@tsrx/core 0.0.27 → 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.
@@ -562,16 +562,17 @@ export function convert_source_map_to_mappings(
562
562
  } else if (node.type === 'JSXIdentifier') {
563
563
  // JSXIdentifiers can also be capitalized (for dynamic components)
564
564
  if (node.loc && node.name) {
565
- if (node.metadata?.is_capitalized) {
566
- tokens.push({
567
- source: node.metadata.source_name,
568
- generated: node.name,
569
- loc: node.loc,
570
- metadata: {},
571
- });
572
- } else {
573
- tokens.push({ source: node.name, generated: node.name, loc: node.loc, metadata: {} });
565
+ /** @type {Token} */
566
+ const token = {
567
+ source: node.metadata?.is_capitalized ? node.metadata.source_name : node.name,
568
+ generated: node.name,
569
+ loc: node.loc,
570
+ metadata: {},
571
+ };
572
+ if (node.metadata?.disable_verification) {
573
+ token.mappingData = { ...mapping_data, verification: false };
574
574
  }
575
+ tokens.push(token);
575
576
  }
576
577
  return; // Leaf node, don't traverse further
577
578
  } else if (node.type === 'Literal') {
@@ -866,6 +867,15 @@ export function convert_source_map_to_mappings(
866
867
  // but since we already map the opening - start, we just need the proper end
867
868
  // and it was causing some issues with mappings
868
869
  mapping.generatedLengths = [mapping.generatedLengths[0] + 1];
870
+ if (!closing && opening.selfClosing) {
871
+ const generated_close_length = '/>;'.length;
872
+ mapping.sourceOffsets = [/** @type {AST.NodeWithLocation} */ (opening).end - 2];
873
+ mapping.lengths = ['/>'.length];
874
+ mapping.generatedOffsets = [
875
+ mapping.generatedOffsets[0] + mapping.generatedLengths[0] - generated_close_length,
876
+ ];
877
+ mapping.generatedLengths = [generated_close_length];
878
+ }
869
879
  mappings.push(mapping);
870
880
  }
871
881
 
package/types/index.d.ts CHANGED
@@ -205,6 +205,7 @@ declare module 'estree' {
205
205
  interface NodeMap {
206
206
  Component: Component;
207
207
  Tsx: Tsx;
208
+ Tsrx: Tsrx;
208
209
  TsxCompat: TsxCompat;
209
210
  TSRXExpression: TSRXExpression;
210
211
  Html: Html;
@@ -213,6 +214,7 @@ declare module 'estree' {
213
214
  Text: TextNode;
214
215
  Attribute: Attribute;
215
216
  RefAttribute: RefAttribute;
217
+ RefExpression: RefExpression;
216
218
  SpreadAttribute: SpreadAttribute;
217
219
  ParenthesizedExpression: ParenthesizedExpression;
218
220
  ScriptContent: ScriptContent;
@@ -220,6 +222,7 @@ declare module 'estree' {
220
222
 
221
223
  interface ExpressionMap {
222
224
  Style: Style;
225
+ RefExpression: RefExpression;
223
226
  Text: TextNode;
224
227
  JSXEmptyExpression: ESTreeJSX.JSXEmptyExpression;
225
228
  ParenthesizedExpression: ParenthesizedExpression;
@@ -344,6 +347,16 @@ declare module 'estree' {
344
347
  closingElement: ESTreeJSX.JSXClosingElement;
345
348
  }
346
349
 
350
+ interface Tsrx extends AST.BaseNode {
351
+ type: 'Tsrx';
352
+ attributes: Array<any>;
353
+ children: AST.Node[];
354
+ selfClosing?: boolean;
355
+ unclosed?: boolean;
356
+ openingElement: ESTreeJSX.JSXOpeningElement;
357
+ closingElement: ESTreeJSX.JSXClosingElement;
358
+ }
359
+
347
360
  interface TsxCompat extends AST.BaseNode {
348
361
  type: 'TsxCompat';
349
362
  kind: string;
@@ -437,6 +450,12 @@ declare module 'estree' {
437
450
  loc?: AST.SourceLocation;
438
451
  }
439
452
 
453
+ interface RefExpression extends AST.BaseNode {
454
+ type: 'RefExpression';
455
+ argument: AST.Expression;
456
+ loc?: AST.SourceLocation;
457
+ }
458
+
440
459
  interface SpreadAttribute extends AST.BaseNode {
441
460
  type: 'SpreadAttribute';
442
461
  argument: AST.Expression;
@@ -471,7 +490,7 @@ declare module 'estree' {
471
490
 
472
491
  export type TSRXStatement = AST.Statement | TSESTree.Statement;
473
492
 
474
- export type NodeWithChildren = AST.Element | AST.Tsx | AST.TsxCompat;
493
+ export type NodeWithChildren = AST.Element | AST.Tsx | AST.Tsrx | AST.TsxCompat;
475
494
 
476
495
  export namespace CSS {
477
496
  export interface BaseNode extends AST.NodeWithMaybeComments {
@@ -36,6 +36,8 @@ export interface JsxTransformContext {
36
36
  needs_error_boundary: boolean;
37
37
  needs_suspense: boolean;
38
38
  needs_merge_refs: boolean;
39
+ needs_ref_prop: boolean;
40
+ needs_normalize_spread_props: boolean;
39
41
  needs_fragment: boolean;
40
42
  module_scoped_hook_components: boolean;
41
43
  helper_state: {
@@ -290,9 +292,14 @@ export interface JsxPlatform {
290
292
  * Module to import `mergeRefs` from when an element has more than one
291
293
  * `ref` attribute and the platform uses the `'merge-refs'` strategy.
292
294
  * Required when `jsx.multiRefStrategy === 'merge-refs'`; ignored
293
- * otherwise. React: `'@tsrx/react/merge-refs'`. Preact: `'@tsrx/preact/merge-refs'`.
295
+ * otherwise. React: `'@tsrx/react/ref'`. Preact: `'@tsrx/preact/ref'`.
294
296
  */
295
297
  mergeRefs?: string;
298
+ /**
299
+ * Module to import named-ref-prop helpers from when compiling
300
+ * `prop={ref expr}` or normalizing host spreads containing named refs.
301
+ */
302
+ refProp?: string;
296
303
  };
297
304
 
298
305
  jsx: {
@@ -320,6 +327,12 @@ export interface JsxPlatform {
320
327
  * unchanged. The platform's runtime is responsible.
321
328
  */
322
329
  multiRefStrategy?: 'merge-refs' | 'array';
330
+ /**
331
+ * Some JSX runtimes do not apply a `ref` that arrives through a props
332
+ * spread. In that case, host spread normalization also emits an
333
+ * explicit `ref={normalized.ref}` attribute.
334
+ */
335
+ hostSpreadRefStrategy?: 'explicit-ref-attr';
323
336
  };
324
337
 
325
338
  validation: {
package/types/parse.d.ts CHANGED
@@ -1172,7 +1172,7 @@ export namespace Parse {
1172
1172
  */
1173
1173
  parseTopLevel(node: AST.Program): AST.Program;
1174
1174
 
1175
- parseElement(): AST.Element | AST.Tsx | AST.TsxCompat;
1175
+ parseElement(): AST.Element | AST.Tsx | AST.Tsrx | AST.TsxCompat;
1176
1176
 
1177
1177
  parseDoubleQuotedTextChild(): AST.TextNode;
1178
1178
 
@@ -0,0 +1,32 @@
1
+ export type MergeableRefCallback<T> = {
2
+ bivarianceHack(node: T | null): void | (() => void);
3
+ }['bivarianceHack'];
4
+ export type MergeableRefObject<T> = { current: T | null };
5
+ export type MergeableVueRef<T> = { value: T | null };
6
+ export type RefProp<T = unknown> = (node: T | null) => void | (() => void);
7
+
8
+ export type MergeableRef<T> =
9
+ | MergeableRefCallback<T>
10
+ | MergeableRefObject<T>
11
+ | MergeableVueRef<T>
12
+ | null
13
+ | undefined;
14
+
15
+ export function mergeRefs<T = any>(...refs: Array<MergeableRef<T>>): (node: T | null) => () => void;
16
+ export function isRefProp(value: unknown): boolean;
17
+ export function create_ref_prop<T>(
18
+ get_ref_value: () => T,
19
+ set_ref_value?: (value: T) => void,
20
+ ): RefProp<T>;
21
+ export function apply_ref_value<T>(
22
+ ref_value: unknown,
23
+ node: T | null,
24
+ set_ref_value?: (value: T) => void,
25
+ ): void | (() => void);
26
+ export function merge_ref_props<T = any>(
27
+ ...refs: unknown[]
28
+ ): undefined | ((node: T | null) => void | (() => void));
29
+ export function normalize_spread_props<T extends Record<PropertyKey, any> | null | undefined>(
30
+ props: T,
31
+ ...outer_refs: unknown[]
32
+ ): T | Record<PropertyKey, any>;
@@ -1,61 +0,0 @@
1
- /**
2
- * Merge multiple refs (function refs and ref objects) into a single
3
- * callback ref. Used by the tsrx-react, tsrx-preact, and tsrx-vue
4
- * compilers when an element has more than one `ref` attribute, since
5
- * those runtimes treat duplicate `ref` props as a regular duplicate-prop
6
- * collision (last wins) rather than running both. Solid does not use this
7
- * helper — its native runtime accepts an array of refs and the compiler
8
- * emits an array literal directly.
9
- *
10
- * The returned callback ref handles four cases per input:
11
- * - `null` / `undefined`: skipped.
12
- * - function ref: invoked with the node. If it returns a function, that
13
- * return value is treated as a React 19 cleanup. Otherwise we record a
14
- * cleanup that calls the ref with `null` so the legacy unmount contract
15
- * still fires.
16
- * - React-style ref object (`{ current }`): assigned on mount, cleared
17
- * on unmount.
18
- * - Vue-style ref object (`{ value }`, e.g. `ref()` / `useTemplateRef()`):
19
- * assigned on mount, cleared on unmount.
20
- *
21
- * The merged ref always returns a cleanup. Under React 19 the cleanup
22
- * runs on unmount and the inner refs are not separately re-invoked with
23
- * `null`. Under older React, Preact, and Vue the cleanup return value
24
- * is ignored, so the runtime instead invokes the merged ref a second
25
- * time with `null` — which re-runs the loop body, calling each inner
26
- * with `null` and clearing each ref object. Either way every inner ref
27
- * sees a balanced mount/unmount.
28
- *
29
- * @param {...((node: any) => void | (() => void)) | { current: any } | { value: any } | null | undefined} refs
30
- * @returns {(node: any) => (() => void)}
31
- */
32
- export function mergeRefs(...refs) {
33
- return (node) => {
34
- /** @type {Array<() => void>} */
35
- const cleanups = [];
36
- for (const ref of refs) {
37
- if (ref == null) continue;
38
- if (typeof ref === 'function') {
39
- const result = ref(node);
40
- if (typeof result === 'function') {
41
- cleanups.push(result);
42
- } else {
43
- cleanups.push(() => ref(null));
44
- }
45
- } else if ('current' in ref) {
46
- ref.current = node;
47
- cleanups.push(() => {
48
- ref.current = null;
49
- });
50
- } else if ('value' in ref) {
51
- ref.value = node;
52
- cleanups.push(() => {
53
- ref.value = null;
54
- });
55
- }
56
- }
57
- return () => {
58
- for (const cleanup of cleanups) cleanup();
59
- };
60
- };
61
- }
@@ -1,12 +0,0 @@
1
- export type MergeableRefCallback<T> = (node: T | null) => void | (() => void);
2
- export type MergeableRefObject<T> = { current: T | null };
3
- export type MergeableVueRef<T> = { value: T | null };
4
-
5
- export type MergeableRef<T> =
6
- | MergeableRefCallback<T>
7
- | MergeableRefObject<T>
8
- | MergeableVueRef<T>
9
- | null
10
- | undefined;
11
-
12
- export function mergeRefs<T = any>(...refs: Array<MergeableRef<T>>): (node: T | null) => () => void;