From 2505c01181ee2688e57f8b0b2905dc99f4e095b8 Mon Sep 17 00:00:00 2001 From: Matheus Cardoso Date: Fri, 20 Dec 2024 20:15:52 -0300 Subject: [PATCH] chore: move decorators to their own folder --- .../ssr-compiler/src/compile-js/api/types.ts | 16 ------ .../compile-js/{ => decorators}/api/consts.ts | 0 .../compile-js/{ => decorators}/api/index.ts | 6 +-- .../{ => decorators}/api/validate.ts | 38 ++++++++------ .../src/compile-js/decorators/index.ts | 36 ++++++++++++++ .../src/compile-js/{ => decorators}/track.ts | 0 .../src/compile-js/{ => decorators}/wire.ts | 10 ++-- .../src/compile-js/generate-markup.ts | 2 +- .../@lwc/ssr-compiler/src/compile-js/index.ts | 49 ++++++------------- .../@lwc/ssr-compiler/src/compile-js/types.ts | 18 ++----- 10 files changed, 86 insertions(+), 89 deletions(-) delete mode 100644 packages/@lwc/ssr-compiler/src/compile-js/api/types.ts rename packages/@lwc/ssr-compiler/src/compile-js/{ => decorators}/api/consts.ts (100%) rename packages/@lwc/ssr-compiler/src/compile-js/{ => decorators}/api/index.ts (87%) rename packages/@lwc/ssr-compiler/src/compile-js/{ => decorators}/api/validate.ts (74%) create mode 100644 packages/@lwc/ssr-compiler/src/compile-js/decorators/index.ts rename packages/@lwc/ssr-compiler/src/compile-js/{ => decorators}/track.ts (100%) rename packages/@lwc/ssr-compiler/src/compile-js/{ => decorators}/wire.ts (97%) diff --git a/packages/@lwc/ssr-compiler/src/compile-js/api/types.ts b/packages/@lwc/ssr-compiler/src/compile-js/api/types.ts deleted file mode 100644 index 5a63dc85dd..0000000000 --- a/packages/@lwc/ssr-compiler/src/compile-js/api/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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 type { MethodDefinition, Identifier, PropertyDefinition } from 'estree'; - -export type ApiMethodDefinition = MethodDefinition & { - key: Identifier; -}; -export type ApiPropertyDefinition = PropertyDefinition & { - key: Identifier; -}; - -export type ApiDefinition = ApiPropertyDefinition | ApiMethodDefinition; diff --git a/packages/@lwc/ssr-compiler/src/compile-js/api/consts.ts b/packages/@lwc/ssr-compiler/src/compile-js/decorators/api/consts.ts similarity index 100% rename from packages/@lwc/ssr-compiler/src/compile-js/api/consts.ts rename to packages/@lwc/ssr-compiler/src/compile-js/decorators/api/consts.ts diff --git a/packages/@lwc/ssr-compiler/src/compile-js/api/index.ts b/packages/@lwc/ssr-compiler/src/compile-js/decorators/api/index.ts similarity index 87% rename from packages/@lwc/ssr-compiler/src/compile-js/api/index.ts rename to packages/@lwc/ssr-compiler/src/compile-js/decorators/api/index.ts index 06a0cfea44..bbb791b887 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/api/index.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/decorators/api/index.ts @@ -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'; } diff --git a/packages/@lwc/ssr-compiler/src/compile-js/api/validate.ts b/packages/@lwc/ssr-compiler/src/compile-js/decorators/api/validate.ts similarity index 74% rename from packages/@lwc/ssr-compiler/src/compile-js/api/validate.ts rename to packages/@lwc/ssr-compiler/src/compile-js/decorators/api/validate.ts index d5bd5e5a09..f0f4badee3 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/api/validate.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/decorators/api/validate.ts @@ -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) { @@ -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) { diff --git a/packages/@lwc/ssr-compiler/src/compile-js/decorators/index.ts b/packages/@lwc/ssr-compiler/src/compile-js/decorators/index.ts new file mode 100644 index 0000000000..b447caf45a --- /dev/null +++ b/packages/@lwc/ssr-compiler/src/compile-js/decorators/index.ts @@ -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); + } +} diff --git a/packages/@lwc/ssr-compiler/src/compile-js/track.ts b/packages/@lwc/ssr-compiler/src/compile-js/decorators/track.ts similarity index 100% rename from packages/@lwc/ssr-compiler/src/compile-js/track.ts rename to packages/@lwc/ssr-compiler/src/compile-js/decorators/track.ts diff --git a/packages/@lwc/ssr-compiler/src/compile-js/wire.ts b/packages/@lwc/ssr-compiler/src/compile-js/decorators/wire.ts similarity index 97% rename from packages/@lwc/ssr-compiler/src/compile-js/wire.ts rename to packages/@lwc/ssr-compiler/src/compile-js/decorators/wire.ts index 64ee6ebf32..f690a9030f 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/wire.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/decorators/wire.ts @@ -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 { @@ -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 { properties: Property[]; @@ -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 ( diff --git a/packages/@lwc/ssr-compiler/src/compile-js/generate-markup.ts b/packages/@lwc/ssr-compiler/src/compile-js/generate-markup.ts index fb29f97ba1..23073babb8 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/generate-markup.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/generate-markup.ts @@ -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, diff --git a/packages/@lwc/ssr-compiler/src/compile-js/index.ts b/packages/@lwc/ssr-compiler/src/compile-js/index.ts index e6c8909a8d..9c075e9b23 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/index.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/index.ts @@ -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'; @@ -97,6 +97,7 @@ const visitors: Visitors = { }, PropertyDefinition(path, state) { const node = path.node; + if (!isKeyIdentifier(node)) { return; } @@ -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, @@ -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, @@ -282,3 +259,9 @@ export default function compileJS( code: generate(ast, {}), }; } + +function isKeyIdentifier( + node: T | undefined | null +): node is T & { key: Identifier } { + return node?.key.type === 'Identifier'; +} diff --git a/packages/@lwc/ssr-compiler/src/compile-js/types.ts b/packages/@lwc/ssr-compiler/src/compile-js/types.ts index 7d412eb819..98949a7764 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/types.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/types.ts @@ -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( - 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; @@ -62,7 +49,10 @@ export interface ComponentMetaState { // the set of variable names associated with explicitly imported CSS files staticStylesheetIds: Set | null; // the public (`@api`-annotated) fields of the component class - publicFields: Map; + publicFields: Map< + string, + (MethodDefinition & { key: Identifier }) | (PropertyDefinition & { key: Identifier }) + >; // the private fields of the component class privateFields: Set; // indicates whether the LightningElement has any wired props