@lwc/babel-plugin-component 8.23.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.
@@ -24,5 +24,6 @@ declare const COMPONENT_NAME_KEY = "sel";
24
24
  declare const API_VERSION_KEY = "apiVersion";
25
25
  declare const COMPONENT_CLASS_ID = "__lwc_component_class_internal";
26
26
  declare const SYNTHETIC_ELEMENT_INTERNALS_KEY = "enableSyntheticElementInternals";
27
- export { DECORATOR_TYPES, LWC_PACKAGE_ALIAS, LWC_PACKAGE_EXPORTS, LWC_COMPONENT_PROPERTIES, REGISTER_COMPONENT_ID, REGISTER_DECORATORS_ID, TEMPLATE_KEY, COMPONENT_NAME_KEY, API_VERSION_KEY, COMPONENT_CLASS_ID, SYNTHETIC_ELEMENT_INTERNALS_KEY, };
27
+ declare const COMPONENT_FEATURE_FLAG_KEY = "componentFeatureFlag";
28
+ export { DECORATOR_TYPES, LWC_PACKAGE_ALIAS, LWC_PACKAGE_EXPORTS, LWC_COMPONENT_PROPERTIES, REGISTER_COMPONENT_ID, REGISTER_DECORATORS_ID, TEMPLATE_KEY, COMPONENT_NAME_KEY, API_VERSION_KEY, COMPONENT_CLASS_ID, SYNTHETIC_ELEMENT_INTERNALS_KEY, COMPONENT_FEATURE_FLAG_KEY, };
28
29
  //# sourceMappingURL=constants.d.ts.map
@@ -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
@@ -42,6 +42,7 @@ const COMPONENT_NAME_KEY = 'sel';
42
42
  const API_VERSION_KEY = 'apiVersion';
43
43
  const COMPONENT_CLASS_ID = '__lwc_component_class_internal';
44
44
  const SYNTHETIC_ELEMENT_INTERNALS_KEY = 'enableSyntheticElementInternals';
45
+ const COMPONENT_FEATURE_FLAG_KEY = 'componentFeatureFlag';
45
46
 
