@tsrx/core 0.1.31 → 0.1.32
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 +1 -0
- package/src/plugin.js +103 -56
- package/src/transform/jsx/index.js +87 -12
- package/src/utils/builders.js +20 -0
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -159,6 +159,7 @@ export {
|
|
|
159
159
|
rewrite_loop_continues_to_bare_returns as rewriteLoopContinuesToBareReturns,
|
|
160
160
|
to_jsx_attribute as toJsxAttribute,
|
|
161
161
|
validate_at_most_one_ref_attribute as validateAtMostOneRefAttribute,
|
|
162
|
+
wrap_edge_whitespace as wrapEdgeWhitespace,
|
|
162
163
|
} from './transform/jsx/index.js';
|
|
163
164
|
export {
|
|
164
165
|
in_jsx_child_context as inJsxChildContext,
|
package/src/plugin.js
CHANGED
|
@@ -5,12 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import * as acorn from 'acorn';
|
|
8
|
-
import {
|
|
9
|
-
skipWhitespace,
|
|
10
|
-
isWhitespaceTextNode,
|
|
11
|
-
BINDING_TYPES,
|
|
12
|
-
DestructuringErrors,
|
|
13
|
-
} from './parse/index.js';
|
|
8
|
+
import { isWhitespaceTextNode, BINDING_TYPES, DestructuringErrors } from './parse/index.js';
|
|
14
9
|
import { parse_style } from './parse/style.js';
|
|
15
10
|
import { regex_newline_characters } from './utils/patterns.js';
|
|
16
11
|
import { error } from './errors.js';
|
|
@@ -549,7 +544,6 @@ export function TSRXPlugin(config) {
|
|
|
549
544
|
while (index < this.input.length) {
|
|
550
545
|
if (this.#isTemplateLineCommentStart(index, start)) {
|
|
551
546
|
const comment_start = index;
|
|
552
|
-
const comment_start_loc = acorn.getLineInfo(this.input, comment_start);
|
|
553
547
|
index += 2;
|
|
554
548
|
while (
|
|
555
549
|
index < this.input.length &&
|
|
@@ -558,20 +552,9 @@ export function TSRXPlugin(config) {
|
|
|
558
552
|
) {
|
|
559
553
|
index++;
|
|
560
554
|
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
// as a leading comment on the following child (which the JSX printers
|
|
565
|
-
// emit), rather than on the container's `elementLeadingComments`.
|
|
566
|
-
this.options.onComment(
|
|
567
|
-
false,
|
|
568
|
-
this.input.slice(comment_start + 2, index),
|
|
569
|
-
comment_start,
|
|
570
|
-
index,
|
|
571
|
-
new acorn.Position(comment_start_loc.line, comment_start_loc.column),
|
|
572
|
-
new acorn.Position(comment_end_loc.line, comment_end_loc.column),
|
|
573
|
-
/** @type {any} */ (null),
|
|
574
|
-
);
|
|
555
|
+
|
|
556
|
+
if (comment_start >= token_end) {
|
|
557
|
+
this.#emitTemplateLineComment(comment_start, index, null);
|
|
575
558
|
}
|
|
576
559
|
continue;
|
|
577
560
|
}
|
|
@@ -590,7 +573,7 @@ export function TSRXPlugin(config) {
|
|
|
590
573
|
index,
|
|
591
574
|
new acorn.Position(comment_start_loc.line, comment_start_loc.column),
|
|
592
575
|
new acorn.Position(comment_end_loc.line, comment_end_loc.column),
|
|
593
|
-
|
|
576
|
+
null,
|
|
594
577
|
);
|
|
595
578
|
}
|
|
596
579
|
continue;
|
|
@@ -640,6 +623,62 @@ export function TSRXPlugin(config) {
|
|
|
640
623
|
return node.value !== '' && !regex_newline_characters.test(node.value);
|
|
641
624
|
}
|
|
642
625
|
|
|
626
|
+
#skipTrailingLayoutWhitespace() {
|
|
627
|
+
let index = this.start;
|
|
628
|
+
let has_newline = false;
|
|
629
|
+
while (index < this.input.length) {
|
|
630
|
+
const ch = this.input.charCodeAt(index);
|
|
631
|
+
if (ch === CharCode.lineFeed || ch === CharCode.carriageReturn) {
|
|
632
|
+
has_newline = true;
|
|
633
|
+
index++;
|
|
634
|
+
} else if (ch === CharCode.space || ch === CharCode.tab) {
|
|
635
|
+
index++;
|
|
636
|
+
} else if (ch === CharCode.slash && this.input.charCodeAt(index + 1) === CharCode.slash) {
|
|
637
|
+
const comment_start = index;
|
|
638
|
+
while (index < this.input.length && !this.#isNewlineCharCode(index)) {
|
|
639
|
+
index++;
|
|
640
|
+
}
|
|
641
|
+
this.#emitTemplateLineComment(comment_start, index, null);
|
|
642
|
+
} else {
|
|
643
|
+
break;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
if (!has_newline) return;
|
|
647
|
+
const loc = acorn.getLineInfo(this.input, index);
|
|
648
|
+
this.start = index;
|
|
649
|
+
this.startLoc = new acorn.Position(loc.line, loc.column);
|
|
650
|
+
if (this.pos <= index) {
|
|
651
|
+
this.curLine = loc.line;
|
|
652
|
+
this.lineStart = index - loc.column;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* @param {number} index
|
|
658
|
+
*/
|
|
659
|
+
#isNewlineCharCode(index) {
|
|
660
|
+
const ch = this.input.charCodeAt(index);
|
|
661
|
+
return ch === CharCode.lineFeed || ch === CharCode.carriageReturn;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* @param {number} start
|
|
666
|
+
* @param {number} end
|
|
667
|
+
* @param {Parse.CommentMetaData | null} metadata
|
|
668
|
+
*/
|
|
669
|
+
#emitTemplateLineComment(start, end, metadata) {
|
|
670
|
+
if (!this.options.onComment) return;
|
|
671
|
+
this.options.onComment(
|
|
672
|
+
false,
|
|
673
|
+
this.input.slice(start + 2, end),
|
|
674
|
+
start,
|
|
675
|
+
end,
|
|
676
|
+
acorn.getLineInfo(this.input, start),
|
|
677
|
+
acorn.getLineInfo(this.input, end),
|
|
678
|
+
metadata,
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
|
|
643
682
|
#isSwitchCaseScriptStatementStart() {
|
|
644
683
|
let index = skip_whitespace_from(this.input, this.start);
|
|
645
684
|
|
|
@@ -4430,50 +4469,58 @@ export function TSRXPlugin(config) {
|
|
|
4430
4469
|
this.context.pop();
|
|
4431
4470
|
}
|
|
4432
4471
|
return;
|
|
4433
|
-
} else if (
|
|
4434
|
-
this.type === tstt.jsxTagStart ||
|
|
4435
|
-
this.input.charCodeAt(this.start) === CharCode.lessThan
|
|
4436
|
-
) {
|
|
4472
|
+
} else if (this.type === tstt.jsxTagStart) {
|
|
4437
4473
|
const startPos = this.start;
|
|
4438
4474
|
const startLoc = this.startLoc;
|
|
4439
|
-
|
|
4440
|
-
this.next();
|
|
4441
|
-
} else {
|
|
4442
|
-
// A control-flow block inside a native template can leave the tokenizer
|
|
4443
|
-
// in normal JS mode, so a closing tag may arrive as a relational
|
|
4444
|
-
// `<` token. Re-enter JSX closing-tag parsing manually.
|
|
4445
|
-
this.pos = startPos + 1;
|
|
4446
|
-
this.type = tstt.jsxTagStart;
|
|
4447
|
-
this.start = startPos;
|
|
4448
|
-
this.startLoc = startLoc;
|
|
4449
|
-
this.exprAllowed = false;
|
|
4450
|
-
// A genuine `jsxTagStart` pushes `tc_expr` + `tc_oTag` in its
|
|
4451
|
-
// `updateContext`; faking the token here skips those pushes. That is
|
|
4452
|
-
// harmless for an opening tag (the next token is the tag name), but a
|
|
4453
|
-
// closing tag (`</`) immediately runs `context.length -= 2` in the
|
|
4454
|
-
// slash `updateContext`, which would underflow the context stack and
|
|
4455
|
-
// throw "Invalid array length" (e.g. `<>@if (a) { … } done</>`). Push
|
|
4456
|
-
// the two contexts a real `jsxTagStart` would have added so the closing
|
|
4457
|
-
// tag pops its own contexts instead of the enclosing template's.
|
|
4458
|
-
if (this.input.charCodeAt(this.pos) === CharCode.slash) {
|
|
4459
|
-
this.context.push(tstc.tc_expr);
|
|
4460
|
-
this.context.push(tstc.tc_oTag);
|
|
4461
|
-
}
|
|
4462
|
-
this.next();
|
|
4463
|
-
}
|
|
4475
|
+
this.next();
|
|
4464
4476
|
if (this.value === '/' || this.type === tt.slash) {
|
|
4465
4477
|
// Consume '/'
|
|
4466
4478
|
this.next();
|
|
4467
4479
|
|
|
4468
|
-
|
|
4480
|
+
const closingNode = this.startNodeAt(startPos, startLoc);
|
|
4481
|
+
const inside_parent_template =
|
|
4482
|
+
this.#jsxExpressionContainerDepth === 0 &&
|
|
4483
|
+
this.#templateScriptParsingDepth === 0 &&
|
|
4484
|
+
this.#path.slice(0, -1).some((node) => this.#isNativeTemplateNode(node));
|
|
4469
4485
|
this.#closingNativeTemplateNode = true;
|
|
4486
|
+
/** @type {ReturnType<Parse.Parser['jsx_parseElementName']>} */
|
|
4487
|
+
let closingName;
|
|
4470
4488
|
try {
|
|
4471
|
-
|
|
4472
|
-
this.jsx_parseClosingElementAt(startPos, startLoc)
|
|
4473
|
-
);
|
|
4489
|
+
closingName = this.jsx_parseElementName();
|
|
4474
4490
|
} finally {
|
|
4475
4491
|
this.#closingNativeTemplateNode = false;
|
|
4476
4492
|
}
|
|
4493
|
+
if (closingName) {
|
|
4494
|
+
/** @type {ESTreeJSX.JSXClosingElement} */ (closingNode).name =
|
|
4495
|
+
/** @type {ESTreeJSX.JSXIdentifier} */ (closingName);
|
|
4496
|
+
}
|
|
4497
|
+
const current = /** @type {ESTreeJSX.JSXFragment | ESTreeJSX.JSXElement} */ (
|
|
4498
|
+
this.#path[this.#path.length - 1]
|
|
4499
|
+
);
|
|
4500
|
+
const current_name = this.#isNativeTemplateNode(current)
|
|
4501
|
+
? current.type === 'JSXFragment'
|
|
4502
|
+
? ''
|
|
4503
|
+
: current.openingElement?.name
|
|
4504
|
+
? this.getElementName(current.openingElement.name)
|
|
4505
|
+
: null
|
|
4506
|
+
: null;
|
|
4507
|
+
const closing_name_str = !closingName
|
|
4508
|
+
? ''
|
|
4509
|
+
: closingName.type === 'JSXNamespacedName'
|
|
4510
|
+
? closingName.namespace.name + ':' + closingName.name.name
|
|
4511
|
+
: this.getElementName(closingName);
|
|
4512
|
+
if (!(inside_parent_template && current_name === closing_name_str)) {
|
|
4513
|
+
this.#closingNativeTemplateNode = true;
|
|
4514
|
+
}
|
|
4515
|
+
this.expect(tstt.jsxTagEnd);
|
|
4516
|
+
this.#closingNativeTemplateNode = false;
|
|
4517
|
+
const closingElement =
|
|
4518
|
+
/** @type {ESTreeJSX.JSXClosingElement & AST.NodeWithLocation} */ (
|
|
4519
|
+
this.finishNode(
|
|
4520
|
+
closingNode,
|
|
4521
|
+
closingName ? 'JSXClosingElement' : 'JSXClosingFragment',
|
|
4522
|
+
)
|
|
4523
|
+
);
|
|
4477
4524
|
if (this.#isDynamicJSXElementName(closingElement.name)) {
|
|
4478
4525
|
/** @type {any} */ (closingElement).isDynamic = true;
|
|
4479
4526
|
}
|
|
@@ -4586,7 +4633,7 @@ export function TSRXPlugin(config) {
|
|
|
4586
4633
|
}
|
|
4587
4634
|
|
|
4588
4635
|
this.#path.pop();
|
|
4589
|
-
|
|
4636
|
+
this.#skipTrailingLayoutWhitespace();
|
|
4590
4637
|
return;
|
|
4591
4638
|
}
|
|
4592
4639
|
const node = this.parseElement();
|
|
@@ -74,6 +74,16 @@ const TSRX_IF_CONTINUE_ERROR =
|
|
|
74
74
|
'Continue statements are not allowed inside TSRX template @if blocks. Filter before rendering or use conditional output instead.';
|
|
75
75
|
const DYNAMIC_IMPORT_LOCAL = 'TsrxDynamic';
|
|
76
76
|
const DYNAMIC_FACTORY_LOCAL = '_tsrx_dynamic';
|
|
77
|
+
const LEADING_INLINE_WHITESPACE = /^[ \t]+/;
|
|
78
|
+
const TRAILING_INLINE_WHITESPACE = /[ \t]+$/;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @param {string | undefined} ch
|
|
82
|
+
* @returns {boolean}
|
|
83
|
+
*/
|
|
84
|
+
function is_newline_char(ch) {
|
|
85
|
+
return ch === '\n' || ch === '\r';
|
|
86
|
+
}
|
|
77
87
|
|
|
78
88
|
/**
|
|
79
89
|
* @param {AST.Node} node
|
|
@@ -2413,9 +2423,7 @@ function mark_native_pretransformed_jsx(node, seen = new Set()) {
|
|
|
2413
2423
|
function get_tsrx_render_children(node) {
|
|
2414
2424
|
return (node.children || []).filter(
|
|
2415
2425
|
(/** @type {any} */ child) =>
|
|
2416
|
-
child &&
|
|
2417
|
-
child.type !== 'EmptyStatement' &&
|
|
2418
|
-
(child.type !== 'JSXText' || child.value.trim() !== ''),
|
|
2426
|
+
child && child.type !== 'EmptyStatement' && (child.type !== 'JSXText' || child.value !== ''),
|
|
2419
2427
|
);
|
|
2420
2428
|
}
|
|
2421
2429
|
|
|
@@ -3399,7 +3407,9 @@ function create_element_children(children, transform_context) {
|
|
|
3399
3407
|
const saved_inside_element_child = transform_context.inside_element_child;
|
|
3400
3408
|
transform_context.inside_element_child = true;
|
|
3401
3409
|
try {
|
|
3402
|
-
return
|
|
3410
|
+
return wrap_edge_whitespace(
|
|
3411
|
+
children.map((/** @type {any} */ child) => to_jsx_child(child, transform_context)),
|
|
3412
|
+
);
|
|
3403
3413
|
} finally {
|
|
3404
3414
|
transform_context.inside_element_child = saved_inside_element_child;
|
|
3405
3415
|
}
|
|
@@ -3949,6 +3959,67 @@ function is_try_control_node(node) {
|
|
|
3949
3959
|
return node?.type === 'TryStatement' || node?.type === 'JSXTryExpression';
|
|
3950
3960
|
}
|
|
3951
3961
|
|
|
3962
|
+
/**
|
|
3963
|
+
* Wrap the inline whitespace at a fragment/element's content edges in `{' '}`
|
|
3964
|
+
* containers. A bare leading/trailing space is fragile: once the output is
|
|
3965
|
+
* line-wrapped (by prettier or the host JSX compiler) it becomes newline-adjacent
|
|
3966
|
+
* and is trimmed away, dropping a significant space. Whitespace BETWEEN siblings
|
|
3967
|
+
* stays bare text — it is not at an edge and is preserved as-is. Only spaces/tabs
|
|
3968
|
+
* are pulled out; whitespace runs containing a newline are layout indentation and
|
|
3969
|
+
* are left for the host compiler to collapse.
|
|
3970
|
+
*
|
|
3971
|
+
* @param {any[]} nodes
|
|
3972
|
+
* @returns {any[]}
|
|
3973
|
+
*/
|
|
3974
|
+
export function wrap_edge_whitespace(nodes) {
|
|
3975
|
+
const length = nodes.length;
|
|
3976
|
+
if (length === 0) {
|
|
3977
|
+
return nodes;
|
|
3978
|
+
}
|
|
3979
|
+
|
|
3980
|
+
const first = nodes[0];
|
|
3981
|
+
const last = nodes[length - 1];
|
|
3982
|
+
if (first?.type !== 'JSXText' && last?.type !== 'JSXText') {
|
|
3983
|
+
return nodes;
|
|
3984
|
+
}
|
|
3985
|
+
|
|
3986
|
+
/** @type {(ESTreeJSX.JSXExpressionContainer | ESTreeJSX.JSXText)[]} */
|
|
3987
|
+
const out = [];
|
|
3988
|
+
for (let i = 0; i < length; i++) {
|
|
3989
|
+
const node = nodes[i];
|
|
3990
|
+
const at_start = i === 0;
|
|
3991
|
+
const at_end = i === length - 1;
|
|
3992
|
+
if (!node || node.type !== 'JSXText' || (!at_start && !at_end)) {
|
|
3993
|
+
out.push(node);
|
|
3994
|
+
continue;
|
|
3995
|
+
}
|
|
3996
|
+
let value = /** @type {string} */ (node.value);
|
|
3997
|
+
if (at_start) {
|
|
3998
|
+
const lead = LEADING_INLINE_WHITESPACE.exec(value);
|
|
3999
|
+
if (lead && !is_newline_char(value[lead[0].length])) {
|
|
4000
|
+
out.push(to_jsx_expression_container(b.literal(lead[0]), node));
|
|
4001
|
+
value = value.slice(lead[0].length);
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4004
|
+
/** @type {ESTreeJSX.JSXExpressionContainer | null} */
|
|
4005
|
+
let trailing = null;
|
|
4006
|
+
if (at_end) {
|
|
4007
|
+
const trail = TRAILING_INLINE_WHITESPACE.exec(value);
|
|
4008
|
+
if (trail && !is_newline_char(value[value.length - trail[0].length - 1])) {
|
|
4009
|
+
trailing = to_jsx_expression_container(b.literal(trail[0]), node);
|
|
4010
|
+
value = value.slice(0, value.length - trail[0].length);
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
if (value !== '') {
|
|
4014
|
+
out.push(b.jsx_text(value, value));
|
|
4015
|
+
}
|
|
4016
|
+
if (trailing) {
|
|
4017
|
+
out.push(trailing);
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
return out;
|
|
4021
|
+
}
|
|
4022
|
+
|
|
3952
4023
|
/**
|
|
3953
4024
|
* @param {any} node
|
|
3954
4025
|
* @param {TransformContext} transform_context
|
|
@@ -4034,15 +4105,15 @@ function to_jsx_child(node, transform_context) {
|
|
|
4034
4105
|
function tsrx_node_to_jsx_expression(node, transform_context, in_jsx_child = false) {
|
|
4035
4106
|
const children = (node.children || []).filter(
|
|
4036
4107
|
(/** @type {any} */ child) =>
|
|
4037
|
-
child &&
|
|
4038
|
-
child.type !== 'EmptyStatement' &&
|
|
4039
|
-
(child.type !== 'JSXText' || child.value.trim() !== ''),
|
|
4108
|
+
child && child.type !== 'EmptyStatement' && (child.type !== 'JSXText' || child.value !== ''),
|
|
4040
4109
|
);
|
|
4041
4110
|
|
|
4042
4111
|
/** @type {any} */
|
|
4043
4112
|
let expression;
|
|
4044
4113
|
if (children.length === 0) {
|
|
4045
|
-
expression =
|
|
4114
|
+
expression = in_jsx_child
|
|
4115
|
+
? set_loc(b.jsx_fragment([]), node.loc ? node : undefined)
|
|
4116
|
+
: create_null_literal();
|
|
4046
4117
|
} else {
|
|
4047
4118
|
expression = return_value_body_to_expression(children, node, transform_context);
|
|
4048
4119
|
}
|
|
@@ -4052,10 +4123,10 @@ function tsrx_node_to_jsx_expression(node, transform_context, in_jsx_child = fal
|
|
|
4052
4123
|
const saved_inside_element_child = transform_context.inside_element_child;
|
|
4053
4124
|
transform_context.inside_element_child = true;
|
|
4054
4125
|
try {
|
|
4055
|
-
const render_nodes =
|
|
4056
|
-
to_jsx_child(child, transform_context),
|
|
4126
|
+
const render_nodes = wrap_edge_whitespace(
|
|
4127
|
+
children.map((/** @type {any} */ child) => to_jsx_child(child, transform_context)),
|
|
4057
4128
|
);
|
|
4058
|
-
expression = build_return_expression(render_nodes) || create_null_literal();
|
|
4129
|
+
expression = build_return_expression(render_nodes, in_jsx_child) || create_null_literal();
|
|
4059
4130
|
} finally {
|
|
4060
4131
|
transform_context.inside_element_child = saved_inside_element_child;
|
|
4061
4132
|
}
|
|
@@ -5839,9 +5910,10 @@ function value_has_unmappable_jsx_loc(value) {
|
|
|
5839
5910
|
|
|
5840
5911
|
/**
|
|
5841
5912
|
* @param {any[]} render_nodes
|
|
5913
|
+
* @param {boolean} [in_jsx_child]
|
|
5842
5914
|
* @returns {any}
|
|
5843
5915
|
*/
|
|
5844
|
-
function build_return_expression(render_nodes) {
|
|
5916
|
+
function build_return_expression(render_nodes, in_jsx_child = false) {
|
|
5845
5917
|
if (render_nodes.length === 0) return null;
|
|
5846
5918
|
if (render_nodes.length === 1) {
|
|
5847
5919
|
const only = render_nodes[0];
|
|
@@ -5855,6 +5927,9 @@ function build_return_expression(render_nodes) {
|
|
|
5855
5927
|
return only.expression;
|
|
5856
5928
|
}
|
|
5857
5929
|
if (only.type === 'JSXText') {
|
|
5930
|
+
if (in_jsx_child) {
|
|
5931
|
+
return set_loc(b.jsx_fragment([only]), only.loc ? only : undefined);
|
|
5932
|
+
}
|
|
5858
5933
|
const value = (only.value ?? '').trim();
|
|
5859
5934
|
return b.literal(value, JSON.stringify(value), only);
|
|
5860
5935
|
}
|
package/src/utils/builders.js
CHANGED
|
@@ -368,6 +368,26 @@ export function literal(value, raw, loc_info) {
|
|
|
368
368
|
return set_location(node, loc_info);
|
|
369
369
|
}
|
|
370
370
|
|
|
371
|
+
/**
|
|
372
|
+
* Ripple template `Text` node wrapping a string literal of `value`. Used by the
|
|
373
|
+
* Ripple normalizer when lowering a JSX text child to a template Text node.
|
|
374
|
+
*
|
|
375
|
+
* Remove once Ripple transformers move to the parser's JSX AST
|
|
376
|
+
*
|
|
377
|
+
* @param {string} value
|
|
378
|
+
* @param {AST.NodeWithLocation} [loc_info]
|
|
379
|
+
* @returns {AST.Text}
|
|
380
|
+
*/
|
|
381
|
+
export function text(value, loc_info) {
|
|
382
|
+
const node = /** @type {AST.Text} */ ({
|
|
383
|
+
type: 'Text',
|
|
384
|
+
expression: literal(value, JSON.stringify(value), loc_info),
|
|
385
|
+
metadata: { path: [] },
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
return set_location(node, loc_info);
|
|
389
|
+
}
|
|
390
|
+
|
|
371
391
|
/**
|
|
372
392
|
* @param {AST.Expression | AST.Super} object
|
|
373
393
|
* @param {string | AST.Expression | AST.PrivateIdentifier} property
|