Skip to content

Commit c04b0b7

Browse files
authored
chore(ssr): use real error messages for errors @W-17408217 (#5249)
* chore(ssr): use real error messages for errors No more TODO! * chore: update test fixture with new error * chore: fix expected error message
1 parent 6eee0d1 commit c04b0b7

File tree

6 files changed

+58
-33
lines changed

6 files changed

+58
-33
lines changed
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
LWCTODO: identifier name '__lwcThrowAnError__' cannot start with '__lwc'
1+
LWC1202: Identifier name cannot start with "__lwc".

packages/@lwc/errors/src/compiler/error-info/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
66
*/
77
/**
8-
* Next error code: 1202
8+
* Next error code: 1203
99
*/
1010

1111
export * from './compiler';
1212
export * from './lwc-class';
1313
export * from './template-transform';
14+
export * from './ssr';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright (c) 2025, Salesforce, Inc.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: MIT
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
6+
*/
7+
import { DiagnosticLevel } from '../../shared/types';
8+
9+
/*
10+
* For the next available error code, reference (and update!) the value in ./index.ts
11+
*/
12+
13+
export const SsrCompilerErrors = {
14+
RESERVED_IDENTIFIER_PREFIX: {
15+
code: 1202,
16+
message: 'Identifier name cannot start with "__lwc".',
17+
level: DiagnosticLevel.Error,
18+
url: '',
19+
},
20+
} as const;

packages/@lwc/ssr-compiler/src/__tests__/dynamic-imports.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe('dynamic imports', () => {
5050
};
5151

5252
if (strictSpecifier && !isStrict) {
53-
expect(callback).toThrowError(/INVALID_DYNAMIC_IMPORT_SOURCE_STRICT/);
53+
expect(callback).toThrowError(/LWC1121/);
5454
return;
5555
} else {
5656
callback();

packages/@lwc/ssr-compiler/src/compile-js/decorators/wire.ts

+26-25
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import type {
2424
BlockStatement,
2525
Decorator,
2626
CallExpression,
27+
SpreadElement,
2728
} from 'estree';
2829
import type { ComponentMetaState, WireAdapter } from '../types';
2930

@@ -42,54 +43,53 @@ function bMemberExpressionChain(props: string[]): MemberExpression {
4243

4344
function getWireParams(
4445
node: MethodDefinition | PropertyDefinition
45-
): [Expression, Expression | undefined] {
46+
): (Expression | SpreadElement)[] {
4647
const { decorators } = node;
4748

4849
if (decorators.length > 1) {
4950
throw generateError(node, DecoratorErrors.ONE_WIRE_DECORATOR_ALLOWED);
5051
}
5152

52-
// validate the parameters
53+
// Before calling this function, we validate that it has exactly one decorator, @wire
5354
const wireDecorator = decorators[0].expression;
5455
if (!is.callExpression(wireDecorator)) {
55-
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
56-
throw new Error('todo - invalid usage');
56+
throw generateError(node, DecoratorErrors.FUNCTION_IDENTIFIER_SHOULD_BE_FIRST_PARAMETER);
5757
}
5858

5959
const args = wireDecorator.arguments;
60-
if (args.length === 0 || args.length > 2) {
61-
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
62-
throw new Error('todo - wrong number of args');
60+
if (args.length === 0) {
61+
throw generateError(node, DecoratorErrors.ADAPTER_SHOULD_BE_FIRST_PARAMETER);
6362
}
6463

65-
const [id, config] = args;
66-
if (is.spreadElement(id) || is.spreadElement(config)) {
67-
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
68-
throw new Error('todo - spread in params');
69-
}
70-
return [id, config];
64+
return args;
7165
}
7266

7367
function validateWireId(
74-
id: Expression,
68+
id: Expression | SpreadElement,
7569
path: NodePath<PropertyDefinition | MethodDefinition>
7670
): asserts id is Identifier | MemberExpression {
7771
// name of identifier or object used in member expression (e.g. "foo" for `foo.bar`)
7872
let wireAdapterVar: string;
7973

8074
if (is.memberExpression(id)) {
8175
if (id.computed) {
82-
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
83-
throw new Error('todo - FUNCTION_IDENTIFIER_CANNOT_HAVE_COMPUTED_PROPS');
76+
throw generateError(
77+
path.node!,
78+
DecoratorErrors.FUNCTION_IDENTIFIER_CANNOT_HAVE_COMPUTED_PROPS
79+
);
8480
}
8581
if (!is.identifier(id.object)) {
86-
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
87-
throw new Error('todo - FUNCTION_IDENTIFIER_CANNOT_HAVE_NESTED_MEMBER_EXRESSIONS');
82+
throw generateError(
83+
path.node!,
84+
DecoratorErrors.FUNCTION_IDENTIFIER_CANNOT_HAVE_NESTED_MEMBER_EXRESSIONS
85+
);
8886
}
8987
wireAdapterVar = id.object.name;
9088
} else if (!is.identifier(id)) {
91-
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
92-
throw new Error('todo - invalid adapter name');
89+
throw generateError(
90+
path.node!,
91+
DecoratorErrors.FUNCTION_IDENTIFIER_SHOULD_BE_FIRST_PARAMETER
92+
);
9393
} else {
9494
wireAdapterVar = id.name;
9595
}
@@ -104,12 +104,11 @@ function validateWireId(
104104
}
105105

106106
function validateWireConfig(
107-
config: Expression,
107+
config: Expression | SpreadElement | undefined,
108108
path: NodePath<PropertyDefinition | MethodDefinition>
109109
): asserts config is NoSpreadObjectExpression {
110110
if (!is.objectExpression(config)) {
111-
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
112-
throw new Error('todo - CONFIG_OBJECT_SHOULD_BE_SECOND_PARAMETER');
111+
throw generateError(path.node!, DecoratorErrors.CONFIG_OBJECT_SHOULD_BE_SECOND_PARAMETER);
113112
}
114113
for (const property of config.properties) {
115114
// Only validate computed object properties because static props are all valid
@@ -127,8 +126,10 @@ function validateWireConfig(
127126
if (is.templateLiteral(key)) {
128127
// A template literal is not guaranteed to always result in the same value
129128
// (e.g. `${Math.random()}`), so we disallow them entirely.
130-
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
131-
throw new Error('todo - COMPUTED_PROPERTY_CANNOT_BE_TEMPLATE_LITERAL');
129+
throw generateError(
130+
path.node!,
131+
DecoratorErrors.COMPUTED_PROPERTY_CANNOT_BE_TEMPLATE_LITERAL
132+
);
132133
} else if (!('regex' in key)) {
133134
// A literal can be a regexp, template literal, or primitive; only allow primitives
134135
continue;

packages/@lwc/ssr-compiler/src/compile-js/index.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { traverse, builders as b, is } from 'estree-toolkit';
1010
import { parseModule } from 'meriyah';
1111

1212
import { LWC_VERSION_COMMENT, type CompilationMode } from '@lwc/shared';
13+
import { LWCClassErrors, SsrCompilerErrors } from '@lwc/errors';
1314
import { transmogrify } from '../transmogrify';
1415
import { ImportManager } from '../imports';
1516
import { replaceLwcImport, replaceNamedLwcExport, replaceAllLwcExport } from './lwc-import';
@@ -24,6 +25,7 @@ import { removeDecoratorImport } from './remove-decorator-import';
2425

2526
import { type Visitors, type ComponentMetaState } from './types';
2627
import { validateUniqueDecorator } from './decorators';
28+
import { generateError } from './errors';
2729
import type { ComponentTransformOptions } from '../shared';
2830
import type {
2931
Identifier as EsIdentifier,
@@ -60,8 +62,10 @@ const visitors: Visitors = {
6062
}
6163
if (experimentalDynamicComponent.strictSpecifier) {
6264
if (!is.literal(path.node?.source) || typeof path.node.source.value !== 'string') {
63-
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
64-
throw new Error('todo - LWCClassErrors.INVALID_DYNAMIC_IMPORT_SOURCE_STRICT');
65+
throw generateError(
66+
path.node!,
67+
LWCClassErrors.INVALID_DYNAMIC_IMPORT_SOURCE_STRICT
68+
);
6569
}
6670
}
6771
const loader = experimentalDynamicComponent.loader;
@@ -162,7 +166,7 @@ const visitors: Visitors = {
162166
state.publicProperties.set(node.key.name, node);
163167
} else if (isWireDecorator(decorators[0])) {
164168
if (node.computed) {
165-
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
169+
// TODO [W-17758410]: implement
166170
throw new Error('@wire cannot be used on computed properties in SSR context.');
167171
}
168172
const isRealMethod = node.kind === 'method';
@@ -245,8 +249,7 @@ const visitors: Visitors = {
245249
Identifier(path, _state) {
246250
const { node } = path;
247251
if (node?.name.startsWith('__lwc')) {
248-
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
249-
throw new Error(`LWCTODO: identifier name '${node.name}' cannot start with '__lwc'`);
252+
throw generateError(node, SsrCompilerErrors.RESERVED_IDENTIFIER_PREFIX);
250253
}
251254
},
252255
};

0 commit comments

Comments
 (0)