@lwc/babel-plugin-component 8.24.0 → 8.25.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/dist/decorators/api/transform.d.ts +2 -2
- package/dist/decorators/index.d.ts +1 -1
- package/dist/decorators/wire/transform.d.ts +2 -2
- package/dist/index.cjs.js +139 -82
- package/dist/index.js +140 -83
- package/dist/utils.d.ts +3 -2
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { types, NodePath } from '@babel/core';
|
|
2
2
|
import type { DecoratorMeta } from '../index';
|
|
3
|
-
import type { BabelTypes } from '../../types';
|
|
3
|
+
import type { BabelTypes, LwcBabelPluginPass } from '../../types';
|
|
4
4
|
import type { ClassBodyItem } from '../types';
|
|
5
|
-
export default function transform(t: BabelTypes, decoratorMetas: DecoratorMeta[], classBodyItems: NodePath<ClassBodyItem>[]): types.ObjectProperty[];
|
|
5
|
+
export default function transform(t: BabelTypes, decoratorMetas: DecoratorMeta[], classBodyItems: NodePath<ClassBodyItem>[], state: LwcBabelPluginPass): types.ObjectProperty[];
|
|
6
6
|
//# sourceMappingURL=transform.d.ts.map
|
|
@@ -7,7 +7,7 @@ export interface DecoratorMeta {
|
|
|
7
7
|
name: LwcDecoratorName;
|
|
8
8
|
propertyName: string;
|
|
9
9
|
path: NodePath<types.Decorator>;
|
|
10
|
-
decoratedNodeType: DecoratorType;
|
|
10
|
+
decoratedNodeType: DecoratorType | null;
|
|
11
11
|
type?: DecoratorType;
|
|
12
12
|
}
|
|
13
13
|
declare function validateImportedLwcDecoratorUsage(engineImportSpecifiers: ImportSpecifier[], state: LwcBabelPluginPass): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { types } from '@babel/core';
|
|
2
2
|
import type { DecoratorMeta } from '../index';
|
|
3
|
-
import type { BabelTypes } from '../../types';
|
|
4
|
-
export default function transform(t: BabelTypes, decoratorMetas: DecoratorMeta[]): types.ObjectProperty[];
|
|
3
|
+
import type { BabelTypes, LwcBabelPluginPass } from '../../types';
|
|
4
|
+
export default function transform(t: BabelTypes, decoratorMetas: DecoratorMeta[], state: LwcBabelPluginPass): types.ObjectProperty[];
|
|
5
5
|
//# sourceMappingURL=transform.d.ts.map
|
package/dist/index.cjs.js
CHANGED
|
@@ -229,9 +229,36 @@ function generateError(source, { errorInfo, messageArgs }, state) {
|
|
|
229
229
|
error.lwcCode = errorInfo && errorInfo.code;
|
|
230
230
|
return error;
|
|
231
231
|
}
|
|
232
|
+
function collectError(source, { errorInfo, messageArgs }, state) {
|
|
233
|
+
const diagnostic = errors.generateCompilerDiagnostic(errorInfo, {
|
|
234
|
+
messageArgs,
|
|
235
|
+
origin: {
|
|
236
|
+
filename: state.filename,
|
|
237
|
+
location: normalizeLocation(source) ?? undefined,
|
|
238
|
+
},
|
|
239
|
+
}, true);
|
|
240
|
+
if (diagnostic.level === errors.DiagnosticLevel.Fatal) {
|
|
241
|
+
throw generateError(source, { errorInfo, messageArgs }, state);
|
|
242
|
+
}
|
|
243
|
+
if (!state.file.metadata.lwcErrors) {
|
|
244
|
+
state.file.metadata.lwcErrors = [];
|
|
245
|
+
}
|
|
246
|
+
state.file.metadata.lwcErrors.push(diagnostic);
|
|
247
|
+
}
|
|
248
|
+
function handleError(source, decoratorErrorOpts, state) {
|
|
249
|
+
if (isErrorRecoveryMode(state)) {
|
|
250
|
+
collectError(source, decoratorErrorOpts, state);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
throw generateError(source, decoratorErrorOpts, state);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
232
256
|
function incrementMetricCounter(metric, state) {
|
|
233
257
|
state.opts.instrumentation?.incrementCounter(metric);
|
|
234
258
|
}
|
|
259
|
+
function isErrorRecoveryMode(state) {
|
|
260
|
+
return state.file.opts?.parserOpts?.errorRecovery ?? false;
|
|
261
|
+
}
|
|
235
262
|
|
|
236
263
|
/*
|
|
237
264
|
* Copyright (c) 2023, salesforce.com, inc.
|
|
@@ -255,7 +282,7 @@ function validateConflict(path, decorators, state) {
|
|
|
255
282
|
const isPublicFieldTracked = decorators.some((decorator) => decorator.name === TRACK_DECORATOR$2 &&
|
|
256
283
|
decorator.path.parentPath.node === path.parentPath.node);
|
|
257
284
|
if (isPublicFieldTracked) {
|
|
258
|
-
|
|
285
|
+
handleError(path, {
|
|
259
286
|
errorInfo: errors.DecoratorErrors.API_AND_TRACK_DECORATOR_CONFLICT,
|
|
260
287
|
}, state);
|
|
261
288
|
}
|
|
@@ -266,45 +293,45 @@ function isBooleanPropDefaultTrue(property) {
|
|
|
266
293
|
}
|
|
267
294
|
function validatePropertyValue(property, state) {
|
|
268
295
|
if (isBooleanPropDefaultTrue(property)) {
|
|
269
|
-
|
|
296
|
+
handleError(property, {
|
|
270
297
|
errorInfo: errors.DecoratorErrors.INVALID_BOOLEAN_PUBLIC_PROPERTY,
|
|
271
298
|
}, state);
|
|
272
299
|
}
|
|
273
300
|
}
|
|
274
301
|
function validatePropertyName(property, state) {
|
|
275
302
|
if (property.node.computed) {
|
|
276
|
-
|
|
303
|
+
handleError(property, {
|
|
277
304
|
errorInfo: errors.DecoratorErrors.PROPERTY_CANNOT_BE_COMPUTED,
|
|
278
305
|
}, state);
|
|
279
306
|
}
|
|
280
307
|
const propertyName = property.get('key.name').node;
|
|
281
308
|
if (propertyName === 'part') {
|
|
282
|
-
|
|
309
|
+
handleError(property, {
|
|
283
310
|
errorInfo: errors.DecoratorErrors.PROPERTY_NAME_PART_IS_RESERVED,
|
|
284
311
|
messageArgs: [propertyName],
|
|
285
312
|
}, state);
|
|
286
313
|
}
|
|
287
314
|
else if (propertyName.startsWith('on')) {
|
|
288
|
-
|
|
315
|
+
handleError(property, {
|
|
289
316
|
errorInfo: errors.DecoratorErrors.PROPERTY_NAME_CANNOT_START_WITH_ON,
|
|
290
317
|
messageArgs: [propertyName],
|
|
291
318
|
}, state);
|
|
292
319
|
}
|
|
293
320
|
else if (propertyName.startsWith('data') && propertyName.length > 4) {
|
|
294
|
-
|
|
321
|
+
handleError(property, {
|
|
295
322
|
errorInfo: errors.DecoratorErrors.PROPERTY_NAME_CANNOT_START_WITH_DATA,
|
|
296
323
|
messageArgs: [propertyName],
|
|
297
324
|
}, state);
|
|
298
325
|
}
|
|
299
326
|
else if (shared.DISALLOWED_PROP_SET.has(propertyName)) {
|
|
300
|
-
|
|
327
|
+
handleError(property, {
|
|
301
328
|
errorInfo: errors.DecoratorErrors.PROPERTY_NAME_IS_RESERVED,
|
|
302
329
|
messageArgs: [propertyName],
|
|
303
330
|
}, state);
|
|
304
331
|
}
|
|
305
332
|
else if (shared.AMBIGUOUS_PROP_SET.has(propertyName)) {
|
|
306
333
|
const camelCased = shared.AMBIGUOUS_PROP_SET.get(propertyName);
|
|
307
|
-
|
|
334
|
+
handleError(property, {
|
|
308
335
|
errorInfo: errors.DecoratorErrors.PROPERTY_NAME_IS_AMBIGUOUS,
|
|
309
336
|
messageArgs: [propertyName, camelCased],
|
|
310
337
|
}, state);
|
|
@@ -322,7 +349,7 @@ function validateSingleApiDecoratorOnSetterGetterPair(decorators, state) {
|
|
|
322
349
|
const methodPath = path.parentPath;
|
|
323
350
|
const methodName = methodPath.get('key.name').node;
|
|
324
351
|
if (visitedMethods.has(methodName)) {
|
|
325
|
-
|
|
352
|
+
handleError(methodPath, {
|
|
326
353
|
errorInfo: errors.DecoratorErrors.SINGLE_DECORATOR_ON_SETTER_GETTER_PAIR,
|
|
327
354
|
messageArgs: [methodName],
|
|
328
355
|
}, state);
|
|
@@ -348,7 +375,7 @@ function validateUniqueness(decorators, state) {
|
|
|
348
375
|
compareType === DECORATOR_TYPES.SETTER) ||
|
|
349
376
|
(currentType === DECORATOR_TYPES.SETTER && compareType === DECORATOR_TYPES.GETTER);
|
|
350
377
|
if (haveSameName && isDifferentProperty && !isGetterSetterPair) {
|
|
351
|
-
|
|
378
|
+
handleError(comparePath, {
|
|
352
379
|
errorInfo: errors.DecoratorErrors.DUPLICATE_API_PROPERTY,
|
|
353
380
|
messageArgs: [currentPropertyName],
|
|
354
381
|
}, state);
|
|
@@ -407,8 +434,12 @@ function getSiblingGetSetPairType(propertyName, type, classBodyItems) {
|
|
|
407
434
|
return siblingKind === 'get' ? DECORATOR_TYPES.GETTER : DECORATOR_TYPES.SETTER;
|
|
408
435
|
}
|
|
409
436
|
}
|
|
410
|
-
function computePublicPropsConfig(publicPropertyMetas, classBodyItems) {
|
|
437
|
+
function computePublicPropsConfig(publicPropertyMetas, classBodyItems, state) {
|
|
411
438
|
return publicPropertyMetas.reduce((acc, { propertyName, decoratedNodeType }) => {
|
|
439
|
+
// This should never happen as we filter null in class visitor and
|
|
440
|
+
// collect appropriate errors in errorRecoveryMode || throw otherwise
|
|
441
|
+
if (isErrorRecoveryMode(state) && !decoratedNodeType)
|
|
442
|
+
return acc;
|
|
412
443
|
if (!(propertyName in acc)) {
|
|
413
444
|
acc[propertyName] = {};
|
|
414
445
|
}
|
|
@@ -425,12 +456,12 @@ function computePublicPropsConfig(publicPropertyMetas, classBodyItems) {
|
|
|
425
456
|
return acc;
|
|
426
457
|
}, {});
|
|
427
458
|
}
|
|
428
|
-
function transform$2(t, decoratorMetas, classBodyItems) {
|
|
459
|
+
function transform$2(t, decoratorMetas, classBodyItems, state) {
|
|
429
460
|
const objectProperties = [];
|
|
430
461
|
const apiDecoratorMetas = decoratorMetas.filter(isApiDecorator);
|
|
431
462
|
const publicPropertyMetas = apiDecoratorMetas.filter(({ decoratedNodeType }) => decoratedNodeType !== DECORATOR_TYPES.METHOD);
|
|
432
463
|
if (publicPropertyMetas.length) {
|
|
433
|
-
const propsConfig = computePublicPropsConfig(publicPropertyMetas, classBodyItems);
|
|
464
|
+
const propsConfig = computePublicPropsConfig(publicPropertyMetas, classBodyItems, state);
|
|
434
465
|
objectProperties.push(t.objectProperty(t.identifier(PUBLIC_PROPS), t.valueToNode(propsConfig)));
|
|
435
466
|
}
|
|
436
467
|
const publicMethodMetas = apiDecoratorMetas.filter(({ decoratedNodeType }) => decoratedNodeType === DECORATOR_TYPES.METHOD);
|
|
@@ -474,9 +505,10 @@ function isWireDecorator(decorator) {
|
|
|
474
505
|
const { TRACK_DECORATOR: TRACK_DECORATOR$1, WIRE_DECORATOR: WIRE_DECORATOR$1, API_DECORATOR } = LWC_PACKAGE_EXPORTS;
|
|
475
506
|
function validateWireId(id, path, state) {
|
|
476
507
|
if (!id) {
|
|
477
|
-
|
|
508
|
+
handleError(path, {
|
|
478
509
|
errorInfo: errors.DecoratorErrors.ADAPTER_SHOULD_BE_FIRST_PARAMETER,
|
|
479
510
|
}, state);
|
|
511
|
+
return;
|
|
480
512
|
}
|
|
481
513
|
let adapter;
|
|
482
514
|
if (id.isIdentifier()) {
|
|
@@ -486,9 +518,10 @@ function validateWireId(id, path, state) {
|
|
|
486
518
|
else if (id.isMemberExpression()) {
|
|
487
519
|
if (id.node.computed) {
|
|
488
520
|
// @wire(adapter[computed])
|
|
489
|
-
|
|
521
|
+
handleError(id, {
|
|
490
522
|
errorInfo: errors.DecoratorErrors.FUNCTION_IDENTIFIER_CANNOT_HAVE_COMPUTED_PROPS,
|
|
491
523
|
}, state);
|
|
524
|
+
return;
|
|
492
525
|
}
|
|
493
526
|
const object = id.get('object');
|
|
494
527
|
if (object.isIdentifier()) {
|
|
@@ -497,73 +530,79 @@ function validateWireId(id, path, state) {
|
|
|
497
530
|
}
|
|
498
531
|
else {
|
|
499
532
|
// @wire(adapter.foo.bar)
|
|
500
|
-
|
|
533
|
+
handleError(id, {
|
|
501
534
|
errorInfo: errors.DecoratorErrors.FUNCTION_IDENTIFIER_CANNOT_HAVE_NESTED_MEMBER_EXRESSIONS,
|
|
502
535
|
}, state);
|
|
536
|
+
return;
|
|
503
537
|
}
|
|
504
538
|
}
|
|
505
539
|
else {
|
|
506
540
|
// @wire(1), @wire('adapter'), @wire(function adapter() {}), etc.
|
|
507
|
-
|
|
541
|
+
handleError(id, {
|
|
508
542
|
errorInfo: errors.DecoratorErrors.FUNCTION_IDENTIFIER_SHOULD_BE_FIRST_PARAMETER,
|
|
509
543
|
}, state);
|
|
544
|
+
return;
|
|
510
545
|
}
|
|
511
546
|
// Ensure wire adapter is imported (check for member expression or identifier)
|
|
512
547
|
const adapterBinding = path.scope.getBinding(adapter.node.name);
|
|
513
548
|
if (!adapterBinding) {
|
|
514
|
-
|
|
549
|
+
handleError(id, {
|
|
515
550
|
errorInfo: errors.DecoratorErrors.WIRE_ADAPTER_SHOULD_BE_IMPORTED,
|
|
516
551
|
messageArgs: [adapter.node.name],
|
|
517
552
|
}, state);
|
|
553
|
+
return;
|
|
518
554
|
}
|
|
519
555
|
// ensure wire adapter is a first parameter
|
|
520
556
|
if (!adapterBinding.path.isImportSpecifier() &&
|
|
521
557
|
!adapterBinding.path.isImportDefaultSpecifier()) {
|
|
522
|
-
|
|
558
|
+
handleError(id, {
|
|
523
559
|
errorInfo: errors.DecoratorErrors.IMPORTED_FUNCTION_IDENTIFIER_SHOULD_BE_FIRST_PARAMETER,
|
|
524
560
|
}, state);
|
|
525
561
|
}
|
|
526
562
|
}
|
|
527
563
|
function validateWireConfig(config, path, state) {
|
|
528
564
|
if (!config.isObjectExpression()) {
|
|
529
|
-
|
|
565
|
+
handleError(config, {
|
|
530
566
|
errorInfo: errors.DecoratorErrors.CONFIG_OBJECT_SHOULD_BE_SECOND_PARAMETER,
|
|
531
567
|
}, state);
|
|
532
568
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
if (key.isIdentifier()) {
|
|
540
|
-
// Only allow identifiers that originated from a `const` declaration
|
|
541
|
-
const binding = key.scope.getBinding(key.node.name);
|
|
542
|
-
// TODO [#3956]: Investigate allowing imported constants
|
|
543
|
-
if (binding?.kind === 'const')
|
|
544
|
-
continue;
|
|
545
|
-
// By default, the identifier `undefined` has no binding (when it's actually undefined),
|
|
546
|
-
// but has a binding if it's used as a variable (e.g. `let undefined = "don't do this"`)
|
|
547
|
-
if (key.node.name === 'undefined' && !binding)
|
|
569
|
+
const properties = config.get('properties');
|
|
570
|
+
if (Array.isArray(properties)) {
|
|
571
|
+
for (const prop of properties) {
|
|
572
|
+
// Only validate {[computed]: true} object properties; {static: true} props are all valid
|
|
573
|
+
// and we ignore {...spreads} and {methods(){}}
|
|
574
|
+
if (!prop.isObjectProperty() || !prop.node.computed)
|
|
548
575
|
continue;
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
//
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
576
|
+
const key = prop.get('key');
|
|
577
|
+
if (key.isIdentifier()) {
|
|
578
|
+
// Only allow identifiers that originated from a `const` declaration
|
|
579
|
+
const binding = key.scope.getBinding(key.node.name);
|
|
580
|
+
// TODO [#3956]: Investigate allowing imported constants
|
|
581
|
+
if (binding?.kind === 'const')
|
|
582
|
+
continue;
|
|
583
|
+
// By default, the identifier `undefined` has no binding (when it's actually undefined),
|
|
584
|
+
// but has a binding if it's used as a variable (e.g. `let undefined = "don't do this"`)
|
|
585
|
+
if (key.node.name === 'undefined' && !binding)
|
|
586
|
+
continue;
|
|
559
587
|
}
|
|
560
|
-
else if (
|
|
561
|
-
|
|
588
|
+
else if (key.isLiteral()) {
|
|
589
|
+
// A literal can be a regexp, template literal, or primitive; only allow primitives
|
|
590
|
+
if (key.isTemplateLiteral()) {
|
|
591
|
+
// A template literal is not guaranteed to always result in the same value
|
|
592
|
+
// (e.g. `${Math.random()}`), so we disallow them entirely.
|
|
593
|
+
// TODO [#3956]: Investigate allowing template literals
|
|
594
|
+
handleError(key, {
|
|
595
|
+
errorInfo: errors.DecoratorErrors.COMPUTED_PROPERTY_CANNOT_BE_TEMPLATE_LITERAL,
|
|
596
|
+
}, state);
|
|
597
|
+
}
|
|
598
|
+
else if (!key.isRegExpLiteral()) {
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
562
601
|
}
|
|
602
|
+
handleError(key, {
|
|
603
|
+
errorInfo: errors.DecoratorErrors.COMPUTED_PROPERTY_MUST_BE_CONSTANT_OR_LITERAL,
|
|
604
|
+
}, state);
|
|
563
605
|
}
|
|
564
|
-
throw generateError(key, {
|
|
565
|
-
errorInfo: errors.DecoratorErrors.COMPUTED_PROPERTY_MUST_BE_CONSTANT_OR_LITERAL,
|
|
566
|
-
}, state);
|
|
567
606
|
}
|
|
568
607
|
}
|
|
569
608
|
function validateWireParameters(path, state) {
|
|
@@ -585,13 +624,13 @@ function validateUsageWithOtherDecorators(path, decorators, state) {
|
|
|
585
624
|
if (path !== decorator.path &&
|
|
586
625
|
decorator.name === WIRE_DECORATOR$1 &&
|
|
587
626
|
decorator.path.parentPath.node === path.parentPath.node) {
|
|
588
|
-
|
|
627
|
+
handleError(path, {
|
|
589
628
|
errorInfo: errors.DecoratorErrors.ONE_WIRE_DECORATOR_ALLOWED,
|
|
590
629
|
}, state);
|
|
591
630
|
}
|
|
592
631
|
if ((decorator.name === API_DECORATOR || decorator.name === TRACK_DECORATOR$1) &&
|
|
593
632
|
decorator.path.parentPath.node === path.parentPath.node) {
|
|
594
|
-
|
|
633
|
+
handleError(path, {
|
|
595
634
|
errorInfo: errors.DecoratorErrors.CONFLICT_WITH_ANOTHER_DECORATOR,
|
|
596
635
|
messageArgs: [decorator.name],
|
|
597
636
|
}, state);
|
|
@@ -617,15 +656,26 @@ function isObservedProperty(configProperty) {
|
|
|
617
656
|
const propertyValue = configProperty.get('value');
|
|
618
657
|
return (propertyValue.isStringLiteral() && propertyValue.node.value.startsWith(WIRE_PARAM_PREFIX));
|
|
619
658
|
}
|
|
620
|
-
function getWiredStatic(wireConfig) {
|
|
621
|
-
|
|
622
|
-
|
|
659
|
+
function getWiredStatic(wireConfig, state) {
|
|
660
|
+
const properties = wireConfig.get('properties');
|
|
661
|
+
// Should only occurs in error recovery mode when config validation has already failed
|
|
662
|
+
// Skip processing since the error has been logged upstream
|
|
663
|
+
if (isErrorRecoveryMode(state) && !Array.isArray(properties)) {
|
|
664
|
+
return [];
|
|
665
|
+
}
|
|
666
|
+
return properties
|
|
623
667
|
.filter((property) => !isObservedProperty(property))
|
|
624
668
|
.map((path) => path.node);
|
|
625
669
|
}
|
|
626
|
-
function getWiredParams(t, wireConfig) {
|
|
627
|
-
|
|
628
|
-
|
|
670
|
+
function getWiredParams(t, wireConfig, state) {
|
|
671
|
+
const properties = wireConfig.get('properties');
|
|
672
|
+
// Should only occur in error recovery mode when config validation has already failed
|
|
673
|
+
// Skip processing since the error has been logged upstream
|
|
674
|
+
if (isErrorRecoveryMode(state) && !Array.isArray(properties)) {
|
|
675
|
+
// In error recovery mode, return empty array instead of crashing
|
|
676
|
+
return [];
|
|
677
|
+
}
|
|
678
|
+
return properties
|
|
629
679
|
.filter((property) => isObservedProperty(property))
|
|
630
680
|
.map((path) => {
|
|
631
681
|
// Need to clone deep the observed property to remove the param prefix
|
|
@@ -755,7 +805,7 @@ const scopedReferenceLookup = (scope) => (name) => {
|
|
|
755
805
|
value,
|
|
756
806
|
};
|
|
757
807
|
};
|
|
758
|
-
function transform$1(t, decoratorMetas) {
|
|
808
|
+
function transform$1(t, decoratorMetas, state) {
|
|
759
809
|
const objectProperties = [];
|
|
760
810
|
const wiredValues = decoratorMetas.filter(isWireDecorator).map(({ path }) => {
|
|
761
811
|
const [id, config] = path.get('expression.arguments');
|
|
@@ -768,8 +818,8 @@ function transform$1(t, decoratorMetas) {
|
|
|
768
818
|
isClassMethod,
|
|
769
819
|
};
|
|
770
820
|
if (config) {
|
|
771
|
-
wiredValue.static = getWiredStatic(config);
|
|
772
|
-
wiredValue.params = getWiredParams(t, config);
|
|
821
|
+
wiredValue.static = getWiredStatic(config, state);
|
|
822
|
+
wiredValue.params = getWiredParams(t, config, state);
|
|
773
823
|
}
|
|
774
824
|
const referenceLookup = scopedReferenceLookup(path.scope);
|
|
775
825
|
const isMemberExpression = id.isMemberExpression();
|
|
@@ -818,7 +868,7 @@ function isTrackDecorator(decorator) {
|
|
|
818
868
|
function validate$1(decorators, state) {
|
|
819
869
|
decorators.filter(isTrackDecorator).forEach(({ path }) => {
|
|
820
870
|
if (!path.parentPath.isClassProperty()) {
|
|
821
|
-
|
|
871
|
+
handleError(path, {
|
|
822
872
|
errorInfo: errors.DecoratorErrors.TRACK_ONLY_ALLOWED_ON_CLASS_PROPERTIES,
|
|
823
873
|
}, state);
|
|
824
874
|
}
|
|
@@ -879,11 +929,14 @@ function getDecoratedNodeType(decoratorPath, state) {
|
|
|
879
929
|
else if (propertyOrMethod.isClassProperty()) {
|
|
880
930
|
return DECORATOR_TYPES.PROPERTY;
|
|
881
931
|
}
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
932
|
+
handleError(propertyOrMethod, {
|
|
933
|
+
errorInfo: errors.DecoratorErrors.INVALID_DECORATOR_TYPE,
|
|
934
|
+
}, state);
|
|
935
|
+
// We should only be here when we are running in errorRecoveryMode
|
|
936
|
+
// otherwise, the handleError method should already "throw"
|
|
937
|
+
// since, we couldn't determine a node type, we will return a null here
|
|
938
|
+
// so we can filter out this node and attempt to proceed with the compilation process
|
|
939
|
+
return null;
|
|
887
940
|
}
|
|
888
941
|
function validateImportedLwcDecoratorUsage(engineImportSpecifiers, state) {
|
|
889
942
|
engineImportSpecifiers
|
|
@@ -906,14 +959,15 @@ function validateImportedLwcDecoratorUsage(engineImportSpecifiers, state) {
|
|
|
906
959
|
? reference.parentPath
|
|
907
960
|
: reference.parentPath.parentPath;
|
|
908
961
|
if (!decorator.isDecorator()) {
|
|
909
|
-
|
|
962
|
+
handleError(decorator, {
|
|
910
963
|
errorInfo: errors.DecoratorErrors.IS_NOT_DECORATOR,
|
|
911
964
|
messageArgs: [name],
|
|
912
965
|
}, state);
|
|
913
966
|
}
|
|
914
967
|
const propertyOrMethod = decorator.parentPath;
|
|
915
|
-
if (
|
|
916
|
-
|
|
968
|
+
if (propertyOrMethod === null ||
|
|
969
|
+
(!propertyOrMethod.isClassProperty() && !propertyOrMethod.isClassMethod())) {
|
|
970
|
+
handleError(propertyOrMethod === null ? decorator : propertyOrMethod, {
|
|
917
971
|
errorInfo: errors.DecoratorErrors.IS_NOT_CLASS_PROPERTY_OR_CLASS_METHOD,
|
|
918
972
|
messageArgs: [name],
|
|
919
973
|
}, state);
|
|
@@ -933,7 +987,7 @@ function validate(decorators, state) {
|
|
|
933
987
|
for (const { name, path } of decorators) {
|
|
934
988
|
const binding = path.scope.getBinding(name);
|
|
935
989
|
if (binding === undefined || !isImportedFromLwcSource(binding.path)) {
|
|
936
|
-
|
|
990
|
+
handleInvalidDecoratorError(path, state);
|
|
937
991
|
}
|
|
938
992
|
}
|
|
939
993
|
DECORATOR_TRANSFORMS.forEach(({ validate }) => validate(decorators, state));
|
|
@@ -953,7 +1007,7 @@ function removeImportedDecoratorSpecifiers(engineImportSpecifiers) {
|
|
|
953
1007
|
}
|
|
954
1008
|
});
|
|
955
1009
|
}
|
|
956
|
-
function
|
|
1010
|
+
function handleInvalidDecoratorError(path, state) {
|
|
957
1011
|
const expressionPath = path.get('expression');
|
|
958
1012
|
const { node } = path;
|
|
959
1013
|
const { expression } = node;
|
|
@@ -965,13 +1019,13 @@ function generateInvalidDecoratorError(path, state) {
|
|
|
965
1019
|
name = expression.callee.name;
|
|
966
1020
|
}
|
|
967
1021
|
if (name) {
|
|
968
|
-
|
|
1022
|
+
handleError(path.parentPath, {
|
|
969
1023
|
errorInfo: errors.DecoratorErrors.INVALID_DECORATOR_WITH_NAME,
|
|
970
1024
|
messageArgs: [name, AVAILABLE_DECORATORS, LWC_PACKAGE_ALIAS],
|
|
971
1025
|
}, state);
|
|
972
1026
|
}
|
|
973
1027
|
else {
|
|
974
|
-
|
|
1028
|
+
handleError(path.parentPath, {
|
|
975
1029
|
errorInfo: errors.DecoratorErrors.INVALID_DECORATOR,
|
|
976
1030
|
messageArgs: [AVAILABLE_DECORATORS, LWC_PACKAGE_ALIAS],
|
|
977
1031
|
}, state);
|
|
@@ -996,7 +1050,8 @@ function getDecoratorMetadata(decoratorPath, state) {
|
|
|
996
1050
|
name = expressionPath.node.callee.name;
|
|
997
1051
|
}
|
|
998
1052
|
else {
|
|
999
|
-
|
|
1053
|
+
handleInvalidDecoratorError(decoratorPath, state);
|
|
1054
|
+
return null;
|
|
1000
1055
|
}
|
|
1001
1056
|
const propertyName = decoratorPath.parent.key.name;
|
|
1002
1057
|
const decoratedNodeType = getDecoratedNodeType(decoratorPath, state);
|
|
@@ -1007,11 +1062,11 @@ function getDecoratorMetadata(decoratorPath, state) {
|
|
|
1007
1062
|
decoratedNodeType,
|
|
1008
1063
|
};
|
|
1009
1064
|
}
|
|
1010
|
-
function getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems) {
|
|
1065
|
+
function getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems, state) {
|
|
1011
1066
|
const list = [
|
|
1012
|
-
...api.transform(t, decoratorMetas, classBodyItems),
|
|
1067
|
+
...api.transform(t, decoratorMetas, classBodyItems, state),
|
|
1013
1068
|
...track.transform(t, decoratorMetas),
|
|
1014
|
-
...wire.transform(t, decoratorMetas),
|
|
1069
|
+
...wire.transform(t, decoratorMetas, state),
|
|
1015
1070
|
];
|
|
1016
1071
|
const fieldNames = classBodyItems
|
|
1017
1072
|
.filter((field) => field.isClassProperty({ computed: false, static: false }))
|
|
@@ -1049,9 +1104,11 @@ function decorators({ types: t }) {
|
|
|
1049
1104
|
return;
|
|
1050
1105
|
}
|
|
1051
1106
|
const decoratorPaths = collectDecoratorPaths(classBodyItems);
|
|
1052
|
-
const decoratorMetas = decoratorPaths
|
|
1107
|
+
const decoratorMetas = decoratorPaths
|
|
1108
|
+
.map((path) => getDecoratorMetadata(path, state))
|
|
1109
|
+
.filter((meta) => meta !== null);
|
|
1053
1110
|
validate(decoratorMetas, state);
|
|
1054
|
-
const metaPropertyList = getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems);
|
|
1111
|
+
const metaPropertyList = getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems, state);
|
|
1055
1112
|
if (metaPropertyList.length === 0) {
|
|
1056
1113
|
return;
|
|
1057
1114
|
}
|
|
@@ -1142,7 +1199,7 @@ function getImportSource(path) {
|
|
|
1142
1199
|
}
|
|
1143
1200
|
function validateImport(sourcePath, state) {
|
|
1144
1201
|
if (!sourcePath.isStringLiteral()) {
|
|
1145
|
-
|
|
1202
|
+
handleError(sourcePath, {
|
|
1146
1203
|
errorInfo: errors.LWCClassErrors.INVALID_DYNAMIC_IMPORT_SOURCE_STRICT,
|
|
1147
1204
|
messageArgs: [String(sourcePath)],
|
|
1148
1205
|
}, state);
|
|
@@ -1289,5 +1346,5 @@ function LwcClassTransform(api) {
|
|
|
1289
1346
|
}
|
|
1290
1347
|
|
|
1291
1348
|
exports.default = LwcClassTransform;
|
|
1292
|
-
/** version: 8.
|
|
1349
|
+
/** version: 8.25.0 */
|
|
1293
1350
|
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { extname, basename } from 'path';
|
|
5
5
|
import { addNamed, addDefault } from '@babel/helper-module-imports';
|
|
6
6
|
import { getAPIVersionFromNumber, generateCustomElementTagName, DISALLOWED_PROP_SET, AMBIGUOUS_PROP_SET, isAPIFeatureEnabled, LWC_VERSION_COMMENT } from '@lwc/shared';
|
|
7
|
-
import { generateErrorMessage, DecoratorErrors, CompilerMetrics, LWCClassErrors } from '@lwc/errors';
|
|
7
|
+
import { generateCompilerDiagnostic, DiagnosticLevel, generateErrorMessage, DecoratorErrors, CompilerMetrics, LWCClassErrors } from '@lwc/errors';
|
|
8
8
|
import lineColumn from 'line-column';
|
|
9
9
|
|
|
10
10
|
/*
|
|
@@ -225,9 +225,36 @@ function generateError(source, { errorInfo, messageArgs }, state) {
|
|
|
225
225
|
error.lwcCode = errorInfo && errorInfo.code;
|
|
226
226
|
return error;
|
|
227
227
|
}
|
|
228
|
+
function collectError(source, { errorInfo, messageArgs }, state) {
|
|
229
|
+
const diagnostic = generateCompilerDiagnostic(errorInfo, {
|
|
230
|
+
messageArgs,
|
|
231
|
+
origin: {
|
|
232
|
+
filename: state.filename,
|
|
233
|
+
location: normalizeLocation(source) ?? undefined,
|
|
234
|
+
},
|
|
235
|
+
}, true);
|
|
236
|
+
if (diagnostic.level === DiagnosticLevel.Fatal) {
|
|
237
|
+
throw generateError(source, { errorInfo, messageArgs }, state);
|
|
238
|
+
}
|
|
239
|
+
if (!state.file.metadata.lwcErrors) {
|
|
240
|
+
state.file.metadata.lwcErrors = [];
|
|
241
|
+
}
|
|
242
|
+
state.file.metadata.lwcErrors.push(diagnostic);
|
|
243
|
+
}
|
|
244
|
+
function handleError(source, decoratorErrorOpts, state) {
|
|
245
|
+
if (isErrorRecoveryMode(state)) {
|
|
246
|
+
collectError(source, decoratorErrorOpts, state);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
throw generateError(source, decoratorErrorOpts, state);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
228
252
|
function incrementMetricCounter(metric, state) {
|
|
229
253
|
state.opts.instrumentation?.incrementCounter(metric);
|
|
230
254
|
}
|
|
255
|
+
function isErrorRecoveryMode(state) {
|
|
256
|
+
return state.file.opts?.parserOpts?.errorRecovery ?? false;
|
|
257
|
+
}
|
|
231
258
|
|
|
232
259
|
/*
|
|
233
260
|
* Copyright (c) 2023, salesforce.com, inc.
|
|
@@ -251,7 +278,7 @@ function validateConflict(path, decorators, state) {
|
|
|
251
278
|
const isPublicFieldTracked = decorators.some((decorator) => decorator.name === TRACK_DECORATOR$2 &&
|
|
252
279
|
decorator.path.parentPath.node === path.parentPath.node);
|
|
253
280
|
if (isPublicFieldTracked) {
|
|
254
|
-
|
|
281
|
+
handleError(path, {
|
|
255
282
|
errorInfo: DecoratorErrors.API_AND_TRACK_DECORATOR_CONFLICT,
|
|
256
283
|
}, state);
|
|
257
284
|
}
|
|
@@ -262,45 +289,45 @@ function isBooleanPropDefaultTrue(property) {
|
|
|
262
289
|
}
|
|
263
290
|
function validatePropertyValue(property, state) {
|
|
264
291
|
if (isBooleanPropDefaultTrue(property)) {
|
|
265
|
-
|
|
292
|
+
handleError(property, {
|
|
266
293
|
errorInfo: DecoratorErrors.INVALID_BOOLEAN_PUBLIC_PROPERTY,
|
|
267
294
|
}, state);
|
|
268
295
|
}
|
|
269
296
|
}
|
|
270
297
|
function validatePropertyName(property, state) {
|
|
271
298
|
if (property.node.computed) {
|
|
272
|
-
|
|
299
|
+
handleError(property, {
|
|
273
300
|
errorInfo: DecoratorErrors.PROPERTY_CANNOT_BE_COMPUTED,
|
|
274
301
|
}, state);
|
|
275
302
|
}
|
|
276
303
|
const propertyName = property.get('key.name').node;
|
|
277
304
|
if (propertyName === 'part') {
|
|
278
|
-
|
|
305
|
+
handleError(property, {
|
|
279
306
|
errorInfo: DecoratorErrors.PROPERTY_NAME_PART_IS_RESERVED,
|
|
280
307
|
messageArgs: [propertyName],
|
|
281
308
|
}, state);
|
|
282
309
|
}
|
|
283
310
|
else if (propertyName.startsWith('on')) {
|
|
284
|
-
|
|
311
|
+
handleError(property, {
|
|
285
312
|
errorInfo: DecoratorErrors.PROPERTY_NAME_CANNOT_START_WITH_ON,
|
|
286
313
|
messageArgs: [propertyName],
|
|
287
314
|
}, state);
|
|
288
315
|
}
|
|
289
316
|
else if (propertyName.startsWith('data') && propertyName.length > 4) {
|
|
290
|
-
|
|
317
|
+
handleError(property, {
|
|
291
318
|
errorInfo: DecoratorErrors.PROPERTY_NAME_CANNOT_START_WITH_DATA,
|
|
292
319
|
messageArgs: [propertyName],
|
|
293
320
|
}, state);
|
|
294
321
|
}
|
|
295
322
|
else if (DISALLOWED_PROP_SET.has(propertyName)) {
|
|
296
|
-
|
|
323
|
+
handleError(property, {
|
|
297
324
|
errorInfo: DecoratorErrors.PROPERTY_NAME_IS_RESERVED,
|
|
298
325
|
messageArgs: [propertyName],
|
|
299
326
|
}, state);
|
|
300
327
|
}
|
|
301
328
|
else if (AMBIGUOUS_PROP_SET.has(propertyName)) {
|
|
302
329
|
const camelCased = AMBIGUOUS_PROP_SET.get(propertyName);
|
|
303
|
-
|
|
330
|
+
handleError(property, {
|
|
304
331
|
errorInfo: DecoratorErrors.PROPERTY_NAME_IS_AMBIGUOUS,
|
|
305
332
|
messageArgs: [propertyName, camelCased],
|
|
306
333
|
}, state);
|
|
@@ -318,7 +345,7 @@ function validateSingleApiDecoratorOnSetterGetterPair(decorators, state) {
|
|
|
318
345
|
const methodPath = path.parentPath;
|
|
319
346
|
const methodName = methodPath.get('key.name').node;
|
|
320
347
|
if (visitedMethods.has(methodName)) {
|
|
321
|
-
|
|
348
|
+
handleError(methodPath, {
|
|
322
349
|
errorInfo: DecoratorErrors.SINGLE_DECORATOR_ON_SETTER_GETTER_PAIR,
|
|
323
350
|
messageArgs: [methodName],
|
|
324
351
|
}, state);
|
|
@@ -344,7 +371,7 @@ function validateUniqueness(decorators, state) {
|
|
|
344
371
|
compareType === DECORATOR_TYPES.SETTER) ||
|
|
345
372
|
(currentType === DECORATOR_TYPES.SETTER && compareType === DECORATOR_TYPES.GETTER);
|
|
346
373
|
if (haveSameName && isDifferentProperty && !isGetterSetterPair) {
|
|
347
|
-
|
|
374
|
+
handleError(comparePath, {
|
|
348
375
|
errorInfo: DecoratorErrors.DUPLICATE_API_PROPERTY,
|
|
349
376
|
messageArgs: [currentPropertyName],
|
|
350
377
|
}, state);
|
|
@@ -403,8 +430,12 @@ function getSiblingGetSetPairType(propertyName, type, classBodyItems) {
|
|
|
403
430
|
return siblingKind === 'get' ? DECORATOR_TYPES.GETTER : DECORATOR_TYPES.SETTER;
|
|
404
431
|
}
|
|
405
432
|
}
|
|
406
|
-
function computePublicPropsConfig(publicPropertyMetas, classBodyItems) {
|
|
433
|
+
function computePublicPropsConfig(publicPropertyMetas, classBodyItems, state) {
|
|
407
434
|
return publicPropertyMetas.reduce((acc, { propertyName, decoratedNodeType }) => {
|
|
435
|
+
// This should never happen as we filter null in class visitor and
|
|
436
|
+
// collect appropriate errors in errorRecoveryMode || throw otherwise
|
|
437
|
+
if (isErrorRecoveryMode(state) && !decoratedNodeType)
|
|
438
|
+
return acc;
|
|
408
439
|
if (!(propertyName in acc)) {
|
|
409
440
|
acc[propertyName] = {};
|
|
410
441
|
}
|
|
@@ -421,12 +452,12 @@ function computePublicPropsConfig(publicPropertyMetas, classBodyItems) {
|
|
|
421
452
|
return acc;
|
|
422
453
|
}, {});
|
|
423
454
|
}
|
|
424
|
-
function transform$2(t, decoratorMetas, classBodyItems) {
|
|
455
|
+
function transform$2(t, decoratorMetas, classBodyItems, state) {
|
|
425
456
|
const objectProperties = [];
|
|
426
457
|
const apiDecoratorMetas = decoratorMetas.filter(isApiDecorator);
|
|
427
458
|
const publicPropertyMetas = apiDecoratorMetas.filter(({ decoratedNodeType }) => decoratedNodeType !== DECORATOR_TYPES.METHOD);
|
|
428
459
|
if (publicPropertyMetas.length) {
|
|
429
|
-
const propsConfig = computePublicPropsConfig(publicPropertyMetas, classBodyItems);
|
|
460
|
+
const propsConfig = computePublicPropsConfig(publicPropertyMetas, classBodyItems, state);
|
|
430
461
|
objectProperties.push(t.objectProperty(t.identifier(PUBLIC_PROPS), t.valueToNode(propsConfig)));
|
|
431
462
|
}
|
|
432
463
|
const publicMethodMetas = apiDecoratorMetas.filter(({ decoratedNodeType }) => decoratedNodeType === DECORATOR_TYPES.METHOD);
|
|
@@ -470,9 +501,10 @@ function isWireDecorator(decorator) {
|
|
|
470
501
|
const { TRACK_DECORATOR: TRACK_DECORATOR$1, WIRE_DECORATOR: WIRE_DECORATOR$1, API_DECORATOR } = LWC_PACKAGE_EXPORTS;
|
|
471
502
|
function validateWireId(id, path, state) {
|
|
472
503
|
if (!id) {
|
|
473
|
-
|
|
504
|
+
handleError(path, {
|
|
474
505
|
errorInfo: DecoratorErrors.ADAPTER_SHOULD_BE_FIRST_PARAMETER,
|
|
475
506
|
}, state);
|
|
507
|
+
return;
|
|
476
508
|
}
|
|
477
509
|
let adapter;
|
|
478
510
|
if (id.isIdentifier()) {
|
|
@@ -482,9 +514,10 @@ function validateWireId(id, path, state) {
|
|
|
482
514
|
else if (id.isMemberExpression()) {
|
|
483
515
|
if (id.node.computed) {
|
|
484
516
|
// @wire(adapter[computed])
|
|
485
|
-
|
|
517
|
+
handleError(id, {
|
|
486
518
|
errorInfo: DecoratorErrors.FUNCTION_IDENTIFIER_CANNOT_HAVE_COMPUTED_PROPS,
|
|
487
519
|
}, state);
|
|
520
|
+
return;
|
|
488
521
|
}
|
|
489
522
|
const object = id.get('object');
|
|
490
523
|
if (object.isIdentifier()) {
|
|
@@ -493,73 +526,79 @@ function validateWireId(id, path, state) {
|
|
|
493
526
|
}
|
|
494
527
|
else {
|
|
495
528
|
// @wire(adapter.foo.bar)
|
|
496
|
-
|
|
529
|
+
handleError(id, {
|
|
497
530
|
errorInfo: DecoratorErrors.FUNCTION_IDENTIFIER_CANNOT_HAVE_NESTED_MEMBER_EXRESSIONS,
|
|
498
531
|
}, state);
|
|
532
|
+
return;
|
|
499
533
|
}
|
|
500
534
|
}
|
|
501
535
|
else {
|
|
502
536
|
// @wire(1), @wire('adapter'), @wire(function adapter() {}), etc.
|
|
503
|
-
|
|
537
|
+
handleError(id, {
|
|
504
538
|
errorInfo: DecoratorErrors.FUNCTION_IDENTIFIER_SHOULD_BE_FIRST_PARAMETER,
|
|
505
539
|
}, state);
|
|
540
|
+
return;
|
|
506
541
|
}
|
|
507
542
|
// Ensure wire adapter is imported (check for member expression or identifier)
|
|
508
543
|
const adapterBinding = path.scope.getBinding(adapter.node.name);
|
|
509
544
|
if (!adapterBinding) {
|
|
510
|
-
|
|
545
|
+
handleError(id, {
|
|
511
546
|
errorInfo: DecoratorErrors.WIRE_ADAPTER_SHOULD_BE_IMPORTED,
|
|
512
547
|
messageArgs: [adapter.node.name],
|
|
513
548
|
}, state);
|
|
549
|
+
return;
|
|
514
550
|
}
|
|
515
551
|
// ensure wire adapter is a first parameter
|
|
516
552
|
if (!adapterBinding.path.isImportSpecifier() &&
|
|
517
553
|
!adapterBinding.path.isImportDefaultSpecifier()) {
|
|
518
|
-
|
|
554
|
+
handleError(id, {
|
|
519
555
|
errorInfo: DecoratorErrors.IMPORTED_FUNCTION_IDENTIFIER_SHOULD_BE_FIRST_PARAMETER,
|
|
520
556
|
}, state);
|
|
521
557
|
}
|
|
522
558
|
}
|
|
523
559
|
function validateWireConfig(config, path, state) {
|
|
524
560
|
if (!config.isObjectExpression()) {
|
|
525
|
-
|
|
561
|
+
handleError(config, {
|
|
526
562
|
errorInfo: DecoratorErrors.CONFIG_OBJECT_SHOULD_BE_SECOND_PARAMETER,
|
|
527
563
|
}, state);
|
|
528
564
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
if (key.isIdentifier()) {
|
|
536
|
-
// Only allow identifiers that originated from a `const` declaration
|
|
537
|
-
const binding = key.scope.getBinding(key.node.name);
|
|
538
|
-
// TODO [#3956]: Investigate allowing imported constants
|
|
539
|
-
if (binding?.kind === 'const')
|
|
540
|
-
continue;
|
|
541
|
-
// By default, the identifier `undefined` has no binding (when it's actually undefined),
|
|
542
|
-
// but has a binding if it's used as a variable (e.g. `let undefined = "don't do this"`)
|
|
543
|
-
if (key.node.name === 'undefined' && !binding)
|
|
565
|
+
const properties = config.get('properties');
|
|
566
|
+
if (Array.isArray(properties)) {
|
|
567
|
+
for (const prop of properties) {
|
|
568
|
+
// Only validate {[computed]: true} object properties; {static: true} props are all valid
|
|
569
|
+
// and we ignore {...spreads} and {methods(){}}
|
|
570
|
+
if (!prop.isObjectProperty() || !prop.node.computed)
|
|
544
571
|
continue;
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
//
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
572
|
+
const key = prop.get('key');
|
|
573
|
+
if (key.isIdentifier()) {
|
|
574
|
+
// Only allow identifiers that originated from a `const` declaration
|
|
575
|
+
const binding = key.scope.getBinding(key.node.name);
|
|
576
|
+
// TODO [#3956]: Investigate allowing imported constants
|
|
577
|
+
if (binding?.kind === 'const')
|
|
578
|
+
continue;
|
|
579
|
+
// By default, the identifier `undefined` has no binding (when it's actually undefined),
|
|
580
|
+
// but has a binding if it's used as a variable (e.g. `let undefined = "don't do this"`)
|
|
581
|
+
if (key.node.name === 'undefined' && !binding)
|
|
582
|
+
continue;
|
|
555
583
|
}
|
|
556
|
-
else if (
|
|
557
|
-
|
|
584
|
+
else if (key.isLiteral()) {
|
|
585
|
+
// A literal can be a regexp, template literal, or primitive; only allow primitives
|
|
586
|
+
if (key.isTemplateLiteral()) {
|
|
587
|
+
// A template literal is not guaranteed to always result in the same value
|
|
588
|
+
// (e.g. `${Math.random()}`), so we disallow them entirely.
|
|
589
|
+
// TODO [#3956]: Investigate allowing template literals
|
|
590
|
+
handleError(key, {
|
|
591
|
+
errorInfo: DecoratorErrors.COMPUTED_PROPERTY_CANNOT_BE_TEMPLATE_LITERAL,
|
|
592
|
+
}, state);
|
|
593
|
+
}
|
|
594
|
+
else if (!key.isRegExpLiteral()) {
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
558
597
|
}
|
|
598
|
+
handleError(key, {
|
|
599
|
+
errorInfo: DecoratorErrors.COMPUTED_PROPERTY_MUST_BE_CONSTANT_OR_LITERAL,
|
|
600
|
+
}, state);
|
|
559
601
|
}
|
|
560
|
-
throw generateError(key, {
|
|
561
|
-
errorInfo: DecoratorErrors.COMPUTED_PROPERTY_MUST_BE_CONSTANT_OR_LITERAL,
|
|
562
|
-
}, state);
|
|
563
602
|
}
|
|
564
603
|
}
|
|
565
604
|
function validateWireParameters(path, state) {
|
|
@@ -581,13 +620,13 @@ function validateUsageWithOtherDecorators(path, decorators, state) {
|
|
|
581
620
|
if (path !== decorator.path &&
|
|
582
621
|
decorator.name === WIRE_DECORATOR$1 &&
|
|
583
622
|
decorator.path.parentPath.node === path.parentPath.node) {
|
|
584
|
-
|
|
623
|
+
handleError(path, {
|
|
585
624
|
errorInfo: DecoratorErrors.ONE_WIRE_DECORATOR_ALLOWED,
|
|
586
625
|
}, state);
|
|
587
626
|
}
|
|
588
627
|
if ((decorator.name === API_DECORATOR || decorator.name === TRACK_DECORATOR$1) &&
|
|
589
628
|
decorator.path.parentPath.node === path.parentPath.node) {
|
|
590
|
-
|
|
629
|
+
handleError(path, {
|
|
591
630
|
errorInfo: DecoratorErrors.CONFLICT_WITH_ANOTHER_DECORATOR,
|
|
592
631
|
messageArgs: [decorator.name],
|
|
593
632
|
}, state);
|
|
@@ -613,15 +652,26 @@ function isObservedProperty(configProperty) {
|
|
|
613
652
|
const propertyValue = configProperty.get('value');
|
|
614
653
|
return (propertyValue.isStringLiteral() && propertyValue.node.value.startsWith(WIRE_PARAM_PREFIX));
|
|
615
654
|
}
|
|
616
|
-
function getWiredStatic(wireConfig) {
|
|
617
|
-
|
|
618
|
-
|
|
655
|
+
function getWiredStatic(wireConfig, state) {
|
|
656
|
+
const properties = wireConfig.get('properties');
|
|
657
|
+
// Should only occurs in error recovery mode when config validation has already failed
|
|
658
|
+
// Skip processing since the error has been logged upstream
|
|
659
|
+
if (isErrorRecoveryMode(state) && !Array.isArray(properties)) {
|
|
660
|
+
return [];
|
|
661
|
+
}
|
|
662
|
+
return properties
|
|
619
663
|
.filter((property) => !isObservedProperty(property))
|
|
620
664
|
.map((path) => path.node);
|
|
621
665
|
}
|
|
622
|
-
function getWiredParams(t, wireConfig) {
|
|
623
|
-
|
|
624
|
-
|
|
666
|
+
function getWiredParams(t, wireConfig, state) {
|
|
667
|
+
const properties = wireConfig.get('properties');
|
|
668
|
+
// Should only occur in error recovery mode when config validation has already failed
|
|
669
|
+
// Skip processing since the error has been logged upstream
|
|
670
|
+
if (isErrorRecoveryMode(state) && !Array.isArray(properties)) {
|
|
671
|
+
// In error recovery mode, return empty array instead of crashing
|
|
672
|
+
return [];
|
|
673
|
+
}
|
|
674
|
+
return properties
|
|
625
675
|
.filter((property) => isObservedProperty(property))
|
|
626
676
|
.map((path) => {
|
|
627
677
|
// Need to clone deep the observed property to remove the param prefix
|
|
@@ -751,7 +801,7 @@ const scopedReferenceLookup = (scope) => (name) => {
|
|
|
751
801
|
value,
|
|
752
802
|
};
|
|
753
803
|
};
|
|
754
|
-
function transform$1(t, decoratorMetas) {
|
|
804
|
+
function transform$1(t, decoratorMetas, state) {
|
|
755
805
|
const objectProperties = [];
|
|
756
806
|
const wiredValues = decoratorMetas.filter(isWireDecorator).map(({ path }) => {
|
|
757
807
|
const [id, config] = path.get('expression.arguments');
|
|
@@ -764,8 +814,8 @@ function transform$1(t, decoratorMetas) {
|
|
|
764
814
|
isClassMethod,
|
|
765
815
|
};
|
|
766
816
|
if (config) {
|
|
767
|
-
wiredValue.static = getWiredStatic(config);
|
|
768
|
-
wiredValue.params = getWiredParams(t, config);
|
|
817
|
+
wiredValue.static = getWiredStatic(config, state);
|
|
818
|
+
wiredValue.params = getWiredParams(t, config, state);
|
|
769
819
|
}
|
|
770
820
|
const referenceLookup = scopedReferenceLookup(path.scope);
|
|
771
821
|
const isMemberExpression = id.isMemberExpression();
|
|
@@ -814,7 +864,7 @@ function isTrackDecorator(decorator) {
|
|
|
814
864
|
function validate$1(decorators, state) {
|
|
815
865
|
decorators.filter(isTrackDecorator).forEach(({ path }) => {
|
|
816
866
|
if (!path.parentPath.isClassProperty()) {
|
|
817
|
-
|
|
867
|
+
handleError(path, {
|
|
818
868
|
errorInfo: DecoratorErrors.TRACK_ONLY_ALLOWED_ON_CLASS_PROPERTIES,
|
|
819
869
|
}, state);
|
|
820
870
|
}
|
|
@@ -875,11 +925,14 @@ function getDecoratedNodeType(decoratorPath, state) {
|
|
|
875
925
|
else if (propertyOrMethod.isClassProperty()) {
|
|
876
926
|
return DECORATOR_TYPES.PROPERTY;
|
|
877
927
|
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
928
|
+
handleError(propertyOrMethod, {
|
|
929
|
+
errorInfo: DecoratorErrors.INVALID_DECORATOR_TYPE,
|
|
930
|
+
}, state);
|
|
931
|
+
// We should only be here when we are running in errorRecoveryMode
|
|
932
|
+
// otherwise, the handleError method should already "throw"
|
|
933
|
+
// since, we couldn't determine a node type, we will return a null here
|
|
934
|
+
// so we can filter out this node and attempt to proceed with the compilation process
|
|
935
|
+
return null;
|
|
883
936
|
}
|
|
884
937
|
function validateImportedLwcDecoratorUsage(engineImportSpecifiers, state) {
|
|
885
938
|
engineImportSpecifiers
|
|
@@ -902,14 +955,15 @@ function validateImportedLwcDecoratorUsage(engineImportSpecifiers, state) {
|
|
|
902
955
|
? reference.parentPath
|
|
903
956
|
: reference.parentPath.parentPath;
|
|
904
957
|
if (!decorator.isDecorator()) {
|
|
905
|
-
|
|
958
|
+
handleError(decorator, {
|
|
906
959
|
errorInfo: DecoratorErrors.IS_NOT_DECORATOR,
|
|
907
960
|
messageArgs: [name],
|
|
908
961
|
}, state);
|
|
909
962
|
}
|
|
910
963
|
const propertyOrMethod = decorator.parentPath;
|
|
911
|
-
if (
|
|
912
|
-
|
|
964
|
+
if (propertyOrMethod === null ||
|
|
965
|
+
(!propertyOrMethod.isClassProperty() && !propertyOrMethod.isClassMethod())) {
|
|
966
|
+
handleError(propertyOrMethod === null ? decorator : propertyOrMethod, {
|
|
913
967
|
errorInfo: DecoratorErrors.IS_NOT_CLASS_PROPERTY_OR_CLASS_METHOD,
|
|
914
968
|
messageArgs: [name],
|
|
915
969
|
}, state);
|
|
@@ -929,7 +983,7 @@ function validate(decorators, state) {
|
|
|
929
983
|
for (const { name, path } of decorators) {
|
|
930
984
|
const binding = path.scope.getBinding(name);
|
|
931
985
|
if (binding === undefined || !isImportedFromLwcSource(binding.path)) {
|
|
932
|
-
|
|
986
|
+
handleInvalidDecoratorError(path, state);
|
|
933
987
|
}
|
|
934
988
|
}
|
|
935
989
|
DECORATOR_TRANSFORMS.forEach(({ validate }) => validate(decorators, state));
|
|
@@ -949,7 +1003,7 @@ function removeImportedDecoratorSpecifiers(engineImportSpecifiers) {
|
|
|
949
1003
|
}
|
|
950
1004
|
});
|
|
951
1005
|
}
|
|
952
|
-
function
|
|
1006
|
+
function handleInvalidDecoratorError(path, state) {
|
|
953
1007
|
const expressionPath = path.get('expression');
|
|
954
1008
|
const { node } = path;
|
|
955
1009
|
const { expression } = node;
|
|
@@ -961,13 +1015,13 @@ function generateInvalidDecoratorError(path, state) {
|
|
|
961
1015
|
name = expression.callee.name;
|
|
962
1016
|
}
|
|
963
1017
|
if (name) {
|
|
964
|
-
|
|
1018
|
+
handleError(path.parentPath, {
|
|
965
1019
|
errorInfo: DecoratorErrors.INVALID_DECORATOR_WITH_NAME,
|
|
966
1020
|
messageArgs: [name, AVAILABLE_DECORATORS, LWC_PACKAGE_ALIAS],
|
|
967
1021
|
}, state);
|
|
968
1022
|
}
|
|
969
1023
|
else {
|
|
970
|
-
|
|
1024
|
+
handleError(path.parentPath, {
|
|
971
1025
|
errorInfo: DecoratorErrors.INVALID_DECORATOR,
|
|
972
1026
|
messageArgs: [AVAILABLE_DECORATORS, LWC_PACKAGE_ALIAS],
|
|
973
1027
|
}, state);
|
|
@@ -992,7 +1046,8 @@ function getDecoratorMetadata(decoratorPath, state) {
|
|
|
992
1046
|
name = expressionPath.node.callee.name;
|
|
993
1047
|
}
|
|
994
1048
|
else {
|
|
995
|
-
|
|
1049
|
+
handleInvalidDecoratorError(decoratorPath, state);
|
|
1050
|
+
return null;
|
|
996
1051
|
}
|
|
997
1052
|
const propertyName = decoratorPath.parent.key.name;
|
|
998
1053
|
const decoratedNodeType = getDecoratedNodeType(decoratorPath, state);
|
|
@@ -1003,11 +1058,11 @@ function getDecoratorMetadata(decoratorPath, state) {
|
|
|
1003
1058
|
decoratedNodeType,
|
|
1004
1059
|
};
|
|
1005
1060
|
}
|
|
1006
|
-
function getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems) {
|
|
1061
|
+
function getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems, state) {
|
|
1007
1062
|
const list = [
|
|
1008
|
-
...api.transform(t, decoratorMetas, classBodyItems),
|
|
1063
|
+
...api.transform(t, decoratorMetas, classBodyItems, state),
|
|
1009
1064
|
...track.transform(t, decoratorMetas),
|
|
1010
|
-
...wire.transform(t, decoratorMetas),
|
|
1065
|
+
...wire.transform(t, decoratorMetas, state),
|
|
1011
1066
|
];
|
|
1012
1067
|
const fieldNames = classBodyItems
|
|
1013
1068
|
.filter((field) => field.isClassProperty({ computed: false, static: false }))
|
|
@@ -1045,9 +1100,11 @@ function decorators({ types: t }) {
|
|
|
1045
1100
|
return;
|
|
1046
1101
|
}
|
|
1047
1102
|
const decoratorPaths = collectDecoratorPaths(classBodyItems);
|
|
1048
|
-
const decoratorMetas = decoratorPaths
|
|
1103
|
+
const decoratorMetas = decoratorPaths
|
|
1104
|
+
.map((path) => getDecoratorMetadata(path, state))
|
|
1105
|
+
.filter((meta) => meta !== null);
|
|
1049
1106
|
validate(decoratorMetas, state);
|
|
1050
|
-
const metaPropertyList = getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems);
|
|
1107
|
+
const metaPropertyList = getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems, state);
|
|
1051
1108
|
if (metaPropertyList.length === 0) {
|
|
1052
1109
|
return;
|
|
1053
1110
|
}
|
|
@@ -1138,7 +1195,7 @@ function getImportSource(path) {
|
|
|
1138
1195
|
}
|
|
1139
1196
|
function validateImport(sourcePath, state) {
|
|
1140
1197
|
if (!sourcePath.isStringLiteral()) {
|
|
1141
|
-
|
|
1198
|
+
handleError(sourcePath, {
|
|
1142
1199
|
errorInfo: LWCClassErrors.INVALID_DYNAMIC_IMPORT_SOURCE_STRICT,
|
|
1143
1200
|
messageArgs: [String(sourcePath)],
|
|
1144
1201
|
}, state);
|
|
@@ -1285,5 +1342,5 @@ function LwcClassTransform(api) {
|
|
|
1285
1342
|
}
|
|
1286
1343
|
|
|
1287
1344
|
export { LwcClassTransform as default };
|
|
1288
|
-
/** version: 8.
|
|
1345
|
+
/** version: 8.25.0 */
|
|
1289
1346
|
//# sourceMappingURL=index.js.map
|
package/dist/utils.d.ts
CHANGED
|
@@ -18,7 +18,8 @@ declare function isSetterClassMethod(classMethod: NodePath<types.Node>, properti
|
|
|
18
18
|
static?: boolean;
|
|
19
19
|
}): classMethod is NodePath<types.ClassMethod>;
|
|
20
20
|
declare function getEngineImportSpecifiers(path: NodePath): ImportSpecifier[];
|
|
21
|
-
declare function
|
|
21
|
+
declare function handleError(source: NodePath<types.Node>, decoratorErrorOpts: DecoratorErrorOptions, state: LwcBabelPluginPass): void;
|
|
22
22
|
declare function incrementMetricCounter(metric: CompilerMetrics, state: LwcBabelPluginPass): void;
|
|
23
|
-
|
|
23
|
+
declare function isErrorRecoveryMode(state: LwcBabelPluginPass): boolean;
|
|
24
|
+
export { isClassMethod, isGetterClassMethod, isSetterClassMethod, getEngineImportSpecifiers, handleError, incrementMetricCounter, isErrorRecoveryMode, };
|
|
24
25
|
//# sourceMappingURL=utils.d.ts.map
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"You can safely modify dependencies, devDependencies, keywords, etc., but other props will be overwritten."
|
|
5
5
|
],
|
|
6
6
|
"name": "@lwc/babel-plugin-component",
|
|
7
|
-
"version": "8.
|
|
7
|
+
"version": "8.25.0",
|
|
8
8
|
"description": "Babel plugin to transform a LWC module",
|
|
9
9
|
"keywords": [
|
|
10
10
|
"lwc"
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@babel/helper-module-imports": "7.27.1",
|
|
50
|
-
"@lwc/errors": "8.
|
|
51
|
-
"@lwc/shared": "8.
|
|
50
|
+
"@lwc/errors": "8.25.0",
|
|
51
|
+
"@lwc/shared": "8.25.0",
|
|
52
52
|
"line-column": "~1.0.2"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|