@tsrx/core 0.1.46 → 0.1.48
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 +1 -1
- package/src/index.js +3 -2
- package/src/parse/index.js +3 -2
- package/src/plugin.js +110 -26
- package/src/transform/imports.js +96 -0
- package/src/transform/jsx/ast-builders.js +131 -110
- package/src/transform/jsx/helpers.js +77 -81
- package/src/transform/jsx/index.js +342 -360
- package/src/transform/lazy.js +5 -5
- package/src/transform/segments.js +29 -28
- package/src/transform/style-ref.js +9 -13
- package/src/utils/ast.js +11 -0
- package/src/utils/builders.js +3 -3
- package/types/index.d.ts +95 -12
- package/types/jsx-platform.d.ts +88 -54
- package/types/parse.d.ts +64 -4
package/types/jsx-platform.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type * as AST from 'estree';
|
|
2
|
+
import type * as ESTreeJSX from 'estree-jsx';
|
|
2
3
|
import type { RawSourceMap } from 'source-map';
|
|
3
|
-
import type { CompileError } from './index';
|
|
4
|
+
import type { CompileError, JsxHelperComponent } from './index';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Result returned by a JSX platform transform (React, Preact, Solid).
|
|
@@ -25,10 +26,8 @@ export interface JsxTransformResult {
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* extend this with their own `needs_*` flags via `hooks.initialState`; helpers
|
|
31
|
-
* defined in `@tsrx/core` only ever rely on these base fields.
|
|
29
|
+
* Per-call transform context that the JSX factory passes into every visitor
|
|
30
|
+
* and platform hook.
|
|
32
31
|
*/
|
|
33
32
|
export interface JsxTransformContext {
|
|
34
33
|
platform: JsxPlatform;
|
|
@@ -43,14 +42,22 @@ export interface JsxTransformContext {
|
|
|
43
42
|
needs_dynamic_factory: boolean;
|
|
44
43
|
needs_for_of_iterable: boolean;
|
|
45
44
|
needs_iteration_value_type: boolean;
|
|
45
|
+
needs_show: boolean;
|
|
46
|
+
needs_for: boolean;
|
|
47
|
+
needs_switch: boolean;
|
|
48
|
+
needs_match: boolean;
|
|
49
|
+
needs_errored: boolean;
|
|
50
|
+
needs_loading: boolean;
|
|
51
|
+
needs_define_vapor_component: boolean;
|
|
52
|
+
needs_vapor_for: boolean;
|
|
46
53
|
stylesheets: AST.CSS.StyleSheet[];
|
|
47
54
|
type_only_style_anchors: AST.Statement[];
|
|
48
55
|
module_scoped_hook_components: boolean;
|
|
49
56
|
helper_state: {
|
|
50
57
|
base_name: string;
|
|
51
58
|
next_id: number;
|
|
52
|
-
helpers:
|
|
53
|
-
statics:
|
|
59
|
+
helpers: AST.Statement[];
|
|
60
|
+
statics: AST.Statement[];
|
|
54
61
|
} | null;
|
|
55
62
|
hook_helpers_enabled: boolean;
|
|
56
63
|
available_bindings: Map<string, AST.Identifier>;
|
|
@@ -138,10 +145,13 @@ export interface JsxPlatformHooks {
|
|
|
138
145
|
* child (or an expression container wrapping one).
|
|
139
146
|
*/
|
|
140
147
|
controlFlow?: {
|
|
141
|
-
ifStatement?: (node:
|
|
142
|
-
forOf?: (node:
|
|
143
|
-
switchStatement?: (
|
|
144
|
-
|
|
148
|
+
ifStatement?: (node: AST.IfStatement, ctx: JsxTransformContext) => ESTreeJSX.JSXRenderNode;
|
|
149
|
+
forOf?: (node: AST.ForOfStatement, ctx: JsxTransformContext) => ESTreeJSX.JSXRenderNode;
|
|
150
|
+
switchStatement?: (
|
|
151
|
+
node: AST.SwitchStatement,
|
|
152
|
+
ctx: JsxTransformContext,
|
|
153
|
+
) => ESTreeJSX.JSXRenderNode;
|
|
154
|
+
tryStatement?: (node: AST.TryStatement, ctx: JsxTransformContext) => ESTreeJSX.JSXRenderNode;
|
|
145
155
|
};
|
|
146
156
|
/**
|
|
147
157
|
* Mark a top-level call expression inside a control-flow branch as requiring
|
|
@@ -149,14 +159,19 @@ export interface JsxPlatformHooks {
|
|
|
149
159
|
* branch instead of once per parent rerender. Vue uses this for branch-local
|
|
150
160
|
* Composition API state like `ref()`.
|
|
151
161
|
*/
|
|
152
|
-
isTopLevelSetupCall?: (callExpression:
|
|
162
|
+
isTopLevelSetupCall?: (callExpression: AST.CallExpression, ctx: JsxTransformContext) => boolean;
|
|
153
163
|
/**
|
|
154
164
|
* Wrap a hoisted helper component declaration emitted by the shared control-
|
|
155
165
|
* flow splitter. The default is the plain function declaration; Vue uses
|
|
156
166
|
* this to wrap helpers in `defineVaporComponent(...)` so branch-local setup
|
|
157
167
|
* state behaves like normal component state.
|
|
158
168
|
*/
|
|
159
|
-
wrapHelperComponent?: (
|
|
169
|
+
wrapHelperComponent?: (
|
|
170
|
+
helperFn: AST.FunctionDeclaration,
|
|
171
|
+
helperId: AST.Identifier,
|
|
172
|
+
ctx: JsxTransformContext,
|
|
173
|
+
sourceNode: AST.NodeWithLocation | undefined,
|
|
174
|
+
) => AST.Statement;
|
|
160
175
|
/**
|
|
161
176
|
* Emit hook-isolation helper components as unique module-scope declarations
|
|
162
177
|
* instead of lazily creating and caching them from the parent component body.
|
|
@@ -171,27 +186,38 @@ export interface JsxPlatformHooks {
|
|
|
171
186
|
* Solid injects `Show`, `For`, `Switch`, `Match`, `Errored`, `Loading`
|
|
172
187
|
* from `solid-js`.
|
|
173
188
|
*/
|
|
174
|
-
injectImports?: (program: AST.Program, ctx:
|
|
189
|
+
injectImports?: (program: AST.Program, ctx: JsxTransformContext, suspenseSource: string) => void;
|
|
175
190
|
/**
|
|
176
|
-
* Transform a Ripple element's
|
|
177
|
-
* is
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
* it — and run their own attribute pass inside their `transformElement`.
|
|
191
|
+
* Transform a Ripple element's parser-native JSX attributes. The result
|
|
192
|
+
* is passed through the shared multi-`ref` merge. Platforms that own a
|
|
193
|
+
* `transformElement` hook (e.g. Solid) run their own attribute pass inside
|
|
194
|
+
* that hook.
|
|
181
195
|
*/
|
|
182
|
-
transformElementAttributes?: (
|
|
196
|
+
transformElementAttributes?: (
|
|
197
|
+
attrs: ESTreeJSX.JSXAttributeNode[],
|
|
198
|
+
ctx: JsxTransformContext,
|
|
199
|
+
element: AST.TSRXJSXElement,
|
|
200
|
+
) => ESTreeJSX.JSXAttributeNode[];
|
|
183
201
|
/**
|
|
184
|
-
* Rewrite
|
|
185
|
-
* `to_jsx_attribute()` mapping runs.
|
|
202
|
+
* Rewrite parser-native JSX attributes before platform transformation.
|
|
186
203
|
*/
|
|
187
|
-
preprocessElementAttributes?: (
|
|
204
|
+
preprocessElementAttributes?: (
|
|
205
|
+
attrs: ESTreeJSX.JSXAttributeNode[],
|
|
206
|
+
ctx: JsxTransformContext,
|
|
207
|
+
element: AST.TSRXJSXElement,
|
|
208
|
+
) => ESTreeJSX.JSXAttributeNode[];
|
|
188
209
|
/**
|
|
189
210
|
* Optionally replace the default React-style `.map(...)` lowering for a
|
|
190
211
|
* `for...of` body after the shared transform has already produced its render
|
|
191
212
|
* statements and applied any explicit or implicit keys. Vue uses this to hand
|
|
192
213
|
* the loop to the downstream Vapor JSX compiler as a typed `VaporFor` component.
|
|
193
214
|
*/
|
|
194
|
-
renderForOf?: (
|
|
215
|
+
renderForOf?: (
|
|
216
|
+
node: AST.ForOfStatement,
|
|
217
|
+
loopParams: AST.Pattern[],
|
|
218
|
+
bodyStatements: AST.Statement[],
|
|
219
|
+
ctx: JsxTransformContext,
|
|
220
|
+
) => ESTreeJSX.JSXExpressionContainer | null;
|
|
195
221
|
/**
|
|
196
222
|
* Optionally replace the default React-style pending lowering for
|
|
197
223
|
* `@try { ... } @pending { ... }`. The default emits
|
|
@@ -200,35 +226,35 @@ export interface JsxPlatformHooks {
|
|
|
200
226
|
* `v-slots`.
|
|
201
227
|
*/
|
|
202
228
|
createPendingBoundary?: (
|
|
203
|
-
tryContent:
|
|
204
|
-
fallbackContent:
|
|
205
|
-
ctx:
|
|
206
|
-
node:
|
|
207
|
-
) =>
|
|
229
|
+
tryContent: ESTreeJSX.JSXRenderNode,
|
|
230
|
+
fallbackContent: ESTreeJSX.JSXRenderNode,
|
|
231
|
+
ctx: JsxTransformContext,
|
|
232
|
+
node: AST.TryStatement,
|
|
233
|
+
) => ESTreeJSX.JSXRenderNode | null;
|
|
208
234
|
/**
|
|
209
235
|
* Optionally create a generated component for a catch fallback body while
|
|
210
236
|
* the catch parameters are still in scope. Platforms can use this to reuse
|
|
211
237
|
* one mapped catch-body component from multiple runtime catch sites.
|
|
212
238
|
*/
|
|
213
239
|
createErrorFallbackComponent?: (
|
|
214
|
-
catchBodyNodes:
|
|
215
|
-
catchParams:
|
|
216
|
-
ctx:
|
|
217
|
-
node:
|
|
218
|
-
) =>
|
|
240
|
+
catchBodyNodes: AST.Statement[],
|
|
241
|
+
catchParams: AST.Pattern[],
|
|
242
|
+
ctx: JsxTransformContext,
|
|
243
|
+
node: AST.TryStatement,
|
|
244
|
+
) => JsxHelperComponent | null;
|
|
219
245
|
/**
|
|
220
246
|
* Optionally replace the default `try/catch` boundary wrapper. The hook
|
|
221
247
|
* receives the current render content, the original try-body content before
|
|
222
248
|
* any pending wrapper, and the generated catch fallback function.
|
|
223
249
|
*/
|
|
224
250
|
createErrorBoundary?: (
|
|
225
|
-
tryContent:
|
|
226
|
-
rawTryContent:
|
|
227
|
-
fallbackFn:
|
|
228
|
-
ctx:
|
|
229
|
-
node:
|
|
230
|
-
info?: { fallbackComponent?:
|
|
231
|
-
) =>
|
|
251
|
+
tryContent: ESTreeJSX.JSXRenderNode,
|
|
252
|
+
rawTryContent: ESTreeJSX.JSXRenderNode,
|
|
253
|
+
fallbackFn: AST.ArrowFunctionExpression,
|
|
254
|
+
ctx: JsxTransformContext,
|
|
255
|
+
node: AST.TryStatement,
|
|
256
|
+
info?: { fallbackComponent?: JsxHelperComponent | null },
|
|
257
|
+
) => ESTreeJSX.JSXRenderNode | null;
|
|
232
258
|
/**
|
|
233
259
|
* Optionally move the primary `try { ... }` render content into an explicit
|
|
234
260
|
* error-boundary prop instead of rendering it as the boundary's JSX children.
|
|
@@ -236,7 +262,11 @@ export interface JsxPlatformHooks {
|
|
|
236
262
|
* zero-argument function. If a `pending` block exists, `tryContent` is the
|
|
237
263
|
* already-created pending boundary so catch wrappers still enclose it.
|
|
238
264
|
*/
|
|
239
|
-
createErrorBoundaryContent?: (
|
|
265
|
+
createErrorBoundaryContent?: (
|
|
266
|
+
tryContent: ESTreeJSX.JSXRenderNode,
|
|
267
|
+
ctx: JsxTransformContext,
|
|
268
|
+
node: AST.TryStatement,
|
|
269
|
+
) => AST.Expression | null;
|
|
240
270
|
/**
|
|
241
271
|
* Customize lowering for a native JSX element. Default is the
|
|
242
272
|
* factory's `to_jsx_element`. The hook receives the walker-transformed
|
|
@@ -245,7 +275,11 @@ export interface JsxPlatformHooks {
|
|
|
245
275
|
* `JSXText` child it can hoist to a `textContent` attribute before the
|
|
246
276
|
* generic text→JSXExpressionContainer transform runs.
|
|
247
277
|
*/
|
|
248
|
-
transformElement?: (
|
|
278
|
+
transformElement?: (
|
|
279
|
+
inner: AST.TSRXJSXElement,
|
|
280
|
+
ctx: JsxTransformContext,
|
|
281
|
+
rawChildren: AST.Node[],
|
|
282
|
+
) => ESTreeJSX.JSXRenderNode;
|
|
249
283
|
/**
|
|
250
284
|
* Optionally rewrite a host element's children into attributes or another
|
|
251
285
|
* specialized child shape after generic attribute lowering but before the
|
|
@@ -258,27 +292,27 @@ export interface JsxPlatformHooks {
|
|
|
258
292
|
* back to the default child handling.
|
|
259
293
|
*/
|
|
260
294
|
transformElementChildren?: (
|
|
261
|
-
element:
|
|
262
|
-
walkedChildren:
|
|
263
|
-
rawChildren:
|
|
264
|
-
attrs:
|
|
265
|
-
ctx:
|
|
266
|
-
) => { children:
|
|
295
|
+
element: AST.TSRXJSXElement,
|
|
296
|
+
walkedChildren: AST.Node[],
|
|
297
|
+
rawChildren: AST.Node[],
|
|
298
|
+
attrs: ESTreeJSX.JSXAttributeNode[],
|
|
299
|
+
ctx: JsxTransformContext,
|
|
300
|
+
) => { children: ESTreeJSX.JSXElement['children']; selfClosing?: boolean } | null;
|
|
267
301
|
/**
|
|
268
302
|
* Decide whether a JSX subtree may be hoisted to module scope when it is
|
|
269
303
|
* otherwise statically safe. Targets can use this to keep runtime-sensitive
|
|
270
304
|
* JSX, such as component invocations, inside render/setup execution.
|
|
271
305
|
*/
|
|
272
|
-
canHoistStaticNode?: (node:
|
|
306
|
+
canHoistStaticNode?: (node: ESTreeJSX.JSXElement, ctx: JsxTransformContext) => boolean;
|
|
273
307
|
/**
|
|
274
308
|
* Custom validation for a component body that uses top-level `await`.
|
|
275
309
|
* Default: enforce `validation.requireUseServerForAwait`. Solid rejects
|
|
276
310
|
* component-level await outright with a keyword-precise location.
|
|
277
311
|
*/
|
|
278
312
|
validateComponentAwait?: (
|
|
279
|
-
awaitNode:
|
|
280
|
-
component:
|
|
281
|
-
ctx:
|
|
313
|
+
awaitNode: AST.TSRXAwaitNode,
|
|
314
|
+
component: AST.Function,
|
|
315
|
+
ctx: JsxTransformContext,
|
|
282
316
|
moduleUsesServerDirective: boolean,
|
|
283
317
|
source: string,
|
|
284
318
|
) => void;
|
|
@@ -287,7 +321,7 @@ export interface JsxPlatformHooks {
|
|
|
287
321
|
* initial `transform_context`. Lets solid seed its `needs_show` /
|
|
288
322
|
* `needs_for` / etc. flags without forking the factory.
|
|
289
323
|
*/
|
|
290
|
-
initialState?: () =>
|
|
324
|
+
initialState?: () => Partial<JsxTransformContext>;
|
|
291
325
|
}
|
|
292
326
|
|
|
293
327
|
/**
|
package/types/parse.d.ts
CHANGED
|
@@ -420,6 +420,8 @@ export namespace Parse {
|
|
|
420
420
|
export interface AcornTypeScriptExtensions {
|
|
421
421
|
tokTypes: AcornTypeScriptTokTypes;
|
|
422
422
|
tokContexts: AcornTypeScriptTokContexts;
|
|
423
|
+
/** Whether a token type can start/continue an identifier (incl. TS soft keywords) */
|
|
424
|
+
tokenIsIdentifier(token: TokenType): boolean;
|
|
423
425
|
}
|
|
424
426
|
|
|
425
427
|
export interface AcornTypeScriptFunctionBodyConfig {
|
|
@@ -427,6 +429,31 @@ export namespace Parse {
|
|
|
427
429
|
isClassMethod?: boolean;
|
|
428
430
|
}
|
|
429
431
|
|
|
432
|
+
/**
|
|
433
|
+
* Snapshot of tokenizer state returned by `lookahead()`, mirroring
|
|
434
|
+
* @sveltejs/acorn-typescript's saved lookahead state. Callers inspect the
|
|
435
|
+
* upcoming token (`type`/`value`/`start`/`containsEsc`) without consuming it,
|
|
436
|
+
* and pass the snapshot to the `*WithState` contextual helpers.
|
|
437
|
+
*/
|
|
438
|
+
export interface LookaheadState {
|
|
439
|
+
pos: number;
|
|
440
|
+
type: TokenType;
|
|
441
|
+
value: string | number | RegExp | bigint | null;
|
|
442
|
+
start: number;
|
|
443
|
+
end: number;
|
|
444
|
+
startLoc: AST.Position;
|
|
445
|
+
endLoc: AST.Position;
|
|
446
|
+
lastTokEnd: number;
|
|
447
|
+
lastTokStart: number;
|
|
448
|
+
lastTokStartLoc: AST.Position;
|
|
449
|
+
lastTokEndLoc: AST.Position;
|
|
450
|
+
context: TokContext[];
|
|
451
|
+
curLine: number;
|
|
452
|
+
lineStart: number;
|
|
453
|
+
curPosition: () => AST.Position;
|
|
454
|
+
containsEsc: boolean;
|
|
455
|
+
}
|
|
456
|
+
|
|
430
457
|
interface Scope {
|
|
431
458
|
flags: number;
|
|
432
459
|
var: string[];
|
|
@@ -496,6 +523,11 @@ export namespace Parse {
|
|
|
496
523
|
inFunction: boolean;
|
|
497
524
|
/** Whether @sveltejs/acorn-typescript is currently parsing a TypeScript type */
|
|
498
525
|
inType: boolean;
|
|
526
|
+
/**
|
|
527
|
+
* `value`/`type` kind of the import or export declaration currently being
|
|
528
|
+
* parsed (@sveltejs/acorn-typescript). `undefined` when not inside one.
|
|
529
|
+
*/
|
|
530
|
+
importOrExportOuterKind?: 'value' | 'type';
|
|
499
531
|
/** Stack of label names for break/continue statements */
|
|
500
532
|
labels: Array<{ kind: string | null; name?: string; statementStart?: number }>;
|
|
501
533
|
/** Current scope flags stack */
|
|
@@ -756,6 +788,23 @@ export namespace Parse {
|
|
|
756
788
|
*/
|
|
757
789
|
expectContextual(name: string): void;
|
|
758
790
|
|
|
791
|
+
/**
|
|
792
|
+
* Like `isContextual`, but tests a `lookahead()` snapshot instead of the
|
|
793
|
+
* current token (@sveltejs/acorn-typescript).
|
|
794
|
+
* @param keyword Keyword to check (e.g. "from", "defer")
|
|
795
|
+
* @param state Lookahead snapshot to test
|
|
796
|
+
*/
|
|
797
|
+
isContextualWithState(keyword: string, state: LookaheadState): boolean;
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* If `state` is the contextual keyword `name`, consume `nextCount` tokens
|
|
801
|
+
* and return true (@sveltejs/acorn-typescript).
|
|
802
|
+
* @param name Contextual keyword to eat (e.g. "type", "defer")
|
|
803
|
+
* @param nextCount Number of tokens to advance when it matches
|
|
804
|
+
* @param state Lookahead snapshot to test
|
|
805
|
+
*/
|
|
806
|
+
ts_eatContextualWithState(name: string, nextCount: number, state: LookaheadState): boolean;
|
|
807
|
+
|
|
759
808
|
/**
|
|
760
809
|
* Check if semicolon can be inserted at current position (ASI)
|
|
761
810
|
*/
|
|
@@ -831,10 +880,11 @@ export namespace Parse {
|
|
|
831
880
|
// Lookahead
|
|
832
881
|
// ============================================================
|
|
833
882
|
/**
|
|
834
|
-
* Look ahead
|
|
835
|
-
*
|
|
883
|
+
* Look ahead `number` tokens (default 1) without consuming, returning a
|
|
884
|
+
* snapshot of the tokenizer state at that position.
|
|
885
|
+
* @param number How many tokens to look ahead (default 1)
|
|
836
886
|
*/
|
|
837
|
-
lookahead():
|
|
887
|
+
lookahead(number?: number): LookaheadState;
|
|
838
888
|
|
|
839
889
|
/**
|
|
840
890
|
* Get next token start position
|
|
@@ -1461,7 +1511,17 @@ export namespace Parse {
|
|
|
1461
1511
|
// Module Parsing (Import/Export)
|
|
1462
1512
|
// ============================================================
|
|
1463
1513
|
/** Parse import declaration */
|
|
1464
|
-
parseImport(node: AST.
|
|
1514
|
+
parseImport(node: AST.TSRXImportDeclaration): AST.TSRXImportDeclaration;
|
|
1515
|
+
|
|
1516
|
+
/**
|
|
1517
|
+
* Parse a TypeScript import-equals declaration, `import x = require('y')`
|
|
1518
|
+
* or `import x = A.B` (@sveltejs/acorn-typescript). Typed as
|
|
1519
|
+
* `ImportDeclaration` because estree has no `TSImportEqualsDeclaration`.
|
|
1520
|
+
*/
|
|
1521
|
+
tsParseImportEqualsDeclaration(node: AST.Node, isExport?: boolean): AST.ImportDeclaration;
|
|
1522
|
+
|
|
1523
|
+
/** Parse an optional import-attributes clause (`with { … }` / `assert { … }`) */
|
|
1524
|
+
parseMaybeImportAttributes(node: AST.Node): void;
|
|
1465
1525
|
|
|
1466
1526
|
/** Parse import specifiers */
|
|
1467
1527
|
parseImportSpecifiers(): AST.ImportSpecifier[];
|