Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
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
Loading