@tsrx/core 0.1.15 → 0.1.17
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/README.md +4 -3
- package/package.json +1 -1
- package/src/analyze/prune.js +13 -28
- package/src/analyze/validation.js +27 -94
- package/src/diagnostics.js +1 -3
- package/src/index.js +18 -28
- package/src/parse/index.js +37 -4
- package/src/plugin.js +248 -635
- package/src/runtime/ref.js +48 -0
- package/src/scope.js +0 -13
- package/src/transform/await.js +1 -1
- package/src/transform/jsx/ast-builders.js +3 -5
- package/src/transform/jsx/helpers.js +1 -2
- package/src/transform/jsx/index.js +1257 -1491
- package/src/transform/lazy.js +6 -6
- package/src/transform/scoping.js +1 -2
- package/src/transform/segments.js +26 -157
- package/src/transform/style-ref.js +235 -0
- package/src/utils/ast.js +15 -23
- package/src/utils/builders.js +0 -18
- package/types/index.d.ts +32 -74
- package/types/jsx-platform.d.ts +20 -28
- package/types/parse.d.ts +2 -15
- package/types/runtime/ref.d.ts +3 -0
package/README.md
CHANGED
|
@@ -41,8 +41,9 @@ The TSRX website is the canonical source for language documentation:
|
|
|
41
41
|
|
|
42
42
|
- [Getting Started](https://tsrx.dev/getting-started) — install TSRX for React,
|
|
43
43
|
Preact, Solid, Vue, or Ripple and configure editor/AI tooling.
|
|
44
|
-
- [Features](https://tsrx.dev/features) — examples of components,
|
|
45
|
-
templates, control flow, scoped styles, submodules, and lazy
|
|
44
|
+
- [Features](https://tsrx.dev/features) — examples of function components,
|
|
45
|
+
statement templates, control flow, scoped styles, submodules, and lazy
|
|
46
|
+
destructuring.
|
|
46
47
|
- [Specification](https://tsrx.dev/specification) — the current grammar and
|
|
47
48
|
parser-level semantics.
|
|
48
49
|
|
|
@@ -54,7 +55,7 @@ here and keeps package docs focused on the core parser API.
|
|
|
54
55
|
- **`parseModule(source, filename, options?)`** — parse a TSRX module into an
|
|
55
56
|
ESTree AST.
|
|
56
57
|
- **Scope analysis** — `createScopes`, `Scope`, `ScopeRoot`, binding tracking
|
|
57
|
-
(`import`, `prop`, `let`, `const`, `function`, `
|
|
58
|
+
(`import`, `prop`, `let`, `const`, `function`, `for_pattern`, …).
|
|
58
59
|
- **AST utilities** — pattern walkers, identifier extraction, builders, location
|
|
59
60
|
helpers, obfuscation helpers.
|
|
60
61
|
- **CSS support** — `parseStyle`, `analyzeCss`, `renderStylesheets`.
|
package/package.json
CHANGED
package/src/analyze/prune.js
CHANGED
|
@@ -323,26 +323,14 @@ function get_descendant_elements(node, adjacent_only) {
|
|
|
323
323
|
}
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
-
if (/** @type {AST.Component} */ (current_node).body) {
|
|
327
|
-
for (const child of /** @type {AST.Component} */ (current_node).body) {
|
|
328
|
-
visit(child, depth + 1);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
326
|
// For template nodes and interpolation expressions
|
|
333
327
|
if (
|
|
334
|
-
(current_node.type === 'TSRXExpression' ||
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
typeof (
|
|
339
|
-
/** @type {AST.TSRXExpression | AST.Html | AST.TextNode} */ (current_node).expression
|
|
340
|
-
) === 'object'
|
|
328
|
+
(current_node.type === 'TSRXExpression' || current_node.type === 'Text') &&
|
|
329
|
+
/** @type {AST.TSRXExpression | AST.TextNode} */ (current_node).expression &&
|
|
330
|
+
typeof (/** @type {AST.TSRXExpression | AST.TextNode} */ (current_node).expression) ===
|
|
331
|
+
'object'
|
|
341
332
|
) {
|
|
342
|
-
visit(
|
|
343
|
-
/** @type {AST.TSRXExpression | AST.Html | AST.TextNode} */ (current_node).expression,
|
|
344
|
-
depth + 1,
|
|
345
|
-
);
|
|
333
|
+
visit(/** @type {AST.TSRXExpression | AST.TextNode} */ (current_node).expression, depth + 1);
|
|
346
334
|
}
|
|
347
335
|
}
|
|
348
336
|
|
|
@@ -399,7 +387,6 @@ function can_render_dynamic_content(element, check_classes = false) {
|
|
|
399
387
|
*/
|
|
400
388
|
function get_possible_element_siblings(node, direction, adjacent_only) {
|
|
401
389
|
const siblings = new Map();
|
|
402
|
-
// Parent has to be an Element not a Component
|
|
403
390
|
const parent = get_element_parent(node);
|
|
404
391
|
|
|
405
392
|
if (!parent) {
|
|
@@ -428,9 +415,9 @@ function get_possible_element_siblings(node, direction, adjacent_only) {
|
|
|
428
415
|
for (let i = start; i !== end; i += step) {
|
|
429
416
|
const sibling = container[i];
|
|
430
417
|
|
|
431
|
-
if (sibling.type === 'Element'
|
|
418
|
+
if (sibling.type === 'Element') {
|
|
432
419
|
siblings.set(sibling, true);
|
|
433
|
-
// Don't break for dynamic elements (children
|
|
420
|
+
// Don't break for dynamic elements (children and dynamic components)
|
|
434
421
|
// as they can render dynamic content or might render nothing
|
|
435
422
|
const isDynamic = can_render_dynamic_content(sibling, false);
|
|
436
423
|
if (adjacent_only && !isDynamic) {
|
|
@@ -534,12 +521,6 @@ function apply_combinator(relative_selector, rest_selectors, rule, node, directi
|
|
|
534
521
|
break;
|
|
535
522
|
}
|
|
536
523
|
if (combinator.name === '+') break; // For adjacent, only check first element
|
|
537
|
-
} else if (subsequent.type === 'Component') {
|
|
538
|
-
// Skip components when looking for the target element
|
|
539
|
-
if (combinator.name === '+') {
|
|
540
|
-
// For adjacent, continue looking
|
|
541
|
-
continue;
|
|
542
|
-
}
|
|
543
524
|
}
|
|
544
525
|
}
|
|
545
526
|
}
|
|
@@ -987,6 +968,10 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element,
|
|
|
987
968
|
}
|
|
988
969
|
|
|
989
970
|
case 'TypeSelector': {
|
|
971
|
+
if (is_element_dynamic(/** @type {AST.Element} */ (element))) {
|
|
972
|
+
break;
|
|
973
|
+
}
|
|
974
|
+
|
|
990
975
|
if (
|
|
991
976
|
element.id.type === 'Identifier' &&
|
|
992
977
|
element.id.name.toLowerCase() !== name.toLowerCase() &&
|
|
@@ -1106,11 +1091,11 @@ export function prune_css(css, element, styleClasses, topScopedClasses) {
|
|
|
1106
1091
|
node.metadata.used = true;
|
|
1107
1092
|
}
|
|
1108
1093
|
|
|
1109
|
-
// Populate top_scoped_classes for truly standalone class selectors
|
|
1094
|
+
// Populate top_scoped_classes for truly standalone class selectors.
|
|
1110
1095
|
// A class is standalone only when the entire effective selector chain (after resolving
|
|
1111
1096
|
// nesting and stripping :global) is a single RelativeSelector with a single ClassSelector.
|
|
1112
1097
|
// This prevents classes from compound selectors like `.wrapper .nested` or selectors
|
|
1113
|
-
// inside :global() from being
|
|
1098
|
+
// inside :global() from being exported through style refs.
|
|
1114
1099
|
if (selectors.length === 1) {
|
|
1115
1100
|
const sole_selector = selectors[0];
|
|
1116
1101
|
if (
|
|
@@ -4,25 +4,22 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { error } from '../errors.js';
|
|
7
|
+
import { DIAGNOSTIC_CODES } from '../diagnostics.js';
|
|
7
8
|
|
|
8
|
-
export const
|
|
9
|
-
'Return statements inside
|
|
10
|
-
export const
|
|
11
|
-
'Return statements are not allowed inside
|
|
12
|
-
export const
|
|
13
|
-
'Break statements are not allowed inside
|
|
14
|
-
export const
|
|
15
|
-
'For loops are not supported in
|
|
16
|
-
export const
|
|
17
|
-
'For...in loops are not supported in
|
|
18
|
-
export const
|
|
19
|
-
'While loops are not supported in
|
|
20
|
-
export const
|
|
21
|
-
'Do...while loops are not supported in
|
|
22
|
-
export const CLASS_COMPONENT_AS_NON_ARROW_PROPERTY_ERROR =
|
|
23
|
-
'Components declared inside a class must be defined as an arrow function class property (e.g. `Foo = component() => { ... }`). Non-arrow component property values are not allowed.';
|
|
24
|
-
export const COMPONENT_MULTIPLE_PARAMS_ERROR =
|
|
25
|
-
'Components accept a single props parameter. Move additional inputs into the props object instead.';
|
|
9
|
+
export const TSRX_RETURN_STATEMENT_ERROR =
|
|
10
|
+
'Return statements are not allowed inside TSRX templates. Move the return before the TSRX return value, or use conditional rendering instead.';
|
|
11
|
+
export const TSRX_LOOP_RETURN_ERROR =
|
|
12
|
+
'Return statements are not allowed inside TSRX template for...of loops. Use continue instead.';
|
|
13
|
+
export const TSRX_LOOP_BREAK_ERROR =
|
|
14
|
+
'Break statements are not allowed inside TSRX template for...of loops.';
|
|
15
|
+
export const TSRX_FOR_STATEMENT_ERROR =
|
|
16
|
+
'For loops are not supported in TSRX templates. Use for...of instead.';
|
|
17
|
+
export const TSRX_FOR_IN_STATEMENT_ERROR =
|
|
18
|
+
'For...in loops are not supported in TSRX templates. Use for...of instead.';
|
|
19
|
+
export const TSRX_WHILE_STATEMENT_ERROR =
|
|
20
|
+
'While loops are not supported in TSRX templates. Move the while loop into a function.';
|
|
21
|
+
export const TSRX_DO_WHILE_STATEMENT_ERROR =
|
|
22
|
+
'Do...while loops are not supported in TSRX templates. Move the do...while loop into a function.';
|
|
26
23
|
|
|
27
24
|
const invalid_nestings = {
|
|
28
25
|
// <p> cannot contain block-level elements
|
|
@@ -184,17 +181,14 @@ export function get_statement_keyword_node(node, keyword) {
|
|
|
184
181
|
* @param {CompileError[]} [errors]
|
|
185
182
|
* @param {AST.CommentWithLocation[]} [comments]
|
|
186
183
|
*/
|
|
187
|
-
export function
|
|
188
|
-
if (node.argument === null) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
|
|
184
|
+
export function validate_tsrx_return_statement(node, filename, errors, comments) {
|
|
192
185
|
error(
|
|
193
|
-
|
|
186
|
+
TSRX_RETURN_STATEMENT_ERROR,
|
|
194
187
|
filename ?? null,
|
|
195
188
|
get_return_keyword_node(node),
|
|
196
189
|
errors,
|
|
197
190
|
comments,
|
|
191
|
+
DIAGNOSTIC_CODES.TEMPLATE_RETURN_STATEMENT,
|
|
198
192
|
);
|
|
199
193
|
}
|
|
200
194
|
|
|
@@ -204,14 +198,8 @@ export function validate_component_return_statement(node, filename, errors, comm
|
|
|
204
198
|
* @param {CompileError[]} [errors]
|
|
205
199
|
* @param {AST.CommentWithLocation[]} [comments]
|
|
206
200
|
*/
|
|
207
|
-
export function
|
|
208
|
-
error(
|
|
209
|
-
COMPONENT_LOOP_RETURN_ERROR,
|
|
210
|
-
filename ?? null,
|
|
211
|
-
get_return_keyword_node(node),
|
|
212
|
-
errors,
|
|
213
|
-
comments,
|
|
214
|
-
);
|
|
201
|
+
export function validate_tsrx_loop_return_statement(node, filename, errors, comments) {
|
|
202
|
+
error(TSRX_LOOP_RETURN_ERROR, filename ?? null, get_return_keyword_node(node), errors, comments);
|
|
215
203
|
}
|
|
216
204
|
|
|
217
205
|
/**
|
|
@@ -220,9 +208,9 @@ export function validate_component_loop_return_statement(node, filename, errors,
|
|
|
220
208
|
* @param {CompileError[]} [errors]
|
|
221
209
|
* @param {AST.CommentWithLocation[]} [comments]
|
|
222
210
|
*/
|
|
223
|
-
export function
|
|
211
|
+
export function validate_tsrx_loop_break_statement(node, filename, errors, comments) {
|
|
224
212
|
error(
|
|
225
|
-
|
|
213
|
+
TSRX_LOOP_BREAK_ERROR,
|
|
226
214
|
filename ?? null,
|
|
227
215
|
get_statement_keyword_node(node, 'break'),
|
|
228
216
|
errors,
|
|
@@ -236,76 +224,21 @@ export function validate_component_loop_break_statement(node, filename, errors,
|
|
|
236
224
|
* @param {CompileError[]} [errors]
|
|
237
225
|
* @param {AST.CommentWithLocation[]} [comments]
|
|
238
226
|
*/
|
|
239
|
-
export function
|
|
227
|
+
export function validate_tsrx_unsupported_loop_statement(node, filename, errors, comments) {
|
|
240
228
|
let message;
|
|
241
229
|
if (node.type === 'ForStatement') {
|
|
242
|
-
message =
|
|
230
|
+
message = TSRX_FOR_STATEMENT_ERROR;
|
|
243
231
|
} else if (node.type === 'ForInStatement') {
|
|
244
|
-
message =
|
|
232
|
+
message = TSRX_FOR_IN_STATEMENT_ERROR;
|
|
245
233
|
} else if (node.type === 'WhileStatement') {
|
|
246
|
-
message =
|
|
234
|
+
message = TSRX_WHILE_STATEMENT_ERROR;
|
|
247
235
|
} else {
|
|
248
|
-
message =
|
|
236
|
+
message = TSRX_DO_WHILE_STATEMENT_ERROR;
|
|
249
237
|
}
|
|
250
238
|
|
|
251
239
|
error(message, filename ?? null, node, errors, comments);
|
|
252
240
|
}
|
|
253
241
|
|
|
254
|
-
/**
|
|
255
|
-
* Validates that a component declares at most a single (props) parameter.
|
|
256
|
-
* Components have one slot for props; additional positional parameters are
|
|
257
|
-
* silently dropped or naively passed through depending on the target, so
|
|
258
|
-
* reject them at analysis time. Reports one error per extra parameter so
|
|
259
|
-
* every offending input gets its own TS diagnostic squiggle. In throwing
|
|
260
|
-
* mode the first call raises and aborts before the loop continues.
|
|
261
|
-
*
|
|
262
|
-
* @param {AST.Component} component
|
|
263
|
-
* @param {string | null | undefined} filename
|
|
264
|
-
* @param {CompileError[]} [errors]
|
|
265
|
-
* @param {AST.CommentWithLocation[]} [comments]
|
|
266
|
-
*/
|
|
267
|
-
export function validate_component_params(component, filename, errors, comments) {
|
|
268
|
-
const params = /** @type {AST.Pattern[] | undefined} */ (component.params);
|
|
269
|
-
if (!params || params.length <= 1) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
for (let i = 1; i < params.length; i++) {
|
|
274
|
-
error(COMPONENT_MULTIPLE_PARAMS_ERROR, filename ?? null, params[i], errors, comments);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* Validates that components declared at the top level of a class body use the
|
|
280
|
-
* only allowed form: an arrow function class property (regular or static).
|
|
281
|
-
* Reports an error for non-arrow component property values such as
|
|
282
|
-
* `Foo = component() { ... }`. The method form (`component foo() {}` inside
|
|
283
|
-
* a class body) is rejected at parse time and never reaches this check.
|
|
284
|
-
*
|
|
285
|
-
* @param {AST.ClassBody} class_body
|
|
286
|
-
* @param {string | null | undefined} filename
|
|
287
|
-
* @param {CompileError[]} [errors]
|
|
288
|
-
* @param {AST.CommentWithLocation[]} [comments]
|
|
289
|
-
*/
|
|
290
|
-
export function validate_class_component_declarations(class_body, filename, errors, comments) {
|
|
291
|
-
for (const member of class_body.body) {
|
|
292
|
-
if (member.type !== 'PropertyDefinition') {
|
|
293
|
-
continue;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const value = /** @type {any} */ (member).value;
|
|
297
|
-
if (value && value.type === 'Component' && !value.metadata?.arrow) {
|
|
298
|
-
error(
|
|
299
|
-
CLASS_COMPONENT_AS_NON_ARROW_PROPERTY_ERROR,
|
|
300
|
-
filename ?? null,
|
|
301
|
-
member,
|
|
302
|
-
errors,
|
|
303
|
-
comments,
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
242
|
/**
|
|
310
243
|
* @param {AST.Element} element
|
|
311
244
|
* @param {AnalysisContext} context
|
package/src/diagnostics.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
export const DIAGNOSTIC_CODES = {
|
|
2
2
|
JSX_EXPRESSION_VALUE: 'tsrx-jsx-expression-value',
|
|
3
|
-
JSX_RETURN_IN_COMPONENT: 'tsrx-jsx-return-in-component',
|
|
4
|
-
FUNCTION_COMPONENT_SYNTAX: 'tsrx-function-component-syntax',
|
|
5
3
|
UNCLOSED_TAG: 'tsrx-unclosed-tag',
|
|
6
4
|
MISMATCHED_CLOSING_TAG: 'tsrx-mismatched-closing-tag',
|
|
7
5
|
TEMPLATE_EXPRESSION_TRAILING_SEMICOLON: 'tsrx-template-expression-trailing-semicolon',
|
|
8
|
-
|
|
6
|
+
TEMPLATE_RETURN_STATEMENT: 'tsrx-template-return-statement',
|
|
9
7
|
};
|
package/src/index.js
CHANGED
|
@@ -86,7 +86,6 @@ export {
|
|
|
86
86
|
build_fallback as buildFallback,
|
|
87
87
|
build_assignment_value as buildAssignmentValue,
|
|
88
88
|
is_class_node as isClassNode,
|
|
89
|
-
is_component_node as isComponentNode,
|
|
90
89
|
is_function_node as isFunctionNode,
|
|
91
90
|
is_function_or_component_node as isFunctionOrComponentNode,
|
|
92
91
|
is_inside_component as isInsideComponent,
|
|
@@ -142,35 +141,25 @@ export { escape, escape_script as escapeScript } from './utils/escaping.js';
|
|
|
142
141
|
|
|
143
142
|
// Transform
|
|
144
143
|
export {
|
|
145
|
-
add_ref_target_type_to_ref_prop_attributes as addRefTargetTypeToRefPropAttributes,
|
|
146
144
|
add_jsx_setup_declaration as addJsxSetupDeclaration,
|
|
147
145
|
clone_switch_helper_invocation as cloneSwitchHelperInvocation,
|
|
148
146
|
collect_param_bindings as collectParamBindings,
|
|
149
147
|
collect_statement_bindings as collectStatementBindings,
|
|
150
148
|
create_hook_safe_helper as createHookSafeHelper,
|
|
151
|
-
create_host_html_attribute as createHostHtmlAttribute,
|
|
152
|
-
create_host_html_conflict_error as createHostHtmlConflictError,
|
|
153
149
|
create_element_ref_target_type as createElementRefTargetType,
|
|
154
150
|
create_element_ref_target_type_for_name as createElementRefTargetTypeForName,
|
|
155
151
|
createJsxTransform,
|
|
156
|
-
CREATE_REF_PROP_INTERNAL_NAME,
|
|
157
152
|
extract_jsx_setup_declarations as extractJsxSetupDeclarations,
|
|
158
|
-
get_host_html_conflicting_attribute as getHostHtmlConflictingAttribute,
|
|
159
|
-
get_invalid_html_child_error_message as getInvalidHtmlChildErrorMessage,
|
|
160
153
|
is_component_like_element,
|
|
161
|
-
is_ref_expression_attribute_value as isRefExpressionAttributeValue,
|
|
162
|
-
is_ref_prop_expression as isRefPropExpression,
|
|
163
154
|
MERGE_REFS_INTERNAL_NAME,
|
|
164
155
|
merge_duplicate_refs as mergeDuplicateRefs,
|
|
156
|
+
NORMALIZE_SPREAD_PROPS_FOR_REF_ATTR_INTERNAL_NAME,
|
|
165
157
|
NORMALIZE_SPREAD_PROPS_INTERNAL_NAME,
|
|
166
158
|
plan_switch_lift as planSwitchLift,
|
|
167
|
-
recover_invalid_html_child as recoverInvalidHtmlChild,
|
|
168
|
-
rewrite_host_html_children as rewriteHostHtmlChildren,
|
|
169
159
|
return_value_body_to_expression as returnValueBodyToExpression,
|
|
170
160
|
rewrite_loop_continues_to_bare_returns as rewriteLoopContinuesToBareReturns,
|
|
171
161
|
to_jsx_attribute as toJsxAttribute,
|
|
172
162
|
validate_at_most_one_ref_attribute as validateAtMostOneRefAttribute,
|
|
173
|
-
component_to_function_declaration as componentToFunctionDeclaration,
|
|
174
163
|
} from './transform/jsx/index.js';
|
|
175
164
|
export {
|
|
176
165
|
ensure_function_metadata as ensureFunctionMetadata,
|
|
@@ -178,6 +167,11 @@ export {
|
|
|
178
167
|
tsx_node_to_jsx_expression as tsxNodeToJsxExpression,
|
|
179
168
|
tsx_with_ts_locations as tsxWithTsLocations,
|
|
180
169
|
} from './transform/jsx/helpers.js';
|
|
170
|
+
export {
|
|
171
|
+
collect_style_ref_attributes as collectStyleRefAttributes,
|
|
172
|
+
create_style_class_map as createStyleClassMap,
|
|
173
|
+
create_style_ref_setup_statements as createStyleRefSetupStatements,
|
|
174
|
+
} from './transform/style-ref.js';
|
|
181
175
|
export {
|
|
182
176
|
clone_expression_node,
|
|
183
177
|
clone_identifier,
|
|
@@ -224,7 +218,7 @@ export {
|
|
|
224
218
|
} from './transform/lazy.js';
|
|
225
219
|
export {
|
|
226
220
|
find_first_top_level_await as findFirstTopLevelAwait,
|
|
227
|
-
|
|
221
|
+
find_first_top_level_await_in_tsrx_function_body as findFirstTopLevelAwaitInTsrxFunctionBody,
|
|
228
222
|
} from './transform/await.js';
|
|
229
223
|
export {
|
|
230
224
|
is_interleaved_body as isInterleavedBody,
|
|
@@ -243,22 +237,18 @@ export {
|
|
|
243
237
|
export { analyze_css as analyzeCss } from './analyze/css-analyze.js';
|
|
244
238
|
export { prune_css as pruneCss } from './analyze/prune.js';
|
|
245
239
|
export {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
COMPONENT_RETURN_VALUE_ERROR,
|
|
254
|
-
COMPONENT_WHILE_STATEMENT_ERROR,
|
|
240
|
+
TSRX_DO_WHILE_STATEMENT_ERROR,
|
|
241
|
+
TSRX_FOR_IN_STATEMENT_ERROR,
|
|
242
|
+
TSRX_FOR_STATEMENT_ERROR,
|
|
243
|
+
TSRX_LOOP_BREAK_ERROR,
|
|
244
|
+
TSRX_LOOP_RETURN_ERROR,
|
|
245
|
+
TSRX_RETURN_STATEMENT_ERROR,
|
|
246
|
+
TSRX_WHILE_STATEMENT_ERROR,
|
|
255
247
|
get_return_keyword_node as getReturnKeywordNode,
|
|
256
248
|
get_statement_keyword_node as getStatementKeywordNode,
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
validate_component_return_statement as validateComponentReturnStatement,
|
|
262
|
-
validate_component_unsupported_loop_statement as validateComponentUnsupportedLoopStatement,
|
|
249
|
+
validate_tsrx_loop_break_statement as validateTsrxLoopBreakStatement,
|
|
250
|
+
validate_tsrx_loop_return_statement as validateTsrxLoopReturnStatement,
|
|
251
|
+
validate_tsrx_return_statement as validateTsrxReturnStatement,
|
|
252
|
+
validate_tsrx_unsupported_loop_statement as validateTsrxUnsupportedLoopStatement,
|
|
263
253
|
validate_nesting as validateNesting,
|
|
264
254
|
} from './analyze/validation.js';
|
package/src/parse/index.js
CHANGED
|
@@ -145,6 +145,36 @@ function elementTemplateClosingTagPlugin(Base) {
|
|
|
145
145
|
return false;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
/**
|
|
149
|
+
* @param {any} parser
|
|
150
|
+
*/
|
|
151
|
+
function isOpeningTagAfterReturnKeyword(parser) {
|
|
152
|
+
if (parser.input.charCodeAt(parser.start + 1) === 47 /* '/' */) return false;
|
|
153
|
+
|
|
154
|
+
let index = parser.start - 1;
|
|
155
|
+
while (index >= 0) {
|
|
156
|
+
const ch = parser.input.charCodeAt(index);
|
|
157
|
+
if (ch === 32 /* ' ' */ || ch === 9 /* '\t' */) {
|
|
158
|
+
index--;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (ch === 10 /* '\n' */ || ch === 13 /* '\r' */) return false;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const end = index + 1;
|
|
166
|
+
const start = end - 'return'.length;
|
|
167
|
+
if (start < 0 || parser.input.slice(start, end) !== 'return') return false;
|
|
168
|
+
const before = start > 0 ? parser.input.charCodeAt(start - 1) : -1;
|
|
169
|
+
return !(
|
|
170
|
+
(before >= 48 /* '0' */ && before <= 57) ||
|
|
171
|
+
(before >= 65 /* 'A' */ && before <= 90) ||
|
|
172
|
+
(before >= 97 /* 'a' */ && before <= 122) ||
|
|
173
|
+
before === 36 /* '$' */ ||
|
|
174
|
+
before === 95 /* '_' */
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
148
178
|
return class extends Base {
|
|
149
179
|
/** @param {number} code */
|
|
150
180
|
// @ts-ignore — extending acorn's Parser with internal hooks
|
|
@@ -165,7 +195,13 @@ function elementTemplateClosingTagPlugin(Base) {
|
|
|
165
195
|
// @ts-ignore — extending acorn's Parser with internal hooks
|
|
166
196
|
canInsertSemicolon() {
|
|
167
197
|
const self = /** @type {any} */ (this);
|
|
168
|
-
if (
|
|
198
|
+
if (
|
|
199
|
+
self.type === jsxTagStart &&
|
|
200
|
+
inElementTemplateBodyAnywhere(self) &&
|
|
201
|
+
!isOpeningTagAfterReturnKeyword(self)
|
|
202
|
+
) {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
169
205
|
// @ts-ignore
|
|
170
206
|
return super.canInsertSemicolon();
|
|
171
207
|
}
|
|
@@ -592,7 +628,6 @@ export function get_comment_handlers(source, comments, index = 0) {
|
|
|
592
628
|
if (
|
|
593
629
|
parent.type === 'BlockStatement' ||
|
|
594
630
|
parent.type === 'Program' ||
|
|
595
|
-
parent.type === 'Component' ||
|
|
596
631
|
parent.type === 'ClassBody'
|
|
597
632
|
) {
|
|
598
633
|
node_array = parent.body;
|
|
@@ -783,8 +818,6 @@ export function get_comment_handlers(source, comments, index = 0) {
|
|
|
783
818
|
const isStatementContext =
|
|
784
819
|
parent.type === 'BlockStatement' || parent.type === 'Program';
|
|
785
820
|
|
|
786
|
-
// Don't apply for Component - let Prettier handle comment attachment there
|
|
787
|
-
// Component bodies have different comment handling via metadata.elementLeadingComments
|
|
788
821
|
if (!isStatementContext) {
|
|
789
822
|
return;
|
|
790
823
|
}
|