Skip to content

Commit

Permalink
chore: move decorators to their own folder
Browse files Browse the repository at this point in the history
  • Loading branch information
cardoso committed Dec 20, 2024
1 parent e5af37c commit 2505c01
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 89 deletions.
16 changes: 0 additions & 16 deletions packages/@lwc/ssr-compiler/src/compile-js/api/types.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@
*/
import type { Decorator, Identifier } from 'estree';

type ApiDecorator = Decorator & {
export function isApiDecorator(decorator: Decorator | undefined): decorator is Decorator & {
expression: Identifier & {
name: 'api';
};
};

export function isApiDecorator(decorator: Decorator | undefined): decorator is ApiDecorator {
} {
return decorator?.expression.type === 'Identifier' && decorator.expression.name === 'api';
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,19 @@
*/

import { DecoratorErrors } from '@lwc/errors';
import { generateError } from '../errors';
import { isMethodKind, type ComponentMetaState } from '../types';
import { generateError } from '../../errors';
import { type ComponentMetaState } from '../../types';
import { DISALLOWED_PROP_SET, AMBIGUOUS_PROP_SET } from './consts';
import type { ApiPropertyDefinition, ApiDefinition, ApiMethodDefinition } from './types';
import type { Identifier, MethodDefinition, PropertyDefinition } from 'estree';

export type ApiMethodDefinition = MethodDefinition & {
key: Identifier;
};
export type ApiPropertyDefinition = PropertyDefinition & {
key: Identifier;
};

export type ApiDefinition = ApiPropertyDefinition | ApiMethodDefinition;

function validateName(definition: ApiDefinition) {
if (definition.computed) {
Expand Down Expand Up @@ -57,20 +66,19 @@ export function validateApiProperty(node: ApiPropertyDefinition, state: Componen
function validateUniqueMethod(node: ApiMethodDefinition, state: ComponentMetaState) {
const field = state.publicFields.get(node.key.name);

if (field) {
if (
field.type === 'MethodDefinition' &&
isMethodKind(field, ['get', 'set']) &&
isMethodKind(node, ['get', 'set'])
) {
throw generateError(
DecoratorErrors.SINGLE_DECORATOR_ON_SETTER_GETTER_PAIR,
node.key.name
);
}
if (!field) {
return;
}

throw generateError(DecoratorErrors.DUPLICATE_API_PROPERTY, node.key.name);
if (
field.type === 'MethodDefinition' &&
(field.kind === 'get' || field.kind === 'set') &&
(node.kind === 'get' || node.kind === 'set')
) {
throw generateError(DecoratorErrors.SINGLE_DECORATOR_ON_SETTER_GETTER_PAIR, node.key.name);
}

throw generateError(DecoratorErrors.DUPLICATE_API_PROPERTY, node.key.name);
}

export function validateApiMethod(node: ApiMethodDefinition, state: ComponentMetaState) {
Expand Down
36 changes: 36 additions & 0 deletions packages/@lwc/ssr-compiler/src/compile-js/decorators/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2024, 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 { DecoratorErrors } from '@lwc/errors';
import { generateError } from '../errors';
import { isApiDecorator } from './api';
import { isTrackDecorator } from './track';
import { isWireDecorator } from './wire';
import type { Decorator as EsDecorator } from 'estree';

export function validateUniqueDecorator(decorators: EsDecorator[]) {
if (decorators.length < 2) {
return;
}

const hasWire = decorators.some(isWireDecorator);
const hasApi = decorators.some(isApiDecorator);
const hasTrack = decorators.some(isTrackDecorator);

if (hasWire) {
if (hasApi) {
throw generateError(DecoratorErrors.CONFLICT_WITH_ANOTHER_DECORATOR, 'api');
}

if (hasTrack) {
throw generateError(DecoratorErrors.CONFLICT_WITH_ANOTHER_DECORATOR, 'track');
}
}

if (hasApi && hasTrack) {
throw generateError(DecoratorErrors.API_AND_TRACK_DECORATOR_CONFLICT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import { is, builders as b } from 'estree-toolkit';
import { produce } from 'immer';
import { DecoratorErrors } from '@lwc/errors';
import { esTemplate } from '../estemplate';
import { generateError } from './errors';
import { esTemplate } from '../../estemplate';
import { generateError } from '../errors';
import type { NodePath } from 'estree-toolkit';

import type {
Expand All @@ -25,7 +25,7 @@ import type {
Decorator,
CallExpression,
} from 'estree';
import type { ComponentMetaState, WireAdapter } from './types';
import type { ComponentMetaState, WireAdapter } from '../types';

interface NoSpreadObjectExpression extends Omit<ObjectExpression, 'properties'> {
properties: Property[];
Expand Down Expand Up @@ -211,9 +211,7 @@ export function bWireAdaptersPlumbing(adapters: WireAdapter[]): BlockStatement[]
});
}

export function isWireDecorator(
decorator: Decorator | undefined
): decorator is Decorator & {
export function isWireDecorator(decorator: Decorator | undefined): decorator is Decorator & {
expression: CallExpression & { callee: Identifier & { name: 'wire' } };
} {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { parse as pathParse } from 'node:path';
import { is, builders as b } from 'estree-toolkit';
import { esTemplate } from '../estemplate';
import { bImportDeclaration } from '../estree/builders';
import { bWireAdaptersPlumbing } from './wire';
import { bWireAdaptersPlumbing } from './decorators/wire';

import type {
Program,
Expand Down
49 changes: 16 additions & 33 deletions packages/@lwc/ssr-compiler/src/compile-js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,27 @@ import { generate } from 'astring';
import { traverse, builders as b, is } from 'estree-toolkit';
import { parseModule } from 'meriyah';

import { DecoratorErrors } from '@lwc/errors';
import { transmogrify } from '../transmogrify';
import { ImportManager } from '../imports';
import { replaceLwcImport, replaceNamedLwcExport, replaceAllLwcExport } from './lwc-import';
import { catalogTmplImport } from './catalog-tmpls';
import { catalogStaticStylesheets, catalogAndReplaceStyleImports } from './stylesheets';
import { addGenerateMarkupFunction } from './generate-markup';
import { catalogWireAdapters, isWireDecorator } from './wire';
import { validateApiProperty, validateApiMethod } from './api/validate';
import { isApiDecorator } from './api';
import { isTrackDecorator } from './track';
import { catalogWireAdapters, isWireDecorator } from './decorators/wire';
import { validateApiProperty, validateApiMethod } from './decorators/api/validate';
import { isApiDecorator } from './decorators/api';

import { removeDecoratorImport } from './remove-decorator-import';
import { generateError } from './errors';

import { type Visitors, type ComponentMetaState, isKeyIdentifier, isMethodKind } from './types';
import { type Visitors, type ComponentMetaState } from './types';
import { validateUniqueDecorator } from './decorators';
import type { ComponentTransformOptions } from '../shared';
import type {
Identifier as EsIdentifier,
Program as EsProgram,
Decorator as EsDecorator,
PropertyDefinition as EsPropertyDefinition,
MethodDefinition as EsMethodDefinition,
Identifier,
} from 'estree';
import type { CompilationMode } from '@lwc/shared';

Expand Down Expand Up @@ -97,6 +97,7 @@ const visitors: Visitors = {
},
PropertyDefinition(path, state) {
const node = path.node;

if (!isKeyIdentifier(node)) {
return;
}
Expand Down Expand Up @@ -144,7 +145,7 @@ const visitors: Visitors = {
} else if (isWireDecorator(decorators[0])) {
// Getters and setters are methods in the AST, but treated as properties by @wire
// Note that this means that their implementations are ignored!
if (isMethodKind(node, ['get', 'set'])) {
if (node.kind === 'get' || node.kind === 'set') {
const methodAsProp = b.propertyDefinition(
structuredClone(node.key),
null,
Expand Down Expand Up @@ -206,30 +207,6 @@ const visitors: Visitors = {
},
};

function validateUniqueDecorator(decorators: EsDecorator[]) {
if (decorators.length < 2) {
return;
}

const hasWire = decorators.some(isWireDecorator);
const hasApi = decorators.some(isApiDecorator);
const hasTrack = decorators.some(isTrackDecorator);

if (hasWire) {
if (hasApi) {
throw generateError(DecoratorErrors.CONFLICT_WITH_ANOTHER_DECORATOR, 'api');
}

if (hasTrack) {
throw generateError(DecoratorErrors.CONFLICT_WITH_ANOTHER_DECORATOR, 'track');
}
}

if (hasApi && hasTrack) {
throw generateError(DecoratorErrors.API_AND_TRACK_DECORATOR_CONFLICT);
}
}

export default function compileJS(
src: string,
filename: string,
Expand Down Expand Up @@ -282,3 +259,9 @@ export default function compileJS(
code: generate(ast, {}),
};
}

function isKeyIdentifier<T extends EsPropertyDefinition | EsMethodDefinition>(
node: T | undefined | null
): node is T & { key: Identifier } {
return node?.key.type === 'Identifier';
}
18 changes: 4 additions & 14 deletions packages/@lwc/ssr-compiler/src/compile-js/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,6 @@ export interface WireAdapter {
field: MethodDefinition | PropertyDefinition;
}

export function isMethodKind<
T extends MethodDefinition,
const K extends [T['kind'], ...T['kind'][]],
>(node: T, kind: K): node is T & { kind: K[number] } {
return kind.includes(node.kind);
}

export function isKeyIdentifier<T extends PropertyDefinition | MethodDefinition>(
node: T | undefined | null
): node is T & { key: Identifier } {
return node?.key.type === 'Identifier';
}

export interface ComponentMetaState {
// indicates whether the LightningElement subclass is found in the JS being traversed
isLWC: boolean;
Expand All @@ -62,7 +49,10 @@ export interface ComponentMetaState {
// the set of variable names associated with explicitly imported CSS files
staticStylesheetIds: Set<string> | null;
// the public (`@api`-annotated) fields of the component class
publicFields: Map<string, (MethodDefinition & { key: Identifier }) | PropertyDefinition>;
publicFields: Map<
string,
(MethodDefinition & { key: Identifier }) | (PropertyDefinition & { key: Identifier })
>;
// the private fields of the component class
privateFields: Set<string>;
// indicates whether the LightningElement has any wired props
Expand Down

0 comments on commit 2505c01

Please sign in to comment.