46
47
  /*
47
48
  * Copyright (c) 2023, salesforce.com, inc.
@@ -75,6 +76,13 @@ function component ({ types: t }) {
75
76
  function createRegisterComponent(declarationPath, state) {
76
77
  const registerComponentId = helperModuleImports.addNamed(declarationPath, REGISTER_COMPONENT_ID, LWC_PACKAGE_ALIAS);
77
78
  const templateIdentifier = importDefaultTemplate(declarationPath, state);
79
+ // Optionally import feature flag module if provided via compiler options
80
+ let componentFeatureFlagIdentifier;
81
+ if (state.opts.componentFeatureFlagModulePath) {
82
+ componentFeatureFlagIdentifier = helperModuleImports.addDefault(declarationPath, state.opts.componentFeatureFlagModulePath, {
83
+ nameHint: COMPONENT_FEATURE_FLAG_KEY,
84
+ });
85
+ }
78
86
  const statementPath = declarationPath.getStatementParent();
79
87
  const componentRegisteredName = getComponentRegisteredName(t, state);
80
88
  let node = declarationPath.node;
@@ -103,6 +111,14 @@ function component ({ types: t }) {
103
111
  // The client needs to trust the server that it's providing an actual known API version
104
112
  t.objectProperty(t.identifier(API_VERSION_KEY), t.numericLiteral(apiVersion)),
105
113
  ];
114
+ if (componentFeatureFlagIdentifier) {
115
+ properties.push(t.objectProperty(t.identifier(COMPONENT_FEATURE_FLAG_KEY), t.objectExpression([
116
+ t.objectProperty(t.identifier('value'), t.callExpression(t.identifier('Boolean'), [
117
+ componentFeatureFlagIdentifier,
118
+ ])),
119
+ t.objectProperty(t.identifier('path'), t.stringLiteral(state.opts.componentFeatureFlagModulePath)),
120
+ ])));
121
+ }
106
122
  // Only include enableSyntheticElementInternals if set to true
107
123
  if (state.opts.enableSyntheticElementInternals === true) {
108
124
  properties.push(t.objectProperty(t.identifier(SYNTHETIC_ELEMENT_INTERNALS_KEY), t.booleanLiteral(true)));
@@ -213,9 +229,36 @@ function generateError(source, { errorInfo, messageArgs }, state) {
213
229
  error.lwcCode = errorInfo && errorInfo.code;
214
230
  return error;
215
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
+ }
216
256
  function incrementMetricCounter(metric, state) {
217
257
  state.opts.instrumentation?.incrementCounter(metric);
218
258
  }
259
+ function isErrorRecoveryMode(state) {
260
+ return state.file.opts?.parserOpts?.errorRecovery ?? false;
261
+ }
219
262
 
220
263
  /*
221
264
  * Copyright (c) 2023, salesforce.com, inc.
@@ -239,7 +282,7 @@ function validateConflict(path, decorators, state) {
239
282
  const isPublicFieldTracked = decorators.some((decorator) => decorator.name === TRACK_DECORATOR$2 &&
240
283
  decorator.path.parentPath.node === path.parentPath.node);
241
284
  if (isPublicFieldTracked) {
242
- throw generateError(path, {
285
+ handleError(path, {
243
286
  errorInfo: errors.DecoratorErrors.API_AND_TRACK_DECORATOR_CONFLICT,
244
287
  }, state);
245
288
  }
@@ -250,45 +293,45 @@ function isBooleanPropDefaultTrue(property) {
250
293
  }
251
294
  function validatePropertyValue(property, state) {
252
295
  if (isBooleanPropDefaultTrue(property)) {
253
- throw generateError(property, {
296
+ handleError(property, {
254
297
  errorInfo: errors.DecoratorErrors.INVALID_BOOLEAN_PUBLIC_PROPERTY,
255
298
  }, state);
256
299
  }
257
300
  }
258
301
  function validatePropertyName(property, state) {
259
302
  if (property.node.computed) {
260
- throw generateError(property, {
303
+ handleError(property, {
261
304
  errorInfo: errors.DecoratorErrors.PROPERTY_CANNOT_BE_COMPUTED,
262
305
  }, state);
263
306
  }
264
307
  const propertyName = property.get('key.name').node;
265
308
  if (propertyName === 'part') {
266
- throw generateError(property, {
309
+ handleError(property, {
267
310
  errorInfo: errors.DecoratorErrors.PROPERTY_NAME_PART_IS_RESERVED,
268
311
  messageArgs: [propertyName],
269
312
  }, state);
270
313
  }
271
314
  else if (propertyName.startsWith('on')) {
272
- throw generateError(property, {
315
+ handleError(property, {
273
316
  errorInfo: errors.DecoratorErrors.PROPERTY_NAME_CANNOT_START_WITH_ON,
274
317
  messageArgs: [propertyName],
275
318
  }, state);
276
319
  }
277
320
  else if (propertyName.startsWith('data') && propertyName.length > 4) {
278
- throw generateError(property, {
321
+ handleError(property, {
279
322
  errorInfo: errors.DecoratorErrors.PROPERTY_NAME_CANNOT_START_WITH_DATA,
280
323
  messageArgs: [propertyName],
281
324
  }, state);
282
325
  }
283
326
  else if (shared.DISALLOWED_PROP_SET.has(propertyName)) {
284
- throw generateError(property, {
327
+ handleError(property, {
285
328
  errorInfo: errors.DecoratorErrors.PROPERTY_NAME_IS_RESERVED,
286
329
  messageArgs: [propertyName],
287
330
  }, state);
288
331
  }
289
332
  else if (shared.AMBIGUOUS_PROP_SET.has(propertyName)) {
290
333
  const camelCased = shared.AMBIGUOUS_PROP_SET.get(propertyName);
291
- throw generateError(property, {
334
+ handleError(property, {
292
335
  errorInfo: errors.DecoratorErrors.PROPERTY_NAME_IS_AMBIGUOUS,
293
336
  messageArgs: [propertyName, camelCased],
294
337
  }, state);
@@ -306,7 +349,7 @@ function validateSingleApiDecoratorOnSetterGetterPair(decorators, state) {
306
349
  const methodPath = path.parentPath;
307
350
  const methodName = methodPath.get('key.name').node;
308
351
  if (visitedMethods.has(methodName)) {
309
- throw generateError(methodPath, {
352
+ handleError(methodPath, {
310
353
  errorInfo: errors.DecoratorErrors.SINGLE_DECORATOR_ON_SETTER_GETTER_PAIR,
311
354
  messageArgs: [methodName],
312
355
  }, state);
@@ -332,7 +375,7 @@ function validateUniqueness(decorators, state) {
332
375
  compareType === DECORATOR_TYPES.SETTER) ||
333
376
  (currentType === DECORATOR_TYPES.SETTER && compareType === DECORATOR_TYPES.GETTER);
334
377
  if (haveSameName && isDifferentProperty && !isGetterSetterPair) {
335
- throw generateError(comparePath, {
378
+ handleError(comparePath, {
336
379
  errorInfo: errors.DecoratorErrors.DUPLICATE_API_PROPERTY,
337
380
  messageArgs: [currentPropertyName],
338
381
  }, state);
@@ -391,8 +434,12 @@ function getSiblingGetSetPairType(propertyName, type, classBodyItems) {
391
434
  return siblingKind === 'get' ? DECORATOR_TYPES.GETTER : DECORATOR_TYPES.SETTER;
392
435
  }
393
436
  }
394
- function computePublicPropsConfig(publicPropertyMetas, classBodyItems) {
437
+ function computePublicPropsConfig(publicPropertyMetas, classBodyItems, state) {
395
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;
396
443
  if (!(propertyName in acc)) {
397
444
  acc[propertyName] = {};
398
445
  }
@@ -409,12 +456,12 @@ function computePublicPropsConfig(publicPropertyMetas, classBodyItems) {
409
456
  return acc;
410
457
  }, {});
411
458
  }
412
- function transform$2(t, decoratorMetas, classBodyItems) {
459
+ function transform$2(t, decoratorMetas, classBodyItems, state) {
413
460
  const objectProperties = [];
414
461
  const apiDecoratorMetas = decoratorMetas.filter(isApiDecorator);
415
462
  const publicPropertyMetas = apiDecoratorMetas.filter(({ decoratedNodeType }) => decoratedNodeType !== DECORATOR_TYPES.METHOD);
416
463
  if (publicPropertyMetas.length) {
417
- const propsConfig = computePublicPropsConfig(publicPropertyMetas, classBodyItems);
464
+ const propsConfig = computePublicPropsConfig(publicPropertyMetas, classBodyItems, state);
418
465
  objectProperties.push(t.objectProperty(t.identifier(PUBLIC_PROPS), t.valueToNode(propsConfig)));
419
466
  }
420
467
  const publicMethodMetas = apiDecoratorMetas.filter(({ decoratedNodeType }) => decoratedNodeType === DECORATOR_TYPES.METHOD);
@@ -458,9 +505,10 @@ function isWireDecorator(decorator) {
458
505
  const { TRACK_DECORATOR: TRACK_DECORATOR$1, WIRE_DECORATOR: WIRE_DECORATOR$1, API_DECORATOR } = LWC_PACKAGE_EXPORTS;
459
506
  function validateWireId(id, path, state) {
460
507
  if (!id) {
461
- throw generateError(path, {
508
+ handleError(path, {
462
509
  errorInfo: errors.DecoratorErrors.ADAPTER_SHOULD_BE_FIRST_PARAMETER,
463
510
  }, state);
511
+ return;
464
512
  }
465
513
  let adapter;
466
514
  if (id.isIdentifier()) {
@@ -470,9 +518,10 @@ function validateWireId(id, path, state) {
470
518
  else if (id.isMemberExpression()) {
471
519
  if (id.node.computed) {
472
520
  // @wire(adapter[computed])
473
- throw generateError(id, {
521
+ handleError(id, {
474
522
  errorInfo: errors.DecoratorErrors.FUNCTION_IDENTIFIER_CANNOT_HAVE_COMPUTED_PROPS,
475
523
  }, state);
524
+ return;
476
525
  }
477
526
  const object = id.get('object');
478
527
  if (object.isIdentifier()) {
@@ -481,73 +530,79 @@ function validateWireId(id, path, state) {
481
530
  }
482
531
  else {
483
532
  // @wire(adapter.foo.bar)
484
- throw generateError(id, {
533
+ handleError(id, {
485
534
  errorInfo: errors.DecoratorErrors.FUNCTION_IDENTIFIER_CANNOT_HAVE_NESTED_MEMBER_EXRESSIONS,
486
535
  }, state);
536
+ return;
487
537
  }
488
538
  }
489
539
  else {
490
540
  // @wire(1), @wire('adapter'), @wire(function adapter() {}), etc.
491
- throw generateError(id, {
541
+ handleError(id, {
492
542
  errorInfo: errors.DecoratorErrors.FUNCTION_IDENTIFIER_SHOULD_BE_FIRST_PARAMETER,
493
543
  }, state);
544
+ return;
494
545
  }
495
546
  // Ensure wire adapter is imported (check for member expression or identifier)
496
547
  const adapterBinding = path.scope.getBinding(adapter.node.name);
497
548
  if (!adapterBinding) {
498
- throw generateError(id, {
549
+ handleError(id, {
499
550
  errorInfo: errors.DecoratorErrors.WIRE_ADAPTER_SHOULD_BE_IMPORTED,
500
551
  messageArgs: [adapter.node.name],
501
552
  }, state);
553
+ return;
502
554
  }
503
555
  // ensure wire adapter is a first parameter
504
556
  if (!adapterBinding.path.isImportSpecifier() &&
505
557
  !adapterBinding.path.isImportDefaultSpecifier()) {
506
- throw generateError(id, {
558
+ handleError(id, {
507
559
  errorInfo: errors.DecoratorErrors.IMPORTED_FUNCTION_IDENTIFIER_SHOULD_BE_FIRST_PARAMETER,
508
560
  }, state);
509
561
  }
510
562
  }
511
563
  function validateWireConfig(config, path, state) {
512
564
  if (!config.isObjectExpression()) {
513
- throw generateError(config, {
565
+ handleError(config, {
514
566
  errorInfo: errors.DecoratorErrors.CONFIG_OBJECT_SHOULD_BE_SECOND_PARAMETER,
515
567
  }, state);
516
568
  }
517
- for (const prop of config.get('properties')) {
518
- // Only validate {[computed]: true} object properties; {static: true} props are all valid
519
- // and we ignore {...spreads} and {methods(){}}
520
- if (!prop.isObjectProperty() || !prop.node.computed)
521
- continue;
522
- const key = prop.get('key');
523
- if (key.isIdentifier()) {
524
- // Only allow identifiers that originated from a `const` declaration
525
- const binding = key.scope.getBinding(key.node.name);
526
- // TODO [#3956]: Investigate allowing imported constants
527
- if (binding?.kind === 'const')
528
- continue;
529
- // By default, the identifier `undefined` has no binding (when it's actually undefined),
530
- // but has a binding if it's used as a variable (e.g. `let undefined = "don't do this"`)
531
- 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)
532
575
  continue;
533
- }
534
- else if (key.isLiteral()) {
535
- // A literal can be a regexp, template literal, or primitive; only allow primitives
536
- if (key.isTemplateLiteral()) {
537
- // A template literal is not guaranteed to always result in the same value
538
- // (e.g. `${Math.random()}`), so we disallow them entirely.
539
- // TODO [#3956]: Investigate allowing template literals
540
- throw generateError(key, {
541
- errorInfo: errors.DecoratorErrors.COMPUTED_PROPERTY_CANNOT_BE_TEMPLATE_LITERAL,
542
- }, state);
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;
543
587
  }
544
- else if (!key.isRegExpLiteral()) {
545
- continue;
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
+ }
546
601
  }
602
+ handleError(key, {
603
+ errorInfo: errors.DecoratorErrors.COMPUTED_PROPERTY_MUST_BE_CONSTANT_OR_LITERAL,
604
+ }, state);
547
605
  }
548
- throw generateError(key, {
549
- errorInfo: errors.DecoratorErrors.COMPUTED_PROPERTY_MUST_BE_CONSTANT_OR_LITERAL,
550
- }, state);
551
606
  }
552
607
  }
553
608
  function validateWireParameters(path, state) {
@@ -569,13 +624,13 @@ function validateUsageWithOtherDecorators(path, decorators, state) {
569
624
  if (path !== decorator.path &&
570
625
  decorator.name === WIRE_DECORATOR$1 &&
571
626
  decorator.path.parentPath.node === path.parentPath.node) {
572
- throw generateError(path, {
627
+ handleError(path, {
573
628
  errorInfo: errors.DecoratorErrors.ONE_WIRE_DECORATOR_ALLOWED,
574
629
  }, state);
575
630
  }
576
631
  if ((decorator.name === API_DECORATOR || decorator.name === TRACK_DECORATOR$1) &&
577
632
  decorator.path.parentPath.node === path.parentPath.node) {
578
- throw generateError(path, {
633
+ handleError(path, {
579
634
  errorInfo: errors.DecoratorErrors.CONFLICT_WITH_ANOTHER_DECORATOR,
580
635
  messageArgs: [decorator.name],
581
636
  }, state);
@@ -601,15 +656,26 @@ function isObservedProperty(configProperty) {
601
656
  const propertyValue = configProperty.get('value');
602
657
  return (propertyValue.isStringLiteral() && propertyValue.node.value.startsWith(WIRE_PARAM_PREFIX));
603
658
  }
604
- function getWiredStatic(wireConfig) {
605
- return wireConfig
606
- .get('properties')
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
607
667
  .filter((property) => !isObservedProperty(property))
608
668
  .map((path) => path.node);
609
669
  }
610
- function getWiredParams(t, wireConfig) {
611
- return wireConfig
612
- .get('properties')
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
613
679
  .filter((property) => isObservedProperty(property))
614
680
  .map((path) => {
615
681
  // Need to clone deep the observed property to remove the param prefix
@@ -739,7 +805,7 @@ const scopedReferenceLookup = (scope) => (name) => {
739
805
  value,
740
806
  };
741
807
  };
742
- function transform$1(t, decoratorMetas) {
808
+ function transform$1(t, decoratorMetas, state) {
743
809
  const objectProperties = [];
744
810
  const wiredValues = decoratorMetas.filter(isWireDecorator).map(({ path }) => {
745
811
  const [id, config] = path.get('expression.arguments');
@@ -752,8 +818,8 @@ function transform$1(t, decoratorMetas) {
752
818
  isClassMethod,
753
819
  };
754
820
  if (config) {
755
- wiredValue.static = getWiredStatic(config);
756
- wiredValue.params = getWiredParams(t, config);
821
+ wiredValue.static = getWiredStatic(config, state);
822
+ wiredValue.params = getWiredParams(t, config, state);
757
823
  }
758
824
  const referenceLookup = scopedReferenceLookup(path.scope);
759
825
  const isMemberExpression = id.isMemberExpression();
@@ -802,7 +868,7 @@ function isTrackDecorator(decorator) {
802
868
  function validate$1(decorators, state) {
803
869
  decorators.filter(isTrackDecorator).forEach(({ path }) => {
804
870
  if (!path.parentPath.isClassProperty()) {
805
- throw generateError(path, {
871
+ handleError(path, {
806
872
  errorInfo: errors.DecoratorErrors.TRACK_ONLY_ALLOWED_ON_CLASS_PROPERTIES,
807
873
  }, state);
808
874
  }
@@ -863,11 +929,14 @@ function getDecoratedNodeType(decoratorPath, state) {
863
929
  else if (propertyOrMethod.isClassProperty()) {
864
930
  return DECORATOR_TYPES.PROPERTY;
865
931
  }
866
- else {
867
- throw generateError(propertyOrMethod, {
868
- errorInfo: errors.DecoratorErrors.INVALID_DECORATOR_TYPE,
869
- }, state);
870
- }
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;
871
940
  }
872
941
  function validateImportedLwcDecoratorUsage(engineImportSpecifiers, state) {
873
942
  engineImportSpecifiers
@@ -890,14 +959,15 @@ function validateImportedLwcDecoratorUsage(engineImportSpecifiers, state) {
890
959
  ? reference.parentPath
891
960
  : reference.parentPath.parentPath;
892
961
  if (!decorator.isDecorator()) {
893
- throw generateError(decorator, {
962
+ handleError(decorator, {
894
963
  errorInfo: errors.DecoratorErrors.IS_NOT_DECORATOR,
895
964
  messageArgs: [name],
896
965
  }, state);
897
966
  }
898
967
  const propertyOrMethod = decorator.parentPath;
899
- if (!propertyOrMethod.isClassProperty() && !propertyOrMethod.isClassMethod()) {
900
- throw generateError(propertyOrMethod, {
968
+ if (propertyOrMethod === null ||
969
+ (!propertyOrMethod.isClassProperty() && !propertyOrMethod.isClassMethod())) {
970
+ handleError(propertyOrMethod === null ? decorator : propertyOrMethod, {
901
971
  errorInfo: errors.DecoratorErrors.IS_NOT_CLASS_PROPERTY_OR_CLASS_METHOD,
902
972
  messageArgs: [name],
903
973
  }, state);
@@ -917,7 +987,7 @@ function validate(decorators, state) {
917
987
  for (const { name, path } of decorators) {
918
988
  const binding = path.scope.getBinding(name);
919
989
  if (binding === undefined || !isImportedFromLwcSource(binding.path)) {
920
- throw generateInvalidDecoratorError(path, state);
990
+ handleInvalidDecoratorError(path, state);
921
991
  }
922
992
  }
923
993
  DECORATOR_TRANSFORMS.forEach(({ validate }) => validate(decorators, state));
@@ -937,7 +1007,7 @@ function removeImportedDecoratorSpecifiers(engineImportSpecifiers) {
937
1007
  }
938
1008
  });
939
1009
  }
940
- function generateInvalidDecoratorError(path, state) {
1010
+ function handleInvalidDecoratorError(path, state) {
941
1011
  const expressionPath = path.get('expression');
942
1012
  const { node } = path;
943
1013
  const { expression } = node;
@@ -949,13 +1019,13 @@ function generateInvalidDecoratorError(path, state) {
949
1019
  name = expression.callee.name;
950
1020
  }
951
1021
  if (name) {
952
- return generateError(path.parentPath, {
1022
+ handleError(path.parentPath, {
953
1023
  errorInfo: errors.DecoratorErrors.INVALID_DECORATOR_WITH_NAME,
954
1024
  messageArgs: [name, AVAILABLE_DECORATORS, LWC_PACKAGE_ALIAS],
955
1025
  }, state);
956
1026
  }
957
1027
  else {
958
- return generateError(path.parentPath, {
1028
+ handleError(path.parentPath, {
959
1029
  errorInfo: errors.DecoratorErrors.INVALID_DECORATOR,
960
1030
  messageArgs: [AVAILABLE_DECORATORS, LWC_PACKAGE_ALIAS],
961
1031
  }, state);
@@ -980,7 +1050,8 @@ function getDecoratorMetadata(decoratorPath, state) {
980
1050
  name = expressionPath.node.callee.name;
981
1051
  }
982
1052
  else {
983
- throw generateInvalidDecoratorError(decoratorPath, state);
1053
+ handleInvalidDecoratorError(decoratorPath, state);
1054
+ return null;
984
1055
  }
985
1056
  const propertyName = decoratorPath.parent.key.name;
986
1057
  const decoratedNodeType = getDecoratedNodeType(decoratorPath, state);
@@ -991,11 +1062,11 @@ function getDecoratorMetadata(decoratorPath, state) {
991
1062
  decoratedNodeType,
992
1063
  };
993
1064
  }
994
- function getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems) {
1065
+ function getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems, state) {
995
1066
  const list = [
996
- ...api.transform(t, decoratorMetas, classBodyItems),
1067
+ ...api.transform(t, decoratorMetas, classBodyItems, state),
997
1068
  ...track.transform(t, decoratorMetas),
998
- ...wire.transform(t, decoratorMetas),
1069
+ ...wire.transform(t, decoratorMetas, state),
999
1070
  ];
1000
1071
  const fieldNames = classBodyItems
1001
1072
  .filter((field) => field.isClassProperty({ computed: false, static: false }))
@@ -1033,9 +1104,11 @@ function decorators({ types: t }) {
1033
1104
  return;
1034
1105
  }
1035
1106
  const decoratorPaths = collectDecoratorPaths(classBodyItems);
1036
- const decoratorMetas = decoratorPaths.map((path) => getDecoratorMetadata(path, state));
1107
+ const decoratorMetas = decoratorPaths
1108
+ .map((path) => getDecoratorMetadata(path, state))
1109
+ .filter((meta) => meta !== null);
1037
1110
  validate(decoratorMetas, state);
1038
- const metaPropertyList = getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems);
1111
+ const metaPropertyList = getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems, state);
1039
1112
  if (metaPropertyList.length === 0) {
1040
1113
  return;
1041
1114
  }
@@ -1126,7 +1199,7 @@ function getImportSource(path) {
1126
1199
  }
1127
1200
  function validateImport(sourcePath, state) {
1128
1201
  if (!sourcePath.isStringLiteral()) {
1129
- throw generateError(sourcePath, {
1202
+ handleError(sourcePath, {
1130
1203
  errorInfo: errors.LWCClassErrors.INVALID_DYNAMIC_IMPORT_SOURCE_STRICT,
1131
1204
  messageArgs: [String(sourcePath)],
1132
1205
  }, state);
@@ -1273,5 +1346,5 @@ function LwcClassTransform(api) {
1273
1346
  }
1274
1347
 
1275
1348
  exports.default = LwcClassTransform;
1276
- /** version: 8.23.0 */
1349
+ /** version: 8.25.0 */
1277
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
  /*
@@ -38,6 +38,7 @@ const COMPONENT_NAME_KEY = 'sel';
38
38
  const API_VERSION_KEY = 'apiVersion';
39
39
  const COMPONENT_CLASS_ID = '__lwc_component_class_internal';
40
40
  const SYNTHETIC_ELEMENT_INTERNALS_KEY = 'enableSyntheticElementInternals';
41
+ const COMPONENT_FEATURE_FLAG_KEY = 'componentFeatureFlag';
41
42
 
42
43
  /*
43
44
  * Copyright (c) 2023, salesforce.com, inc.
@@ -71,6 +72,13 @@ function component ({ types: t }) {
71
72
  function createRegisterComponent(declarationPath, state) {
72
73
  const registerComponentId = addNamed(declarationPath, REGISTER_COMPONENT_ID, LWC_PACKAGE_ALIAS);
73
74
  const templateIdentifier = importDefaultTemplate(declarationPath, state);
75
+ // Optionally import feature flag module if provided via compiler options
76
+ let componentFeatureFlagIdentifier;
77
+ if (state.opts.componentFeatureFlagModulePath) {
78
+ componentFeatureFlagIdentifier = addDefault(declarationPath, state.opts.componentFeatureFlagModulePath, {
79
+ nameHint: COMPONENT_FEATURE_FLAG_KEY,
80
+ });
81
+ }
74
82
  const statementPath = declarationPath.getStatementParent();
75
83
  const componentRegisteredName = getComponentRegisteredName(t, state);
76
84
  let node = declarationPath.node;
@@ -99,6 +107,14 @@ function component ({ types: t }) {
99
107
  // The client needs to trust the server that it's providing an actual known API version
100
108
  t.objectProperty(t.identifier(API_VERSION_KEY), t.numericLiteral(apiVersion)),
101
109
  ];
110
+ if (componentFeatureFlagIdentifier) {
111
+ properties.push(t.objectProperty(t.identifier(COMPONENT_FEATURE_FLAG_KEY), t.objectExpression([
112
+ t.objectProperty(t.identifier('value'), t.callExpression(t.identifier('Boolean'), [
113
+ componentFeatureFlagIdentifier,
114
+ ])),
115
+ t.objectProperty(t.identifier('path'), t.stringLiteral(state.opts.componentFeatureFlagModulePath)),
116
+ ])));
117
+ }
102
118
  // Only include enableSyntheticElementInternals if set to true
103
119
  if (state.opts.enableSyntheticElementInternals === true) {
104
120
  properties.push(t.objectProperty(t.identifier(SYNTHETIC_ELEMENT_INTERNALS_KEY), t.booleanLiteral(true)));
@@ -209,9 +225,36 @@ function generateError(source, { errorInfo, messageArgs }, state) {
209
225
  error.lwcCode = errorInfo && errorInfo.code;
210
226
  return error;
211
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
+ }
212
252
  function incrementMetricCounter(metric, state) {
213
253
  state.opts.instrumentation?.incrementCounter(metric);
214
254
  }
255
+ function isErrorRecoveryMode(state) {
256
+ return state.file.opts?.parserOpts?.errorRecovery ?? false;
257
+ }
215
258
 
216
259
  /*
217
260
  * Copyright (c) 2023, salesforce.com, inc.
@@ -235,7 +278,7 @@ function validateConflict(path, decorators, state) {
235
278
  const isPublicFieldTracked = decorators.some((decorator) => decorator.name === TRACK_DECORATOR$2 &&
236
279
  decorator.path.parentPath.node === path.parentPath.node);
237
280
  if (isPublicFieldTracked) {
238
- throw generateError(path, {
281
+ handleError(path, {
239
282
  errorInfo: DecoratorErrors.API_AND_TRACK_DECORATOR_CONFLICT,
240
283
  }, state);
241
284
  }
@@ -246,45 +289,45 @@ function isBooleanPropDefaultTrue(property) {
246
289
  }
247
290
  function validatePropertyValue(property, state) {
248
291
  if (isBooleanPropDefaultTrue(property)) {
249
- throw generateError(property, {
292
+ handleError(property, {
250
293
  errorInfo: DecoratorErrors.INVALID_BOOLEAN_PUBLIC_PROPERTY,
251
294
  }, state);
252
295
  }
253
296
  }
254
297
  function validatePropertyName(property, state) {
255
298
  if (property.node.computed) {
256
- throw generateError(property, {
299
+ handleError(property, {
257
300
  errorInfo: DecoratorErrors.PROPERTY_CANNOT_BE_COMPUTED,
258
301
  }, state);
259
302
  }
260
303
  const propertyName = property.get('key.name').node;
261
304
  if (propertyName === 'part') {
262
- throw generateError(property, {
305
+ handleError(property, {
263
306
  errorInfo: DecoratorErrors.PROPERTY_NAME_PART_IS_RESERVED,
264
307
  messageArgs: [propertyName],
265
308
  }, state);
266
309
  }
267
310
  else if (propertyName.startsWith('on')) {
268
- throw generateError(property, {
311
+ handleError(property, {
269
312
  errorInfo: DecoratorErrors.PROPERTY_NAME_CANNOT_START_WITH_ON,
270
313
  messageArgs: [propertyName],
271
314
  }, state);
272
315
  }
273
316
  else if (propertyName.startsWith('data') && propertyName.length > 4) {
274
- throw generateError(property, {
317
+ handleError(property, {
275
318
  errorInfo: DecoratorErrors.PROPERTY_NAME_CANNOT_START_WITH_DATA,
276
319
  messageArgs: [propertyName],
277
320
  }, state);
278
321
  }
279
322
  else if (DISALLOWED_PROP_SET.has(propertyName)) {
280
- throw generateError(property, {
323
+ handleError(property, {
281
324
  errorInfo: DecoratorErrors.PROPERTY_NAME_IS_RESERVED,
282
325
  messageArgs: [propertyName],
283
326
  }, state);
284
327
  }
285
328
  else if (AMBIGUOUS_PROP_SET.has(propertyName)) {
286
329
  const camelCased = AMBIGUOUS_PROP_SET.get(propertyName);
287
- throw generateError(property, {
330
+ handleError(property, {
288
331
  errorInfo: DecoratorErrors.PROPERTY_NAME_IS_AMBIGUOUS,
289
332
  messageArgs: [propertyName, camelCased],
290
333
  }, state);
@@ -302,7 +345,7 @@ function validateSingleApiDecoratorOnSetterGetterPair(decorators, state) {
302
345
  const methodPath = path.parentPath;
303
346
  const methodName = methodPath.get('key.name').node;
304
347
  if (visitedMethods.has(methodName)) {
305
- throw generateError(methodPath, {
348
+ handleError(methodPath, {
306
349
  errorInfo: DecoratorErrors.SINGLE_DECORATOR_ON_SETTER_GETTER_PAIR,
307
350
  messageArgs: [methodName],
308
351
  }, state);
@@ -328,7 +371,7 @@ function validateUniqueness(decorators, state) {
328
371
  compareType === DECORATOR_TYPES.SETTER) ||
329
372
  (currentType === DECORATOR_TYPES.SETTER && compareType === DECORATOR_TYPES.GETTER);
330
373
  if (haveSameName && isDifferentProperty && !isGetterSetterPair) {
331
- throw generateError(comparePath, {
374
+ handleError(comparePath, {
332
375
  errorInfo: DecoratorErrors.DUPLICATE_API_PROPERTY,
333
376
  messageArgs: [currentPropertyName],
334
377
  }, state);
@@ -387,8 +430,12 @@ function getSiblingGetSetPairType(propertyName, type, classBodyItems) {
387
430
  return siblingKind === 'get' ? DECORATOR_TYPES.GETTER : DECORATOR_TYPES.SETTER;
388
431
  }
389
432
  }
390
- function computePublicPropsConfig(publicPropertyMetas, classBodyItems) {
433
+ function computePublicPropsConfig(publicPropertyMetas, classBodyItems, state) {
391
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;
392
439
  if (!(propertyName in acc)) {
393
440
  acc[propertyName] = {};
394
441
  }
@@ -405,12 +452,12 @@ function computePublicPropsConfig(publicPropertyMetas, classBodyItems) {
405
452
  return acc;
406
453
  }, {});
407
454
  }
408
- function transform$2(t, decoratorMetas, classBodyItems) {
455
+ function transform$2(t, decoratorMetas, classBodyItems, state) {
409
456
  const objectProperties = [];
410
457
  const apiDecoratorMetas = decoratorMetas.filter(isApiDecorator);
411
458
  const publicPropertyMetas = apiDecoratorMetas.filter(({ decoratedNodeType }) => decoratedNodeType !== DECORATOR_TYPES.METHOD);
412
459
  if (publicPropertyMetas.length) {
413
- const propsConfig = computePublicPropsConfig(publicPropertyMetas, classBodyItems);
460
+ const propsConfig = computePublicPropsConfig(publicPropertyMetas, classBodyItems, state);
414
461
  objectProperties.push(t.objectProperty(t.identifier(PUBLIC_PROPS), t.valueToNode(propsConfig)));
415
462
  }
416
463
  const publicMethodMetas = apiDecoratorMetas.filter(({ decoratedNodeType }) => decoratedNodeType === DECORATOR_TYPES.METHOD);
@@ -454,9 +501,10 @@ function isWireDecorator(decorator) {
454
501
  const { TRACK_DECORATOR: TRACK_DECORATOR$1, WIRE_DECORATOR: WIRE_DECORATOR$1, API_DECORATOR } = LWC_PACKAGE_EXPORTS;
455
502
  function validateWireId(id, path, state) {
456
503
  if (!id) {
457
- throw generateError(path, {
504
+ handleError(path, {
458
505
  errorInfo: DecoratorErrors.ADAPTER_SHOULD_BE_FIRST_PARAMETER,
459
506
  }, state);
507
+ return;
460
508
  }
461
509
  let adapter;
462
510
  if (id.isIdentifier()) {
@@ -466,9 +514,10 @@ function validateWireId(id, path, state) {
466
514
  else if (id.isMemberExpression()) {
467
515
  if (id.node.computed) {
468
516
  // @wire(adapter[computed])
469
- throw generateError(id, {
517
+ handleError(id, {
470
518
  errorInfo: DecoratorErrors.FUNCTION_IDENTIFIER_CANNOT_HAVE_COMPUTED_PROPS,
471
519
  }, state);
520
+ return;
472
521
  }
473
522
  const object = id.get('object');
474
523
  if (object.isIdentifier()) {
@@ -477,73 +526,79 @@ function validateWireId(id, path, state) {
477
526
  }
478
527
  else {
479
528
  // @wire(adapter.foo.bar)
480
- throw generateError(id, {
529
+ handleError(id, {
481
530
  errorInfo: DecoratorErrors.FUNCTION_IDENTIFIER_CANNOT_HAVE_NESTED_MEMBER_EXRESSIONS,
482
531
  }, state);
532
+ return;
483
533
  }
484
534
  }
485
535
  else {
486
536
  // @wire(1), @wire('adapter'), @wire(function adapter() {}), etc.
487
- throw generateError(id, {
537
+ handleError(id, {
488
538
  errorInfo: DecoratorErrors.FUNCTION_IDENTIFIER_SHOULD_BE_FIRST_PARAMETER,
489
539
  }, state);
540
+ return;
490
541
  }
491
542
  // Ensure wire adapter is imported (check for member expression or identifier)
492
543
  const adapterBinding = path.scope.getBinding(adapter.node.name);
493
544
  if (!adapterBinding) {
494
- throw generateError(id, {
545
+ handleError(id, {
495
546
  errorInfo: DecoratorErrors.WIRE_ADAPTER_SHOULD_BE_IMPORTED,
496
547
  messageArgs: [adapter.node.name],
497
548
  }, state);
549
+ return;
498
550
  }
499
551
  // ensure wire adapter is a first parameter
500
552
  if (!adapterBinding.path.isImportSpecifier() &&
501
553
  !adapterBinding.path.isImportDefaultSpecifier()) {
502
- throw generateError(id, {
554
+ handleError(id, {
503
555
  errorInfo: DecoratorErrors.IMPORTED_FUNCTION_IDENTIFIER_SHOULD_BE_FIRST_PARAMETER,
504
556
  }, state);
505
557
  }
506
558
  }
507
559
  function validateWireConfig(config, path, state) {
508
560
  if (!config.isObjectExpression()) {
509
- throw generateError(config, {
561
+ handleError(config, {
510
562
  errorInfo: DecoratorErrors.CONFIG_OBJECT_SHOULD_BE_SECOND_PARAMETER,
511
563
  }, state);
512
564
  }
513
- for (const prop of config.get('properties')) {
514
- // Only validate {[computed]: true} object properties; {static: true} props are all valid
515
- // and we ignore {...spreads} and {methods(){}}
516
- if (!prop.isObjectProperty() || !prop.node.computed)
517
- continue;
518
- const key = prop.get('key');
519
- if (key.isIdentifier()) {
520
- // Only allow identifiers that originated from a `const` declaration
521
- const binding = key.scope.getBinding(key.node.name);
522
- // TODO [#3956]: Investigate allowing imported constants
523
- if (binding?.kind === 'const')
524
- continue;
525
- // By default, the identifier `undefined` has no binding (when it's actually undefined),
526
- // but has a binding if it's used as a variable (e.g. `let undefined = "don't do this"`)
527
- 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)
528
571
  continue;
529
- }
530
- else if (key.isLiteral()) {
531
- // A literal can be a regexp, template literal, or primitive; only allow primitives
532
- if (key.isTemplateLiteral()) {
533
- // A template literal is not guaranteed to always result in the same value
534
- // (e.g. `${Math.random()}`), so we disallow them entirely.
535
- // TODO [#3956]: Investigate allowing template literals
536
- throw generateError(key, {
537
- errorInfo: DecoratorErrors.COMPUTED_PROPERTY_CANNOT_BE_TEMPLATE_LITERAL,
538
- }, state);
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;
539
583
  }
540
- else if (!key.isRegExpLiteral()) {
541
- continue;
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
+ }
542
597
  }
598
+ handleError(key, {
599
+ errorInfo: DecoratorErrors.COMPUTED_PROPERTY_MUST_BE_CONSTANT_OR_LITERAL,
600
+ }, state);
543
601
  }
544
- throw generateError(key, {
545
- errorInfo: DecoratorErrors.COMPUTED_PROPERTY_MUST_BE_CONSTANT_OR_LITERAL,
546
- }, state);
547
602
  }
548
603
  }
549
604
  function validateWireParameters(path, state) {
@@ -565,13 +620,13 @@ function validateUsageWithOtherDecorators(path, decorators, state) {
565
620
  if (path !== decorator.path &&
566
621
  decorator.name === WIRE_DECORATOR$1 &&
567
622
  decorator.path.parentPath.node === path.parentPath.node) {
568
- throw generateError(path, {
623
+ handleError(path, {
569
624
  errorInfo: DecoratorErrors.ONE_WIRE_DECORATOR_ALLOWED,
570
625
  }, state);
571
626
  }
572
627
  if ((decorator.name === API_DECORATOR || decorator.name === TRACK_DECORATOR$1) &&
573
628
  decorator.path.parentPath.node === path.parentPath.node) {
574
- throw generateError(path, {
629
+ handleError(path, {
575
630
  errorInfo: DecoratorErrors.CONFLICT_WITH_ANOTHER_DECORATOR,
576
631
  messageArgs: [decorator.name],
577
632
  }, state);
@@ -597,15 +652,26 @@ function isObservedProperty(configProperty) {
597
652
  const propertyValue = configProperty.get('value');
598
653
  return (propertyValue.isStringLiteral() && propertyValue.node.value.startsWith(WIRE_PARAM_PREFIX));
599
654
  }
600
- function getWiredStatic(wireConfig) {
601
- return wireConfig
602
- .get('properties')
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
603
663
  .filter((property) => !isObservedProperty(property))
604
664
  .map((path) => path.node);
605
665
  }
606
- function getWiredParams(t, wireConfig) {
607
- return wireConfig
608
- .get('properties')
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
609
675
  .filter((property) => isObservedProperty(property))
610
676
  .map((path) => {
611
677
  // Need to clone deep the observed property to remove the param prefix
@@ -735,7 +801,7 @@ const scopedReferenceLookup = (scope) => (name) => {
735
801
  value,
736
802
  };
737
803
  };
738
- function transform$1(t, decoratorMetas) {
804
+ function transform$1(t, decoratorMetas, state) {
739
805
  const objectProperties = [];
740
806
  const wiredValues = decoratorMetas.filter(isWireDecorator).map(({ path }) => {
741
807
  const [id, config] = path.get('expression.arguments');
@@ -748,8 +814,8 @@ function transform$1(t, decoratorMetas) {
748
814
  isClassMethod,
749
815
  };
750
816
  if (config) {
751
- wiredValue.static = getWiredStatic(config);
752
- wiredValue.params = getWiredParams(t, config);
817
+ wiredValue.static = getWiredStatic(config, state);
818
+ wiredValue.params = getWiredParams(t, config, state);
753
819
  }
754
820
  const referenceLookup = scopedReferenceLookup(path.scope);
755
821
  const isMemberExpression = id.isMemberExpression();
@@ -798,7 +864,7 @@ function isTrackDecorator(decorator) {
798
864
  function validate$1(decorators, state) {
799
865
  decorators.filter(isTrackDecorator).forEach(({ path }) => {
800
866
  if (!path.parentPath.isClassProperty()) {
801
- throw generateError(path, {
867
+ handleError(path, {
802
868
  errorInfo: DecoratorErrors.TRACK_ONLY_ALLOWED_ON_CLASS_PROPERTIES,
803
869
  }, state);
804
870
  }
@@ -859,11 +925,14 @@ function getDecoratedNodeType(decoratorPath, state) {
859
925
  else if (propertyOrMethod.isClassProperty()) {
860
926
  return DECORATOR_TYPES.PROPERTY;
861
927
  }
862
- else {
863
- throw generateError(propertyOrMethod, {
864
- errorInfo: DecoratorErrors.INVALID_DECORATOR_TYPE,
865
- }, state);
866
- }
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;
867
936
  }
868
937
  function validateImportedLwcDecoratorUsage(engineImportSpecifiers, state) {
869
938
  engineImportSpecifiers
@@ -886,14 +955,15 @@ function validateImportedLwcDecoratorUsage(engineImportSpecifiers, state) {
886
955
  ? reference.parentPath
887
956
  : reference.parentPath.parentPath;
888
957
  if (!decorator.isDecorator()) {
889
- throw generateError(decorator, {
958
+ handleError(decorator, {
890
959
  errorInfo: DecoratorErrors.IS_NOT_DECORATOR,
891
960
  messageArgs: [name],
892
961
  }, state);
893
962
  }
894
963
  const propertyOrMethod = decorator.parentPath;
895
- if (!propertyOrMethod.isClassProperty() && !propertyOrMethod.isClassMethod()) {
896
- throw generateError(propertyOrMethod, {
964
+ if (propertyOrMethod === null ||
965
+ (!propertyOrMethod.isClassProperty() && !propertyOrMethod.isClassMethod())) {
966
+ handleError(propertyOrMethod === null ? decorator : propertyOrMethod, {
897
967
  errorInfo: DecoratorErrors.IS_NOT_CLASS_PROPERTY_OR_CLASS_METHOD,
898
968
  messageArgs: [name],
899
969
  }, state);
@@ -913,7 +983,7 @@ function validate(decorators, state) {
913
983
  for (const { name, path } of decorators) {
914
984
  const binding = path.scope.getBinding(name);
915
985
  if (binding === undefined || !isImportedFromLwcSource(binding.path)) {
916
- throw generateInvalidDecoratorError(path, state);
986
+ handleInvalidDecoratorError(path, state);
917
987
  }
918
988
  }
919
989
  DECORATOR_TRANSFORMS.forEach(({ validate }) => validate(decorators, state));
@@ -933,7 +1003,7 @@ function removeImportedDecoratorSpecifiers(engineImportSpecifiers) {
933
1003
  }
934
1004
  });
935
1005
  }
936
- function generateInvalidDecoratorError(path, state) {
1006
+ function handleInvalidDecoratorError(path, state) {
937
1007
  const expressionPath = path.get('expression');
938
1008
  const { node } = path;
939
1009
  const { expression } = node;
@@ -945,13 +1015,13 @@ function generateInvalidDecoratorError(path, state) {
945
1015
  name = expression.callee.name;
946
1016
  }
947
1017
  if (name) {
948
- return generateError(path.parentPath, {
1018
+ handleError(path.parentPath, {
949
1019
  errorInfo: DecoratorErrors.INVALID_DECORATOR_WITH_NAME,
950
1020
  messageArgs: [name, AVAILABLE_DECORATORS, LWC_PACKAGE_ALIAS],
951
1021
  }, state);
952
1022
  }
953
1023
  else {
954
- return generateError(path.parentPath, {
1024
+ handleError(path.parentPath, {
955
1025
  errorInfo: DecoratorErrors.INVALID_DECORATOR,
956
1026
  messageArgs: [AVAILABLE_DECORATORS, LWC_PACKAGE_ALIAS],
957
1027
  }, state);
@@ -976,7 +1046,8 @@ function getDecoratorMetadata(decoratorPath, state) {
976
1046
  name = expressionPath.node.callee.name;
977
1047
  }
978
1048
  else {
979
- throw generateInvalidDecoratorError(decoratorPath, state);
1049
+ handleInvalidDecoratorError(decoratorPath, state);
1050
+ return null;
980
1051
  }
981
1052
  const propertyName = decoratorPath.parent.key.name;
982
1053
  const decoratedNodeType = getDecoratedNodeType(decoratorPath, state);
@@ -987,11 +1058,11 @@ function getDecoratorMetadata(decoratorPath, state) {
987
1058
  decoratedNodeType,
988
1059
  };
989
1060
  }
990
- function getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems) {
1061
+ function getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems, state) {
991
1062
  const list = [
992
- ...api.transform(t, decoratorMetas, classBodyItems),
1063
+ ...api.transform(t, decoratorMetas, classBodyItems, state),
993
1064
  ...track.transform(t, decoratorMetas),
994
- ...wire.transform(t, decoratorMetas),
1065
+ ...wire.transform(t, decoratorMetas, state),
995
1066
  ];
996
1067
  const fieldNames = classBodyItems
997
1068
  .filter((field) => field.isClassProperty({ computed: false, static: false }))
@@ -1029,9 +1100,11 @@ function decorators({ types: t }) {
1029
1100
  return;
1030
1101
  }
1031
1102
  const decoratorPaths = collectDecoratorPaths(classBodyItems);
1032
- const decoratorMetas = decoratorPaths.map((path) => getDecoratorMetadata(path, state));
1103
+ const decoratorMetas = decoratorPaths
1104
+ .map((path) => getDecoratorMetadata(path, state))
1105
+ .filter((meta) => meta !== null);
1033
1106
  validate(decoratorMetas, state);
1034
- const metaPropertyList = getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems);
1107
+ const metaPropertyList = getMetadataObjectPropertyList(t, decoratorMetas, classBodyItems, state);
1035
1108
  if (metaPropertyList.length === 0) {
1036
1109
  return;
1037
1110
  }
@@ -1122,7 +1195,7 @@ function getImportSource(path) {
1122
1195
  }
1123
1196
  function validateImport(sourcePath, state) {
1124
1197
  if (!sourcePath.isStringLiteral()) {
1125
- throw generateError(sourcePath, {
1198
+ handleError(sourcePath, {
1126
1199
  errorInfo: LWCClassErrors.INVALID_DYNAMIC_IMPORT_SOURCE_STRICT,
1127
1200
  messageArgs: [String(sourcePath)],
1128
1201
  }, state);
@@ -1269,5 +1342,5 @@ function LwcClassTransform(api) {
1269
1342
  }
1270
1343
 
1271
1344
  export { LwcClassTransform as default };
1272
- /** version: 8.23.0 */
1345
+ /** version: 8.25.0 */
1273
1346
  //# sourceMappingURL=index.js.map
