Skip to content

Commit

Permalink
chore(ssr): use real error messages for errors @W-17408217 (#5249)
Browse files Browse the repository at this point in the history
* chore(ssr): use real error messages for errors

No more TODO!

* chore: update test fixture with new error

* chore: fix expected error message
  • Loading branch information
wjhsf authored Feb 28, 2025
1 parent 6eee0d1 commit c04b0b7
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
LWCTODO: identifier name '__lwcThrowAnError__' cannot start with '__lwc'
LWC1202: Identifier name cannot start with "__lwc".
3 changes: 2 additions & 1 deletion packages/@lwc/errors/src/compiler/error-info/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
/**
* Next error code: 1202
* Next error code: 1203
*/

export * from './compiler';
export * from './lwc-class';
export * from './template-transform';
export * from './ssr';
20 changes: 20 additions & 0 deletions packages/@lwc/errors/src/compiler/error-info/ssr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2025, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
import { DiagnosticLevel } from '../../shared/types';

/*
* For the next available error code, reference (and update!) the value in ./index.ts
*/

export const SsrCompilerErrors = {
RESERVED_IDENTIFIER_PREFIX: {
code: 1202,
message: 'Identifier name cannot start with "__lwc".',
level: DiagnosticLevel.Error,
url: '',
},
} as const;
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ describe('dynamic imports', () => {
};

if (strictSpecifier && !isStrict) {
expect(callback).toThrowError(/INVALID_DYNAMIC_IMPORT_SOURCE_STRICT/);
expect(callback).toThrowError(/LWC1121/);
return;
} else {
callback();
Expand Down
51 changes: 26 additions & 25 deletions packages/@lwc/ssr-compiler/src/compile-js/decorators/wire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type {
BlockStatement,
Decorator,
CallExpression,
SpreadElement,
} from 'estree';
import type { ComponentMetaState, WireAdapter } from '../types';

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

function getWireParams(
node: MethodDefinition | PropertyDefinition
): [Expression, Expression | undefined] {
): (Expression | SpreadElement)[] {
const { decorators } = node;

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

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

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

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

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

if (is.memberExpression(id)) {
if (id.computed) {
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
throw new Error('todo - FUNCTION_IDENTIFIER_CANNOT_HAVE_COMPUTED_PROPS');
throw generateError(
path.node!,
DecoratorErrors.FUNCTION_IDENTIFIER_CANNOT_HAVE_COMPUTED_PROPS
);
}
if (!is.identifier(id.object)) {
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
throw new Error('todo - FUNCTION_IDENTIFIER_CANNOT_HAVE_NESTED_MEMBER_EXRESSIONS');
throw generateError(
path.node!,
DecoratorErrors.FUNCTION_IDENTIFIER_CANNOT_HAVE_NESTED_MEMBER_EXRESSIONS
);
}
wireAdapterVar = id.object.name;
} else if (!is.identifier(id)) {
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
throw new Error('todo - invalid adapter name');
throw generateError(
path.node!,
DecoratorErrors.FUNCTION_IDENTIFIER_SHOULD_BE_FIRST_PARAMETER
);
} else {
wireAdapterVar = id.name;
}
Expand All @@ -104,12 +104,11 @@ function validateWireId(
}

function validateWireConfig(
config: Expression,
config: Expression | SpreadElement | undefined,
path: NodePath<PropertyDefinition | MethodDefinition>
): asserts config is NoSpreadObjectExpression {
if (!is.objectExpression(config)) {
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
throw new Error('todo - CONFIG_OBJECT_SHOULD_BE_SECOND_PARAMETER');
throw generateError(path.node!, DecoratorErrors.CONFIG_OBJECT_SHOULD_BE_SECOND_PARAMETER);
}
for (const property of config.properties) {
// Only validate computed object properties because static props are all valid
Expand All @@ -127,8 +126,10 @@ function validateWireConfig(
if (is.templateLiteral(key)) {
// A template literal is not guaranteed to always result in the same value
// (e.g. `${Math.random()}`), so we disallow them entirely.
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
throw new Error('todo - COMPUTED_PROPERTY_CANNOT_BE_TEMPLATE_LITERAL');
throw generateError(
path.node!,
DecoratorErrors.COMPUTED_PROPERTY_CANNOT_BE_TEMPLATE_LITERAL
);
} else if (!('regex' in key)) {
// A literal can be a regexp, template literal, or primitive; only allow primitives
continue;
Expand Down
13 changes: 8 additions & 5 deletions packages/@lwc/ssr-compiler/src/compile-js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { traverse, builders as b, is } from 'estree-toolkit';
import { parseModule } from 'meriyah';

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

import { type Visitors, type ComponentMetaState } from './types';
import { validateUniqueDecorator } from './decorators';
import { generateError } from './errors';
import type { ComponentTransformOptions } from '../shared';
import type {
Identifier as EsIdentifier,
Expand Down Expand Up @@ -60,8 +62,10 @@ const visitors: Visitors = {
}
if (experimentalDynamicComponent.strictSpecifier) {
if (!is.literal(path.node?.source) || typeof path.node.source.value !== 'string') {
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
throw new Error('todo - LWCClassErrors.INVALID_DYNAMIC_IMPORT_SOURCE_STRICT');
throw generateError(
path.node!,
LWCClassErrors.INVALID_DYNAMIC_IMPORT_SOURCE_STRICT
);
}
}
const loader = experimentalDynamicComponent.loader;
Expand Down Expand Up @@ -162,7 +166,7 @@ const visitors: Visitors = {
state.publicProperties.set(node.key.name, node);
} else if (isWireDecorator(decorators[0])) {
if (node.computed) {
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
// TODO [W-17758410]: implement
throw new Error('@wire cannot be used on computed properties in SSR context.');
}
const isRealMethod = node.kind === 'method';
Expand Down Expand Up @@ -245,8 +249,7 @@ const visitors: Visitors = {
Identifier(path, _state) {
const { node } = path;
if (node?.name.startsWith('__lwc')) {
// TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
throw new Error(`LWCTODO: identifier name '${node.name}' cannot start with '__lwc'`);
throw generateError(node, SsrCompilerErrors.RESERVED_IDENTIFIER_PREFIX);
}
},
};
Expand Down

0 comments on commit c04b0b7

Please sign in to comment.