@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.
- package/package.json +5 -4
- package/src/index.js +6 -0
- package/src/plugin.js +131 -25
- package/src/runtime/language-helpers.js +57 -0
- package/src/runtime/ref.js +250 -0
- package/src/scope.js +7 -0
- package/src/transform/jsx/ast-builders.js +14 -13
- package/src/transform/jsx/index.js +490 -55
- package/src/transform/segments.js +19 -9
- package/types/index.d.ts +20 -1
- package/types/jsx-platform.d.ts +14 -1
- package/types/parse.d.ts +1 -1
- package/types/runtime/ref.d.ts +32 -0
- package/src/runtime/merge-refs.js +0 -61
- package/types/runtime/merge-refs.d.ts +0 -12
|
@@ -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
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
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 {
|
package/types/jsx-platform.d.ts
CHANGED
|
@@ -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/
|
|
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;
|