From 3bf7147cfe33e13ad0f6d5a26dd150d8db32a922 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Tue, 19 Nov 2024 15:48:14 -0500 Subject: [PATCH 01/11] test(ssr): add test for wire config object --- .../src/__tests__/fixtures.spec.ts | 15 ++++++++++- .../fixtures/{wire => wire-basic}/error.txt | 0 .../{wire => wire-basic}/expected.html | 0 .../fixtures/{wire => wire-basic}/index.js | 0 .../modules/x/wire/adapter.js | 0 .../modules/x/wire/wire.html | 0 .../modules/x/wire/wire.js | 0 .../__tests__/fixtures/wire-config/error.txt | 0 .../fixtures/wire-config/expected.html | 23 ++++++++++++++++ .../__tests__/fixtures/wire-config/index.js | 3 +++ .../wire-config/modules/x/wire/adapter.js | 14 ++++++++++ .../wire-config/modules/x/wire/wire.html | 4 +++ .../wire-config/modules/x/wire/wire.js | 27 +++++++++++++++++++ 13 files changed, 85 insertions(+), 1 deletion(-) rename packages/@lwc/engine-server/src/__tests__/fixtures/{wire => wire-basic}/error.txt (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/{wire => wire-basic}/expected.html (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/{wire => wire-basic}/index.js (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/{wire => wire-basic}/modules/x/wire/adapter.js (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/{wire => wire-basic}/modules/x/wire/wire.html (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/{wire => wire-basic}/modules/x/wire/wire.js (100%) create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/error.txt create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/expected.html create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/index.js create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/adapter.js create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.html create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures.spec.ts b/packages/@lwc/engine-server/src/__tests__/fixtures.spec.ts index 2dcbf8ca38..83a1154fc3 100755 --- a/packages/@lwc/engine-server/src/__tests__/fixtures.spec.ts +++ b/packages/@lwc/engine-server/src/__tests__/fixtures.spec.ts @@ -6,7 +6,7 @@ */ import path from 'node:path'; -import { vi, describe } from 'vitest'; +import { vi, describe, beforeEach, afterEach } from 'vitest'; import { rollup } from 'rollup'; import lwcRollupPlugin, { RollupLwcOptions } from '@lwc/rollup-plugin'; import { testFixtureDir, formatHTML } from '@lwc/test-utils-lwc-internals'; @@ -148,6 +148,19 @@ function testFixtures(options?: RollupLwcOptions) { } describe.concurrent('fixtures', () => { + let originalFlags: any; + beforeEach(() => { + originalFlags = (globalThis as any).lwcRuntimeFlags; + (globalThis as any).lwcRuntimeFlags = { + ...(globalThis as any).lwcRuntimeFlags, + ENABLE_WIRE_SYNC_EMIT: true, + }; + }); + + afterEach(() => { + (globalThis as any).lwcRuntimeFlags = originalFlags; + }); + describe.concurrent('default', () => { testFixtures(); }); diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/error.txt similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/error.txt rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/error.txt diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/expected.html similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/expected.html rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/expected.html diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/index.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/index.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/index.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/modules/x/wire/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/adapter.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/modules/x/wire/adapter.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/adapter.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/modules/x/wire/wire.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/wire.html similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/modules/x/wire/wire.html rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/wire.html diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/modules/x/wire/wire.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/wire.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/modules/x/wire/wire.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/wire.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/error.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/expected.html new file mode 100644 index 0000000000..a584db6ede --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/expected.html @@ -0,0 +1,23 @@ + + + \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/index.js new file mode 100644 index 0000000000..70aed90174 --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/index.js @@ -0,0 +1,3 @@ +export const tagName = 'x-wire'; +export { default } from 'x/wire'; +export * from 'x/wire'; \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/adapter.js new file mode 100644 index 0000000000..405f2a3765 --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/adapter.js @@ -0,0 +1,14 @@ +export class adapter { + constructor(dataCallback) { + this.dc = dataCallback; + } + + connect() {} + + update(config) { + // Quotes are encoded in the output, which is ugly + this.dc(JSON.stringify(config, null, 4).replace(/"/g, '')); + } + + disconnect() {} +} diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.html new file mode 100644 index 0000000000..9323264c3a --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.html @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.js new file mode 100644 index 0000000000..0f3ab9c133 --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.js @@ -0,0 +1,27 @@ +import { LightningElement, wire } from 'lwc'; + +import { adapter } from './adapter'; + +const variable = 0x1134 + +export default class Wire extends LightningElement { + @wire(adapter, { + variable, + prop: 'not magic', + magic: '$cmpProp', + array: ['value'], + fakeMagic: ['$cmpProp', "$ string in arrays aren't magic"], + true: true, + false: false, + 0: 0, + null: null, + undefined: undefined, + Infinity: Infinity, + NaN: NaN, + '': '', + why(){} + }) + wiredProp; + + cmpProp = 123; +} \ No newline at end of file From 69d29b814de6fa8bac9220446c4ac6ea3f7fdd6f Mon Sep 17 00:00:00 2001 From: James Tu Date: Tue, 19 Nov 2024 13:53:26 -0800 Subject: [PATCH 02/11] feat: add wire adapter param validation --- .../@lwc/ssr-compiler/src/compile-js/wire.ts | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/packages/@lwc/ssr-compiler/src/compile-js/wire.ts b/packages/@lwc/ssr-compiler/src/compile-js/wire.ts index dabd55848d..d5bc0b11b7 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/wire.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/wire.ts @@ -9,9 +9,7 @@ import { is, builders as b } from 'estree-toolkit'; import { esTemplate } from '../estemplate'; import { isValidIdentifier } from '../shared'; -import type { PropertyDefinition as EsPropertyDefinitionWithDecorators } from 'meriyah/dist/src/estree'; import type { - Expression, PropertyDefinition, ObjectExpression, Statement, @@ -34,7 +32,7 @@ function extractWireConfig( const { key, value } = objProp; if (!is.identifier(key)) { - throw new Error(`@wire config entry key must be an identifer; found ${key.type}`); + throw new Error(`@wire config entry key must be an identifier; found ${key.type}`); } if (!is.literal(value) || typeof value.value !== 'string' || value.value[0] !== '$') { throw new Error('@wire config entry values must be strings starting with a $'); @@ -62,38 +60,46 @@ export function catalogWireAdapters( state: ComponentMetaState, node: PropertyDefinition | MethodDefinition ) { - if (!is.identifier(node.key)) { - throw new Error( - 'Unimplemented: wires that decorate non-identifiers are not currently supported.' - ); + const { decorators } = node; + if (decorators.length > 1) { + throw new Error('todo - multiple decorators at once'); } - const { name } = node.key; - const { decorators } = node as EsPropertyDefinitionWithDecorators; - if (decorators?.length !== 1) { - throw new Error('Only one decorator can be applied to a single field.'); + // validate the parameters + const wireDecorator = decorators[0].expression; + if (!is.callExpression(wireDecorator)) { + throw new Error('todo - invalid usage'); } - const expression = decorators[0].expression as Expression; - if (!is.callExpression(expression)) { - throw new Error('The @wire decorator must be called.'); + const args = wireDecorator.arguments; + if (args.length === 0 || args.length > 2) { + throw new Error('todo - wrong number of args'); } - const { arguments: args } = expression; - const [adapterConstructorId, config] = args; - if (!is.identifier(adapterConstructorId)) { - throw new Error('The @wire decorator must reference a wire adapter class.'); + const [id, config] = args; + if (is.spreadElement(id) || is.spreadElement(config)) { + throw new Error('todo - spread in params'); } - if (config && !is.objectExpression(config)) { - throw new Error('Invalid config provided to @wire decorator; expected an object literal.'); + + // validate id + if (is.memberExpression(id)) { + if (id.computed) { + throw new Error('todo - FUNCTION_IDENTIFIER_CANNOT_HAVE_COMPUTED_PROPS'); + } + if (!is.identifier(id.object)) { + throw new Error('todo - FUNCTION_IDENTIFIER_CANNOT_HAVE_NESTED_MEMBER_EXRESSIONS'); + } + } else if (!is.identifier(id)) { + throw new Error('todo - invalid adapter name'); } - const fieldtype = - node.type === 'MethodDefinition' && node.kind === 'method' ? 'method' : 'property'; + // FIXME: Validate that wire adapter is imported + + // conditionally valid the config state.wireAdapters = [ ...state.wireAdapters, - extractWireConfig(name, adapterConstructorId.name, fieldtype, config), + // extractWireConfig(name, adapterConstructorId.name, fieldtype, config), ]; } From 71a7f193c844b389d08ce61e780333af51dcbca3 Mon Sep 17 00:00:00 2001 From: James Tu Date: Tue, 19 Nov 2024 14:13:50 -0800 Subject: [PATCH 03/11] test: add some test fixtures for wire --- .../__tests__/fixtures/wire-basic/error.txt | 0 .../fixtures/wire-basic/expected.html | 5 ---- .../__tests__/fixtures/wire-basic/index.js | 3 --- .../wire-basic/modules/x/wire/adapter.js | 16 ----------- .../wire-basic/modules/x/wire/wire.html | 3 --- .../wire-basic/modules/x/wire/wire.js | 12 --------- .../__tests__/fixtures/wire-config/error.txt | 0 .../fixtures/wire-config/expected.html | 23 ---------------- .../__tests__/fixtures/wire-config/index.js | 3 --- .../wire-config/modules/x/wire/adapter.js | 14 ---------- .../wire-config/modules/x/wire/wire.html | 4 --- .../wire-config/modules/x/wire/wire.js | 27 ------------------- 12 files changed, 110 deletions(-) delete mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/error.txt delete mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/expected.html delete mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/index.js delete mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/adapter.js delete mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/wire.html delete mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/wire.js delete mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/error.txt delete mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/expected.html delete mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/index.js delete mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/adapter.js delete mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.html delete mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/error.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/expected.html deleted file mode 100644 index b3477dc689..0000000000 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/expected.html +++ /dev/null @@ -1,5 +0,0 @@ - - - \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/index.js deleted file mode 100644 index 70aed90174..0000000000 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export const tagName = 'x-wire'; -export { default } from 'x/wire'; -export * from 'x/wire'; \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/adapter.js deleted file mode 100644 index 6adf77517b..0000000000 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/adapter.js +++ /dev/null @@ -1,16 +0,0 @@ -export let isAdapterInvoked = false; - -export class adapter { - constructor(dataCallback) { - this.dc = dataCallback; - } - - connect() {} - - update() { - isAdapterInvoked = true; - this.dc(true); - } - - disconnect() {} -} diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/wire.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/wire.html deleted file mode 100644 index 16f6c6192c..0000000000 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/wire.html +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/wire.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/wire.js deleted file mode 100644 index a7302b4b3a..0000000000 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-basic/modules/x/wire/wire.js +++ /dev/null @@ -1,12 +0,0 @@ -import { LightningElement, wire } from 'lwc'; - -import { adapter, isAdapterInvoked } from './adapter'; - -export default class Wire extends LightningElement { - @wire(adapter) - wiredProp; - - get isAdapterInvoked() { - return isAdapterInvoked; - } -} \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/error.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/expected.html deleted file mode 100644 index a584db6ede..0000000000 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/expected.html +++ /dev/null @@ -1,23 +0,0 @@ - - - \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/index.js deleted file mode 100644 index 70aed90174..0000000000 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export const tagName = 'x-wire'; -export { default } from 'x/wire'; -export * from 'x/wire'; \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/adapter.js deleted file mode 100644 index 405f2a3765..0000000000 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/adapter.js +++ /dev/null @@ -1,14 +0,0 @@ -export class adapter { - constructor(dataCallback) { - this.dc = dataCallback; - } - - connect() {} - - update(config) { - // Quotes are encoded in the output, which is ugly - this.dc(JSON.stringify(config, null, 4).replace(/"/g, '')); - } - - disconnect() {} -} diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.html deleted file mode 100644 index 9323264c3a..0000000000 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.html +++ /dev/null @@ -1,4 +0,0 @@ - \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.js deleted file mode 100644 index 0f3ab9c133..0000000000 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire-config/modules/x/wire/wire.js +++ /dev/null @@ -1,27 +0,0 @@ -import { LightningElement, wire } from 'lwc'; - -import { adapter } from './adapter'; - -const variable = 0x1134 - -export default class Wire extends LightningElement { - @wire(adapter, { - variable, - prop: 'not magic', - magic: '$cmpProp', - array: ['value'], - fakeMagic: ['$cmpProp', "$ string in arrays aren't magic"], - true: true, - false: false, - 0: 0, - null: null, - undefined: undefined, - Infinity: Infinity, - NaN: NaN, - '': '', - why(){} - }) - wiredProp; - - cmpProp = 123; -} \ No newline at end of file From f033910c7c54b140a6e4a68bcbcbde8cbaaea588 Mon Sep 17 00:00:00 2001 From: James Tu Date: Tue, 19 Nov 2024 14:14:22 -0800 Subject: [PATCH 04/11] test: add test fixtures for wire --- .../fixtures/wire/wire-basic/error.txt | 0 .../fixtures/wire/wire-basic/expected.html | 5 ++++ .../fixtures/wire/wire-basic/index.js | 3 +++ .../wire/wire-basic/modules/x/wire/adapter.js | 16 +++++++++++ .../wire/wire-basic/modules/x/wire/wire.html | 3 +++ .../wire/wire-basic/modules/x/wire/wire.js | 12 +++++++++ .../fixtures/wire/wire-config/error.txt | 0 .../fixtures/wire/wire-config/expected.html | 23 ++++++++++++++++ .../fixtures/wire/wire-config/index.js | 3 +++ .../wire-config/modules/x/wire/adapter.js | 14 ++++++++++ .../wire/wire-config/modules/x/wire/wire.html | 4 +++ .../wire/wire-config/modules/x/wire/wire.js | 27 +++++++++++++++++++ .../fixtures/wire/wired-field/error.txt | 0 .../fixtures/wire/wired-field/expected.html | 11 ++++++++ .../fixtures/wire/wired-field/index.js | 3 +++ .../wired-field/modules/x/adapter/adapter.js | 14 ++++++++++ .../wire/wired-field/modules/x/wire/wire.html | 3 +++ .../wire/wired-field/modules/x/wire/wire.js | 8 ++++++ .../fixtures/wire/wired-method/error.txt | 0 .../fixtures/wire/wired-method/expected.html | 11 ++++++++ .../fixtures/wire/wired-method/index.js | 3 +++ .../wired-method/modules/x/adapter/adapter.js | 14 ++++++++++ .../wired-method/modules/x/wire/wire.html | 3 +++ .../wire/wired-method/modules/x/wire/wire.js | 11 ++++++++ 24 files changed, 191 insertions(+) create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/error.txt create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/expected.html create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/index.js create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/adapter.js create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/wire.html create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/wire.js create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/error.txt create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/expected.html create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/index.js create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/adapter.js create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/wire.html create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/wire.js create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/error.txt create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/expected.html create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/index.js create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/adapter/adapter.js create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/wire/wire.html create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/wire/wire.js create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/error.txt create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/expected.html create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/index.js create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/adapter/adapter.js create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/wire/wire.html create mode 100644 packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/wire/wire.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/error.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/expected.html new file mode 100644 index 0000000000..b3477dc689 --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/expected.html @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/index.js new file mode 100644 index 0000000000..70aed90174 --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/index.js @@ -0,0 +1,3 @@ +export const tagName = 'x-wire'; +export { default } from 'x/wire'; +export * from 'x/wire'; \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/adapter.js new file mode 100644 index 0000000000..6adf77517b --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/adapter.js @@ -0,0 +1,16 @@ +export let isAdapterInvoked = false; + +export class adapter { + constructor(dataCallback) { + this.dc = dataCallback; + } + + connect() {} + + update() { + isAdapterInvoked = true; + this.dc(true); + } + + disconnect() {} +} diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/wire.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/wire.html new file mode 100644 index 0000000000..16f6c6192c --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/wire.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/wire.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/wire.js new file mode 100644 index 0000000000..a7302b4b3a --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/wire.js @@ -0,0 +1,12 @@ +import { LightningElement, wire } from 'lwc'; + +import { adapter, isAdapterInvoked } from './adapter'; + +export default class Wire extends LightningElement { + @wire(adapter) + wiredProp; + + get isAdapterInvoked() { + return isAdapterInvoked; + } +} \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/error.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/expected.html new file mode 100644 index 0000000000..a584db6ede --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/expected.html @@ -0,0 +1,23 @@ + + + \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/index.js new file mode 100644 index 0000000000..70aed90174 --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/index.js @@ -0,0 +1,3 @@ +export const tagName = 'x-wire'; +export { default } from 'x/wire'; +export * from 'x/wire'; \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/adapter.js new file mode 100644 index 0000000000..405f2a3765 --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/adapter.js @@ -0,0 +1,14 @@ +export class adapter { + constructor(dataCallback) { + this.dc = dataCallback; + } + + connect() {} + + update(config) { + // Quotes are encoded in the output, which is ugly + this.dc(JSON.stringify(config, null, 4).replace(/"/g, '')); + } + + disconnect() {} +} diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/wire.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/wire.html new file mode 100644 index 0000000000..9323264c3a --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/wire.html @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/wire.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/wire.js new file mode 100644 index 0000000000..0f3ab9c133 --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/wire.js @@ -0,0 +1,27 @@ +import { LightningElement, wire } from 'lwc'; + +import { adapter } from './adapter'; + +const variable = 0x1134 + +export default class Wire extends LightningElement { + @wire(adapter, { + variable, + prop: 'not magic', + magic: '$cmpProp', + array: ['value'], + fakeMagic: ['$cmpProp', "$ string in arrays aren't magic"], + true: true, + false: false, + 0: 0, + null: null, + undefined: undefined, + Infinity: Infinity, + NaN: NaN, + '': '', + why(){} + }) + wiredProp; + + cmpProp = 123; +} \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/error.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/expected.html new file mode 100644 index 0000000000..218386bc3c --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/expected.html @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/index.js new file mode 100644 index 0000000000..70aed90174 --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/index.js @@ -0,0 +1,3 @@ +export const tagName = 'x-wire'; +export { default } from 'x/wire'; +export * from 'x/wire'; \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/adapter/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/adapter/adapter.js new file mode 100644 index 0000000000..2a24199363 --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/adapter/adapter.js @@ -0,0 +1,14 @@ +export default class adapter { + constructor(dataCallback) { + this.dc = dataCallback; + } + + connect() {} + + update(config) { + // Quotes are encoded in the output, which is ugly + this.dc(JSON.stringify(config, null, 4).replace(/"/g, '')); + } + + disconnect() {} +} diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/wire/wire.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/wire/wire.html new file mode 100644 index 0000000000..1db03c7f9f --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/wire/wire.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/wire/wire.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/wire/wire.js new file mode 100644 index 0000000000..3e5130b9ea --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/wire/wire.js @@ -0,0 +1,8 @@ +import { wire, LightningElement } from "lwc"; +import WireAdapter from "x/adapter"; +export default class Test extends LightningElement { + @wire(WireAdapter, { key1: "$prop1", key2: ["fixed", "array"] }) + wiredProp; + + prop1 = 'foo'; +} diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/error.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/expected.html new file mode 100644 index 0000000000..218386bc3c --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/expected.html @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/index.js new file mode 100644 index 0000000000..70aed90174 --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/index.js @@ -0,0 +1,3 @@ +export const tagName = 'x-wire'; +export { default } from 'x/wire'; +export * from 'x/wire'; \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/adapter/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/adapter/adapter.js new file mode 100644 index 0000000000..2a24199363 --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/adapter/adapter.js @@ -0,0 +1,14 @@ +export default class adapter { + constructor(dataCallback) { + this.dc = dataCallback; + } + + connect() {} + + update(config) { + // Quotes are encoded in the output, which is ugly + this.dc(JSON.stringify(config, null, 4).replace(/"/g, '')); + } + + disconnect() {} +} diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/wire/wire.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/wire/wire.html new file mode 100644 index 0000000000..c70725ad81 --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/wire/wire.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/wire/wire.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/wire/wire.js new file mode 100644 index 0000000000..3e71c1c52d --- /dev/null +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/wire/wire.js @@ -0,0 +1,11 @@ +import { wire, LightningElement } from "lwc"; +import WireAdapter from "x/adapter"; +export default class Test extends LightningElement { + @wire(WireAdapter, { key1: "$prop1", key2: ["fixed", "array"] }) + wiredMethod(value) { + this.externalProp = value; + } + + prop1 = 'foo'; + externalProp; +} From 82ed436e2ccbe2974161f60ecc5f0d9be823720d Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Tue, 19 Nov 2024 15:08:10 -0800 Subject: [PATCH 05/11] test: refactor tests --- .../@lwc/engine-server/src/__tests__/fixtures.spec.ts | 10 +++------- .../fixtures/wire/{wire-basic => basic}/error.txt | 0 .../fixtures/wire/{wire-basic => basic}/expected.html | 0 .../fixtures/wire/{wire-basic => basic}/index.js | 0 .../{wire-basic => basic}/modules/x/wire/adapter.js | 0 .../{wire-basic => basic}/modules/x/wire/wire.html | 0 .../wire/{wire-basic => basic}/modules/x/wire/wire.js | 0 .../fixtures/wire/{wire-config => config}/error.txt | 0 .../wire/{wire-config => config}/expected.html | 0 .../fixtures/wire/{wire-config => config}/index.js | 0 .../{wire-config => config}/modules/x/wire/adapter.js | 0 .../{wire-config => config}/modules/x/wire/wire.html | 0 .../{wire-config => config}/modules/x/wire/wire.js | 0 .../fixtures/wire/{wired-field => field}/error.txt | 0 .../fixtures/wire/{wired-field => field}/expected.html | 0 .../fixtures/wire/{wired-field => field}/index.js | 0 .../modules/x/adapter/adapter.js | 0 .../{wired-field => field}/modules/x/wire/wire.html | 0 .../wire/{wired-field => field}/modules/x/wire/wire.js | 0 .../fixtures/wire/{wired-method => method}/error.txt | 0 .../wire/{wired-method => method}/expected.html | 0 .../fixtures/wire/{wired-method => method}/index.js | 0 .../modules/x/adapter/adapter.js | 0 .../{wired-method => method}/modules/x/wire/wire.html | 0 .../{wired-method => method}/modules/x/wire/wire.js | 0 25 files changed, 3 insertions(+), 7 deletions(-) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wire-basic => basic}/error.txt (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wire-basic => basic}/expected.html (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wire-basic => basic}/index.js (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wire-basic => basic}/modules/x/wire/adapter.js (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wire-basic => basic}/modules/x/wire/wire.html (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wire-basic => basic}/modules/x/wire/wire.js (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wire-config => config}/error.txt (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wire-config => config}/expected.html (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wire-config => config}/index.js (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wire-config => config}/modules/x/wire/adapter.js (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wire-config => config}/modules/x/wire/wire.html (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wire-config => config}/modules/x/wire/wire.js (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wired-field => field}/error.txt (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wired-field => field}/expected.html (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wired-field => field}/index.js (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wired-field => field}/modules/x/adapter/adapter.js (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wired-field => field}/modules/x/wire/wire.html (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wired-field => field}/modules/x/wire/wire.js (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wired-method => method}/error.txt (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wired-method => method}/expected.html (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wired-method => method}/index.js (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wired-method => method}/modules/x/adapter/adapter.js (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wired-method => method}/modules/x/wire/wire.html (100%) rename packages/@lwc/engine-server/src/__tests__/fixtures/wire/{wired-method => method}/modules/x/wire/wire.js (100%) diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures.spec.ts b/packages/@lwc/engine-server/src/__tests__/fixtures.spec.ts index 83a1154fc3..69ebd309a2 100755 --- a/packages/@lwc/engine-server/src/__tests__/fixtures.spec.ts +++ b/packages/@lwc/engine-server/src/__tests__/fixtures.spec.ts @@ -10,6 +10,7 @@ import { vi, describe, beforeEach, afterEach } from 'vitest'; import { rollup } from 'rollup'; import lwcRollupPlugin, { RollupLwcOptions } from '@lwc/rollup-plugin'; import { testFixtureDir, formatHTML } from '@lwc/test-utils-lwc-internals'; +import { setFeatureFlagForTest } from '../index'; import type * as lwc from '../index'; interface FixtureModule { @@ -148,17 +149,12 @@ function testFixtures(options?: RollupLwcOptions) { } describe.concurrent('fixtures', () => { - let originalFlags: any; beforeEach(() => { - originalFlags = (globalThis as any).lwcRuntimeFlags; - (globalThis as any).lwcRuntimeFlags = { - ...(globalThis as any).lwcRuntimeFlags, - ENABLE_WIRE_SYNC_EMIT: true, - }; + setFeatureFlagForTest('ENABLE_WIRE_SYNC_EMIT', true); }); afterEach(() => { - (globalThis as any).lwcRuntimeFlags = originalFlags; + setFeatureFlagForTest('ENABLE_WIRE_SYNC_EMIT', false); }); describe.concurrent('default', () => { diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/basic/error.txt similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/error.txt rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/basic/error.txt diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/basic/expected.html similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/expected.html rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/basic/expected.html diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/basic/index.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/index.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/basic/index.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/basic/modules/x/wire/adapter.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/adapter.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/basic/modules/x/wire/adapter.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/wire.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/basic/modules/x/wire/wire.html similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/wire.html rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/basic/modules/x/wire/wire.html diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/wire.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/basic/modules/x/wire/wire.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-basic/modules/x/wire/wire.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/basic/modules/x/wire/wire.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/error.txt similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/error.txt rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/error.txt diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/expected.html similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/expected.html rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/expected.html diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/index.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/index.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/index.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/modules/x/wire/adapter.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/adapter.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/modules/x/wire/adapter.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/wire.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/modules/x/wire/wire.html similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/wire.html rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/modules/x/wire/wire.html diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/wire.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/modules/x/wire/wire.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wire-config/modules/x/wire/wire.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/modules/x/wire/wire.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/error.txt similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/error.txt rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/error.txt diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/expected.html similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/expected.html rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/expected.html diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/index.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/index.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/index.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/adapter/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/modules/x/adapter/adapter.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/adapter/adapter.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/modules/x/adapter/adapter.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/wire/wire.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/modules/x/wire/wire.html similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/wire/wire.html rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/modules/x/wire/wire.html diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/wire/wire.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/modules/x/wire/wire.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-field/modules/x/wire/wire.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/modules/x/wire/wire.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/error.txt similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/error.txt rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/error.txt diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/expected.html similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/expected.html rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/expected.html diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/index.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/index.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/index.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/adapter/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/modules/x/adapter/adapter.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/adapter/adapter.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/modules/x/adapter/adapter.js diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/wire/wire.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/modules/x/wire/wire.html similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/wire/wire.html rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/modules/x/wire/wire.html diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/wire/wire.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/modules/x/wire/wire.js similarity index 100% rename from packages/@lwc/engine-server/src/__tests__/fixtures/wire/wired-method/modules/x/wire/wire.js rename to packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/modules/x/wire/wire.js From c50fc58795e5720459031828a8b0e14543628ab4 Mon Sep 17 00:00:00 2001 From: Eugene Kashida Date: Wed, 20 Nov 2024 12:04:43 -0800 Subject: [PATCH 06/11] feat: validate that the adapter is an imported module --- .../@lwc/ssr-compiler/src/compile-js/index.ts | 2 +- .../@lwc/ssr-compiler/src/compile-js/wire.ts | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/@lwc/ssr-compiler/src/compile-js/index.ts b/packages/@lwc/ssr-compiler/src/compile-js/index.ts index be704d543f..6cf7fa8042 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/index.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/index.ts @@ -80,7 +80,7 @@ const visitors: Visitors = { is.identifier(decoratedExpression.callee) && decoratedExpression.callee.name === 'wire' ) { - catalogWireAdapters(state, node); + catalogWireAdapters(path, state); state.privateFields.push(node.key.name); } else { state.privateFields.push(node.key.name); diff --git a/packages/@lwc/ssr-compiler/src/compile-js/wire.ts b/packages/@lwc/ssr-compiler/src/compile-js/wire.ts index d5bc0b11b7..fa59dfcfab 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/wire.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/wire.ts @@ -5,7 +5,7 @@ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT */ -import { is, builders as b } from 'estree-toolkit'; +import { is, builders as b, NodePath } from 'estree-toolkit'; import { esTemplate } from '../estemplate'; import { isValidIdentifier } from '../shared'; @@ -57,10 +57,12 @@ function extractWireConfig( } export function catalogWireAdapters( + path: NodePath, state: ComponentMetaState, - node: PropertyDefinition | MethodDefinition ) { + const node = path.node!; const { decorators } = node; + if (decorators.length > 1) { throw new Error('todo - multiple decorators at once'); } @@ -81,6 +83,8 @@ export function catalogWireAdapters( throw new Error('todo - spread in params'); } + let wireBinding; + // validate id if (is.memberExpression(id)) { if (id.computed) { @@ -89,11 +93,17 @@ export function catalogWireAdapters( if (!is.identifier(id.object)) { throw new Error('todo - FUNCTION_IDENTIFIER_CANNOT_HAVE_NESTED_MEMBER_EXRESSIONS'); } + wireBinding = id.object.name; } else if (!is.identifier(id)) { throw new Error('todo - invalid adapter name'); + } else { + wireBinding = id.name; } - // FIXME: Validate that wire adapter is imported + // This is not the exact same validation done in @lwc/babel-plugin-component but it accomplishes the same thing + if (path.scope?.getBinding(wireBinding)?.kind !== 'module') { + throw new Error('todo - WIRE_ADAPTER_SHOULD_BE_IMPORTED'); + } // conditionally valid the config From 290ee9fc4ece3a05011e0229abcc406829dedcc9 Mon Sep 17 00:00:00 2001 From: Eugene Kashida Date: Wed, 20 Nov 2024 13:46:24 -0800 Subject: [PATCH 07/11] feat: add config validation --- .../@lwc/ssr-compiler/src/compile-js/wire.ts | 55 ++++++++++++------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/packages/@lwc/ssr-compiler/src/compile-js/wire.ts b/packages/@lwc/ssr-compiler/src/compile-js/wire.ts index fa59dfcfab..a1362230a3 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/wire.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/wire.ts @@ -26,26 +26,16 @@ function extractWireConfig( ): WireAdapter { const extractedConfig = config?.properties?.map?.((objProp) => { - if (!is.property(objProp)) { - throw new Error('Object spread syntax is disallowed in @wire config.'); + if (is.property(objProp)) { + const { key, value } = objProp; + if (is.literal(value) && typeof value.value === 'string') { + const referencedField = value.value.slice(1); + return { + configKey: key.name, + referencedField, + }; + } } - const { key, value } = objProp; - - if (!is.identifier(key)) { - throw new Error(`@wire config entry key must be an identifier; found ${key.type}`); - } - if (!is.literal(value) || typeof value.value !== 'string' || value.value[0] !== '$') { - throw new Error('@wire config entry values must be strings starting with a $'); - } - const referencedField = value.value.slice(1); - if (!isValidIdentifier(referencedField)) { - throw new Error(`@wire config referenced invalid field: ${referencedField}`); - } - - return { - configKey: key.name, - referencedField, - }; }) ?? []; return { @@ -105,7 +95,32 @@ export function catalogWireAdapters( throw new Error('todo - WIRE_ADAPTER_SHOULD_BE_IMPORTED'); } - // conditionally valid the config + if (config) { + if (!is.objectExpression(config)) { + throw new Error('todo - CONFIG_OBJECT_SHOULD_BE_SECOND_PARAMETER'); + } + for (const property of config.properties) { + if (!is.property(property) || !property.computed) continue; + const key = property.key; + if (is.identifier(key)) { + const binding = path.scope.getBinding(key.name); + // TODO [#3956]: Investigate allowing imported constants + if (binding?.kind === 'const') continue; + // By default, the identifier `undefined` has no binding (when it's actually undefined), + // but has a binding if it's used as a variable (e.g. `let undefined = "don't do this"`) + if (key.name === 'undefined' && !binding) continue; + } else if (is.literal(key)) { + 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. + throw new Error('todo - COMPUTED_PROPERTY_CANNOT_BE_TEMPLATE_LITERAL'); + } else if ('regex' in key) { + continue; + } + } + } + throw new Error('todo - COMPUTED_PROPERTY_MUST_BE_CONSTANT_OR_LITERAL'); + } state.wireAdapters = [ ...state.wireAdapters, From 36444c5de3f76d60118d97242c470bf8c5f07798 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Thu, 21 Nov 2024 12:34:58 -0500 Subject: [PATCH 08/11] feat(ssr): fix wire adapter assumptions --- .../@lwc/ssr-compiler/src/compile-js/index.ts | 2 +- .../@lwc/ssr-compiler/src/compile-js/types.ts | 19 +- .../@lwc/ssr-compiler/src/compile-js/wire.ts | 201 +++++++++--------- packages/@lwc/ssr-compiler/src/estemplate.ts | 2 +- 4 files changed, 118 insertions(+), 106 deletions(-) diff --git a/packages/@lwc/ssr-compiler/src/compile-js/index.ts b/packages/@lwc/ssr-compiler/src/compile-js/index.ts index 6cf7fa8042..5b4b04f7ef 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/index.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/index.ts @@ -117,7 +117,7 @@ const visitors: Visitors = { is.identifier(decoratedExpression.callee) && decoratedExpression.callee.name === 'wire' ) { - catalogWireAdapters(state, node); + catalogWireAdapters(path, state); } switch (node.key.name) { diff --git a/packages/@lwc/ssr-compiler/src/compile-js/types.ts b/packages/@lwc/ssr-compiler/src/compile-js/types.ts index 81412f60a3..335fc0e2f3 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/types.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/types.ts @@ -6,18 +6,21 @@ */ import type { traverse } from 'estree-toolkit'; -import type { Node } from 'estree'; +import type { + Identifier, + MemberExpression, + MethodDefinition, + Node, + ObjectExpression, + PropertyDefinition, +} from 'estree'; export type Visitors = Parameters>[1]; export interface WireAdapter { - fieldName: string; - adapterConstructorId: string; - config: Array<{ - configKey: string; - referencedField: string; - }>; - fieldType: 'property' | 'method'; + adapterId: Identifier | MemberExpression; + config: ObjectExpression; + field: MethodDefinition | PropertyDefinition; } export interface ComponentMetaState { diff --git a/packages/@lwc/ssr-compiler/src/compile-js/wire.ts b/packages/@lwc/ssr-compiler/src/compile-js/wire.ts index a1362230a3..0755e2985e 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/wire.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/wire.ts @@ -6,51 +6,38 @@ */ import { is, builders as b, NodePath } from 'estree-toolkit'; +import { produce } from 'immer'; import { esTemplate } from '../estemplate'; -import { isValidIdentifier } from '../shared'; import type { PropertyDefinition, ObjectExpression, - Statement, MethodDefinition, ExpressionStatement, + Expression, + Identifier, + MemberExpression, + Property, + BlockStatement, } from 'estree'; import type { ComponentMetaState, WireAdapter } from './types'; -function extractWireConfig( - fieldName: string, - adapterConstructorId: string, - fieldType: 'method' | 'property', - config?: ObjectExpression -): WireAdapter { - const extractedConfig = - config?.properties?.map?.((objProp) => { - if (is.property(objProp)) { - const { key, value } = objProp; - if (is.literal(value) && typeof value.value === 'string') { - const referencedField = value.value.slice(1); - return { - configKey: key.name, - referencedField, - }; - } - } - }) ?? []; - - return { - fieldName, - fieldType, - adapterConstructorId, - config: extractedConfig, - }; +interface NoSpreadObjectExpression extends Omit { + properties: Property[]; } -export function catalogWireAdapters( - path: NodePath, - state: ComponentMetaState, -) { - const node = path.node!; +function bMemberExpressionChain(props: string[]): MemberExpression { + // Technically an incorrect assertion, but it works fine... + let expr: MemberExpression = b.identifier('instance') as any; + for (const prop of props) { + expr = b.memberExpression(expr, b.literal(prop), true); + } + return expr; +} + +function getWireParams( + node: MethodDefinition | PropertyDefinition +): [Expression, Expression | undefined] { const { decorators } = node; if (decorators.length > 1) { @@ -72,10 +59,16 @@ export function catalogWireAdapters( if (is.spreadElement(id) || is.spreadElement(config)) { throw new Error('todo - spread in params'); } + return [id, config]; +} - let wireBinding; +function validateWireId( + id: Expression, + path: NodePath +): asserts id is Identifier | MemberExpression { + // name of identifier or object used in member expression (e.g. "foo" for `foo.bar`) + let wireAdapterVar: string; - // validate id if (is.memberExpression(id)) { if (id.computed) { throw new Error('todo - FUNCTION_IDENTIFIER_CANNOT_HAVE_COMPUTED_PROPS'); @@ -83,63 +76,86 @@ export function catalogWireAdapters( if (!is.identifier(id.object)) { throw new Error('todo - FUNCTION_IDENTIFIER_CANNOT_HAVE_NESTED_MEMBER_EXRESSIONS'); } - wireBinding = id.object.name; + wireAdapterVar = id.object.name; } else if (!is.identifier(id)) { throw new Error('todo - invalid adapter name'); } else { - wireBinding = id.name; + wireAdapterVar = id.name; } // This is not the exact same validation done in @lwc/babel-plugin-component but it accomplishes the same thing - if (path.scope?.getBinding(wireBinding)?.kind !== 'module') { + if (path.scope?.getBinding(wireAdapterVar)?.kind !== 'module') { throw new Error('todo - WIRE_ADAPTER_SHOULD_BE_IMPORTED'); } +} - if (config) { - if (!is.objectExpression(config)) { - throw new Error('todo - CONFIG_OBJECT_SHOULD_BE_SECOND_PARAMETER'); - } - for (const property of config.properties) { - if (!is.property(property) || !property.computed) continue; - const key = property.key; - if (is.identifier(key)) { - const binding = path.scope.getBinding(key.name); - // TODO [#3956]: Investigate allowing imported constants - if (binding?.kind === 'const') continue; - // By default, the identifier `undefined` has no binding (when it's actually undefined), - // but has a binding if it's used as a variable (e.g. `let undefined = "don't do this"`) - if (key.name === 'undefined' && !binding) continue; - } else if (is.literal(key)) { - 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. - throw new Error('todo - COMPUTED_PROPERTY_CANNOT_BE_TEMPLATE_LITERAL'); - } else if ('regex' in key) { - continue; - } +function validateWireConfig( + config: Expression, + path: NodePath +): asserts config is NoSpreadObjectExpression { + if (!is.objectExpression(config)) { + throw new Error('todo - CONFIG_OBJECT_SHOULD_BE_SECOND_PARAMETER'); + } + for (const property of config.properties) { + // Only validate computed object properties because static props are all valid + // and we ignore {...spreads} and {methods(){}} + if (!is.property(property) || !property.computed) continue; + const key = property.key; + if (is.identifier(key)) { + const binding = path.scope?.getBinding(key.name); + // TODO [#3956]: Investigate allowing imported constants + if (binding?.kind === 'const') continue; + // By default, the identifier `undefined` has no binding (when it's actually undefined), + // but has a binding if it's used as a variable (e.g. `let undefined = "don't do this"`) + if (key.name === 'undefined' && !binding) continue; + } else if (is.literal(key)) { + 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. + throw new Error('todo - 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; } } throw new Error('todo - COMPUTED_PROPERTY_MUST_BE_CONSTANT_OR_LITERAL'); } +} + +export function catalogWireAdapters( + path: NodePath, + state: ComponentMetaState +) { + const node = path.node!; + const [id, config] = getWireParams(node); + validateWireId(id, path); + let reactiveConfig: ObjectExpression; + if (config) { + validateWireConfig(config, path); + reactiveConfig = produce(config, (draft) => { + // replace '$foo' values with `instance.foo`; preserve everything else + for (const prop of draft.properties) { + const { value } = prop; + if ( + is.literal(value) && + typeof value.value === 'string' && + value.value.startsWith('$') + ) { + prop.value = bMemberExpressionChain(value.value.slice(1).split('.')); + } + } + }); + } else { + // FIXME: for `@wire(Adapter), does engine-server use `undefined` or `{}` for config? + reactiveConfig = b.objectExpression([]); // empty object + } state.wireAdapters = [ ...state.wireAdapters, - // extractWireConfig(name, adapterConstructorId.name, fieldtype, config), + { adapterId: id, config: reactiveConfig, field: node }, ]; } -function bWireConfigObj(adapter: WireAdapter) { - return b.objectExpression( - adapter.config.map(({ configKey, referencedField }) => - b.property( - 'init', - b.identifier(configKey), - b.memberExpression(b.identifier('instance'), b.identifier(referencedField)) - ) - ) - ); -} - const bSetWiredProp = esTemplate` instance.${/*wire-decorated property*/ is.identifier} = newValue `; @@ -148,41 +164,34 @@ const bCallWiredMethod = esTemplate` instance.${/*wire-decorated method*/ is.identifier}(newValue) `; -const bWireAdapterPlumbing = esTemplate` - const wireInstance = new ${/*wire adapter constructor*/ is.identifier}((newValue) => { +const bWireAdapterPlumbing = esTemplate`{ + const wireInstance = new ${/*wire adapter constructor*/ is.expression}((newValue) => { ${/*update the decorated property or call the decorated method*/ is.expressionStatement}; }); wireInstance.connect?.(); if (wireInstance.update) { - const wireConfigObj = ${/*mapping from lwc fields to wire config keys*/ is.objectExpression}; - + const getLiveConfig = () => { + return ${/* reactive wire config */ is.objectExpression}; + }; // This may look a bit weird, in that the 'update' function is called twice: once with // an 'undefined' value and possibly again with a context-provided value. While weird, // this preserves the behavior of the browser-side wire implementation as well as the // original SSR implementation. - wireInstance.update(wireConfigObj, undefined); + wireInstance.update(getLiveConfig(), undefined); __connectContext(${/*wire adapter constructor*/ 0}, instance, (newContextValue) => { - const wireConfigObj = ${/*mapping from lwc fields to wire config keys*/ 2}; - wireInstance.update(wireConfigObj, newContextValue); + wireInstance.update(getLiveConfig(), newContextValue); }); } -`; - -export function bWireAdaptersPlumbing(adapters: WireAdapter[]): Statement[] { - return adapters.map((adapter) => { - const { adapterConstructorId, fieldName } = adapter; +}`; +export function bWireAdaptersPlumbing(adapters: WireAdapter[]): BlockStatement[] { + return adapters.map(({ adapterId, config, field }) => { const actionUponNewValue = - adapter.fieldType === 'method' - ? bCallWiredMethod(b.identifier(fieldName)) - : bSetWiredProp(b.identifier(fieldName)); - - return b.blockStatement( - bWireAdapterPlumbing( - b.identifier(adapterConstructorId), - actionUponNewValue, - bWireConfigObj(adapter) - ) - ); + is.methodDefinition(field) && field.kind === 'method' + ? // Validation in compile-js/index.ts `visitors` ensures `key` is an identifier + bCallWiredMethod(field.key as Identifier) + : bSetWiredProp(field.key as Identifier); + + return bWireAdapterPlumbing(adapterId, actionUponNewValue, config); }); } diff --git a/packages/@lwc/ssr-compiler/src/estemplate.ts b/packages/@lwc/ssr-compiler/src/estemplate.ts index c4de0ec181..2d1f148b64 100644 --- a/packages/@lwc/ssr-compiler/src/estemplate.ts +++ b/packages/@lwc/ssr-compiler/src/estemplate.ts @@ -96,7 +96,7 @@ const getReplacementNode = ( validateReplacement.name || '(could not determine)'; const actualType = Array.isArray(replacementNode) - ? `[${replacementNode.map((n) => n.type)}.join(', ')]` + ? `[${replacementNode.map((n) => n.type).join(', ')}]` : replacementNode?.type; throw new Error( `Validation failed for templated node. Expected type ${expectedType}, but received ${actualType}.` From 8e2a8eb71e12d34567356e2a108b7aca75b55130 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Thu, 21 Nov 2024 12:35:27 -0500 Subject: [PATCH 09/11] chore(fixtures): standardize output order --- .../fixtures/wire/config/expected.html | 23 ++++++++----------- .../wire/config/modules/x/wire/adapter.js | 11 +++++++-- .../fixtures/wire/field/expected.html | 7 ++---- .../wire/field/modules/x/adapter/adapter.js | 11 +++++++-- .../fixtures/wire/method/expected.html | 7 ++---- .../wire/method/modules/x/adapter/adapter.js | 11 +++++++-- 6 files changed, 41 insertions(+), 29 deletions(-) diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/expected.html index a584db6ede..73debe9ade 100644 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/expected.html +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/expected.html @@ -1,23 +1,20 @@ \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/modules/x/wire/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/modules/x/wire/adapter.js index 405f2a3765..f96f1a3444 100644 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/modules/x/wire/adapter.js +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/config/modules/x/wire/adapter.js @@ -6,8 +6,15 @@ export class adapter { connect() {} update(config) { - // Quotes are encoded in the output, which is ugly - this.dc(JSON.stringify(config, null, 4).replace(/"/g, '')); + // JSON.stringify serializes differently for engine-server/ssr-compiler, so we do it manually + const output = Object.entries(config) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([key, value]) => ` ${key}: ${JSON.stringify(value)},`) + .join('\n') + // Quotes are encoded as " in the output, which makes it harder to read... + .replace(/"/g, ''); + + this.dc(`{\n${output}\n}`); } disconnect() {} diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/expected.html index 218386bc3c..d753c1fdb7 100644 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/expected.html +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/expected.html @@ -1,11 +1,8 @@ \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/modules/x/adapter/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/modules/x/adapter/adapter.js index 2a24199363..6243b8735b 100644 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/modules/x/adapter/adapter.js +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/field/modules/x/adapter/adapter.js @@ -6,8 +6,15 @@ export default class adapter { connect() {} update(config) { - // Quotes are encoded in the output, which is ugly - this.dc(JSON.stringify(config, null, 4).replace(/"/g, '')); + // JSON.stringify serializes differently for engine-server/ssr-compiler, so we do it manually + const output = Object.entries(config) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([key, value]) => ` ${key}: ${JSON.stringify(value)},`) + .join('\n') + // Quotes are encoded as " in the output, which makes it harder to read... + .replace(/"/g, ''); + + this.dc(`{\n${output}\n}`); } disconnect() {} diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/expected.html index 218386bc3c..d753c1fdb7 100644 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/expected.html +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/expected.html @@ -1,11 +1,8 @@ \ No newline at end of file diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/modules/x/adapter/adapter.js b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/modules/x/adapter/adapter.js index 2a24199363..6243b8735b 100644 --- a/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/modules/x/adapter/adapter.js +++ b/packages/@lwc/engine-server/src/__tests__/fixtures/wire/method/modules/x/adapter/adapter.js @@ -6,8 +6,15 @@ export default class adapter { connect() {} update(config) { - // Quotes are encoded in the output, which is ugly - this.dc(JSON.stringify(config, null, 4).replace(/"/g, '')); + // JSON.stringify serializes differently for engine-server/ssr-compiler, so we do it manually + const output = Object.entries(config) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([key, value]) => ` ${key}: ${JSON.stringify(value)},`) + .join('\n') + // Quotes are encoded as " in the output, which makes it harder to read... + .replace(/"/g, ''); + + this.dc(`{\n${output}\n}`); } disconnect() {} From 1fc68fb5923d5e8251271ba12d1717781a6907d6 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Thu, 21 Nov 2024 12:43:51 -0500 Subject: [PATCH 10/11] chore(ssr): unexpect failures --- .../ssr-compiler/src/__tests__/utils/expected-failures.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/@lwc/ssr-compiler/src/__tests__/utils/expected-failures.ts b/packages/@lwc/ssr-compiler/src/__tests__/utils/expected-failures.ts index 49fe978de3..daa540dc44 100644 --- a/packages/@lwc/ssr-compiler/src/__tests__/utils/expected-failures.ts +++ b/packages/@lwc/ssr-compiler/src/__tests__/utils/expected-failures.ts @@ -52,9 +52,4 @@ export const expectedFailures = new Set([ 'superclass/mixin/index.js', 'superclass/override/index.js', 'svgs/index.js', - 'wire/config/index.js', - 'wire/deep-reference/index.js', - 'wire/field/index.js', - 'wire/imported-member/index.js', - 'wire/method/index.js', ]); From 33067a893e821f17157414db2031812c098e09f6 Mon Sep 17 00:00:00 2001 From: Will Harney Date: Thu, 21 Nov 2024 12:52:53 -0500 Subject: [PATCH 11/11] chore: linter fixes --- packages/@lwc/ssr-compiler/src/compile-js/wire.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/@lwc/ssr-compiler/src/compile-js/wire.ts b/packages/@lwc/ssr-compiler/src/compile-js/wire.ts index 0755e2985e..1ed5b5fc12 100644 --- a/packages/@lwc/ssr-compiler/src/compile-js/wire.ts +++ b/packages/@lwc/ssr-compiler/src/compile-js/wire.ts @@ -5,9 +5,10 @@ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT */ -import { is, builders as b, NodePath } from 'estree-toolkit'; +import { is, builders as b } from 'estree-toolkit'; import { produce } from 'immer'; import { esTemplate } from '../estemplate'; +import type { NodePath } from 'estree-toolkit'; import type { PropertyDefinition,