package/dist/types.d.ts CHANGED
@@ -14,6 +14,7 @@ export interface LwcBabelPluginOptions {
14
14
  instrumentation?: InstrumentationObject;
15
15
  apiVersion?: number;
16
16
  enableSyntheticElementInternals?: boolean;
17
+ componentFeatureFlagModulePath?: string;
17
18
  }
18
19
  export interface LwcBabelPluginPass extends PluginPass {
19
20
  opts: LwcBabelPluginOptions;
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 generateError(source: NodePath<types.Node>, { errorInfo, messageArgs }: DecoratorErrorOptions, state: LwcBabelPluginPass): Error;
21
+ declare function handleError(source: NodePath<types.Node>, decoratorErrorOpts: DecoratorErrorOptions, state: LwcBabelPluginPass): void;
22
22
  declare function incrementMetricCounter(metric: CompilerMetrics, state: LwcBabelPluginPass): void;
23
- export { isClassMethod, isGetterClassMethod, isSetterClassMethod, generateError, getEngineImportSpecifiers, incrementMetricCounter, };
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.23.0",
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.23.0",
51
- "@lwc/shared": "8.23.0",
50
+ "@lwc/errors": "8.25.0",
51
+ "@lwc/shared": "8.25.0",
52
52
  "line-column": "~1.0.2"
53
53
  },
54
54
  "devDependencies": {