From cda40622543e9b58e6e52e69a291e19e79001708 Mon Sep 17 00:00:00 2001 From: achab9 Date: Wed, 13 Nov 2024 17:16:12 -0500 Subject: [PATCH 01/23] checkConditionalStatement --- lib/util/ssr.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 122737c..0d79d5d 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -9,10 +9,32 @@ module.exports.isSSREscape = function isSSREscape(node) { return ( (node.type === 'IfStatement' || node.type === 'ConditionalExpression') && - (isMetaEnvCheck(node.test) || isWindowOrDocumentCheck(node.test)) + (checkConditionalStatements(node.test) || isWindowOrDocumentCheck(node.test)) ); }; +function checkConditionalStatements(test) { + let node = test; + + // Recursive Case: If the node is a logical expression, check its left and right parts. + if (node.type === 'LogicalExpression') { + checkIfStatements(node.left); + checkIfStatements(node.right); + } + + // Base Case: If the node is an Identifier or MemberExpression, don't need to continue. + if (node.type === 'Identifier' || node.type === 'MemberExpression') { + return false; + } + + // Base Case: If the node is UnaryExpression, call isMetaEnvCheck(). + if (node.type === 'UnaryExpression') { + return isMetaEnvCheck(node); + } + + return false; +} + function isMetaEnvCheck(test) { let node = test; if (!(node.type === 'UnaryExpression' && node.operator === '!')) return false; From 894a09d63b34511ab20ca8a8c7fc8cbb645b5cdb Mon Sep 17 00:00:00 2001 From: achab9 Date: Thu, 14 Nov 2024 15:50:45 -0500 Subject: [PATCH 02/23] test attempt 1 --- lib/analyze-component.js | 4 +- lib/rule-helpers.js | 2 + lib/util/ssr.js | 44 +- .../rules/no-unsupported-ssr-properties.js | 709 ++++++++++-------- 4 files changed, 431 insertions(+), 328 deletions(-) diff --git a/lib/analyze-component.js b/lib/analyze-component.js index e97dc3f..d6c1667 100644 --- a/lib/analyze-component.js +++ b/lib/analyze-component.js @@ -6,7 +6,7 @@ */ 'use strict'; const { walk } = require('./walk'); -const { isSSREscape } = require('./util/ssr'); +const { originalIsSSREscape } = require('./util/ssr'); const componentCache = new WeakMap(); @@ -109,7 +109,7 @@ function getMethodInterdependencies(classDecl) { const methodName = methodDefNode.key.name; walk(methodDefNode.value.body, (node, _parent, { skip }) => { - if (isSSREscape(node)) { + if (originalIsSSREscape(node)) { skip(); } if ( diff --git a/lib/rule-helpers.js b/lib/rule-helpers.js index a528cd4..1bcd212 100644 --- a/lib/rule-helpers.js +++ b/lib/rule-helpers.js @@ -89,6 +89,7 @@ function reachableDuringSSRPartial() { reachableMethodThatWeAreIn = null; }, IfStatement: (node) => { + console.log('calling escape1()'); if (isSSREscape(node)) { skippedBlockThatWeAreIn = node; } @@ -99,6 +100,7 @@ function reachableDuringSSRPartial() { } }, ConditionalExpression: (node) => { + console.log('calling escape2()'); if (isSSREscape(node)) { skippedConditionThatWeAreIn = node; } diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 0d79d5d..fbb09aa 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -7,23 +7,43 @@ 'use strict'; module.exports.isSSREscape = function isSSREscape(node) { + if (node.type === 'IfStatement' || node.type === 'ConditionalExpression') { + console.log(`ISSSRESCPAE NODETYPE: ${node.type}`); + + if (checkConditionalStatements(node.test) || isWindowOrDocumentCheck(node.test)) { + return true; + } + } + + return false; +}; + +module.exports.originalIsSSREscape = function originalIsSSREscape(node) { return ( (node.type === 'IfStatement' || node.type === 'ConditionalExpression') && - (checkConditionalStatements(node.test) || isWindowOrDocumentCheck(node.test)) + (isMetaEnvCheck(node.test) || isWindowOrDocumentCheck(node.test)) ); -}; +} function checkConditionalStatements(test) { let node = test; + console.log(`NODE TYPE: ${node.type}`); // Recursive Case: If the node is a logical expression, check its left and right parts. - if (node.type === 'LogicalExpression') { - checkIfStatements(node.left); - checkIfStatements(node.right); + // TODO: Do we want to be calling this for BinaryExpression? + if (node.type === 'LogicalExpression' || node.type === 'BinaryExpression') { + console.log('Calling Left'); + checkConditionalStatements(node.left); + + console.log('Calling Right'); + checkConditionalStatements(node.right); } // Base Case: If the node is an Identifier or MemberExpression, don't need to continue. - if (node.type === 'Identifier' || node.type === 'MemberExpression') { + // TODO: Do we want to be calling this for Literal? + if (node.type === 'Identifier' || node.type === 'MemberExpression' || node.type === 'Literal') { + if (node.type === 'Literal') console.log(node.value); + if (node.type === 'MemberExpression') console.log(node.property.name); return false; } @@ -35,11 +55,23 @@ function checkConditionalStatements(test) { return false; } +// Questions: +// 1. Why is this getting called SO many times +// 2. What is the nonSSR node.property.name +// 3. What is the BinaryExpression it's calling on +// 4. Why is it even calling checkConditionalStatement on BinaryExpression + // Shouldn't it only call if IfStatement or ConditionalExpression + + function isMetaEnvCheck(test) { let node = test; if (!(node.type === 'UnaryExpression' && node.operator === '!')) return false; node = node.argument; + + console.log(node.type); + console.log(`INSIDE ISMETAENVCHECK(): ${node.property.name}`); + if ( !( node.type === 'MemberExpression' && diff --git a/test/lib/rules/no-unsupported-ssr-properties.js b/test/lib/rules/no-unsupported-ssr-properties.js index 2abe9f7..81b6851 100644 --- a/test/lib/rules/no-unsupported-ssr-properties.js +++ b/test/lib/rules/no-unsupported-ssr-properties.js @@ -12,357 +12,426 @@ const { testRule } = require('../shared'); testRule('no-unsupported-ssr-properties', { valid: [ - { - code: ` - import { LightningElement } from 'lwc'; - import tmplA from './a.html'; + // { + // code: ` + // import { LightningElement } from 'lwc'; + // import tmplA from './a.html'; - export default class Foo extends LightningElement { - connectedCallback() { - // we can't use this.querySelector here - } - renderedCallback() { - this.querySelector('span')?.foo(); - } - bar() { - this.querySelector('span')?.foo(); - } - } - `, - }, - { - code: ` - import { LightningElement } from 'lwc'; - import tmplA from './a.html'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // // we can't use this.querySelector here + // } + // renderedCallback() { + // this.querySelector('span')?.foo(); + // } + // bar() { + // this.querySelector('span')?.foo(); + // } + // } + // `, + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + // import tmplA from './a.html'; - export default class Foo extends LightningElement { - connectedCallback() { - // we can't use this.querySelector here - } - renderedCallback() { - this.bar(); - } - bar() { - this.querySelector('span')?.foo(); - } - } - `, - }, - { - code: ` - import { LightningElement } from 'lwc'; - import tmplA from './a.html'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // // we can't use this.querySelector here + // } + // renderedCallback() { + // this.bar(); + // } + // bar() { + // this.querySelector('span')?.foo(); + // } + // } + // `, + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + // import tmplA from './a.html'; - export default class Foo extends LightningElement { - connectedCallback() { - // we can't use this.lastChild here - } - renderedCallback() { - this.bar(); - } - bar() { - doSomething(this.lastChild); - } - } - `, - }, - { - code: ` - import { LightningElement } from 'lwc'; - import tmplA from './a.html'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // // we can't use this.lastChild here + // } + // renderedCallback() { + // this.bar(); + // } + // bar() { + // doSomething(this.lastChild); + // } + // } + // `, + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + // import tmplA from './a.html'; - export default class Foo extends LightningElement { - connectedCallback() { - // we can't use this.ownerDocument here - } - bar() { - doSomething(this.ownerDocument); - } - } - `, - }, - { - code: ` - import { LightningElement } from 'lwc'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // // we can't use this.ownerDocument here + // } + // bar() { + // doSomething(this.ownerDocument); + // } + // } + // `, + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; - export default class Foo extends LightningElement { - connectedCallback() { - if(typeof document !== 'undefined') { - doSomething(this.lastElementChild); - } - } - } - `, - }, + // export default class Foo extends LightningElement { + // connectedCallback() { + // if(typeof document !== 'undefined') { + // doSomething(this.lastElementChild); + // } + // } + // } + // `, + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + + // export default class Foo extends LightningElement { + // connectedCallback() { + // if (!import.meta.env.SSR) { + // this.querySelector('span').getAttribute('role'); + // } + // } + // } + // `, + // }, { code: ` import { LightningElement } from 'lwc'; - + export default class Foo extends LightningElement { connectedCallback() { - if (!import.meta.env.SSR) { + if (!import.meta.env.SSR && !randomOtherCheck) { this.querySelector('span').getAttribute('role'); } } } `, }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + + // export default class Foo extends LightningElement { + // let randomOtherCheck = true; + + // connectedCallback() { + // if (!import.meta.env.SSR && randomOtherCheck) { + // this.querySelector('span').getAttribute('role'); + // } + // } + // } + // `, + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + + // export default class Foo extends LightningElement { + // let randomOtherCheck = true; + + // connectedCallback() { + // if (randomOtherCheck && !import.meta.env.SSR) { + // this.querySelector('span').getAttribute('role'); + // } + // } + // } + // `, + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + + // export default class Foo extends LightningElement { + // let [a, b, c, d] = [true, true, true, true]; + + // connectedCallback() { + // if (!a && b && !c && d && !import.meta.env.SSR) { + // this.querySelector('span').getAttribute('role'); + // } + // } + // } + // `, + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + + // export default class Foo extends LightningElement { + // connectedCallback() { + // return isCSR ? this.template.querySelector('button') : null; + // } + // } + // `, + // }, ], invalid: [ - { - code: ` - import { LightningElement } from 'lwc'; - import tmplA from './a.html'; + // { + // code: ` + // import { LightningElement } from 'lwc'; + // import tmplA from './a.html'; - export default class Foo extends LightningElement { - connectedCallback() { - this.querySelector('span')?.foo(); - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, - { - code: ` - import { LightningElement } from 'lwc'; - import tmplA from './a.html'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // this.querySelector('span')?.foo(); + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + // import tmplA from './a.html'; - export default class Foo extends LightningElement { - connectedCallback() { - this.foo(); - } - foo() { - this.querySelectorAll('span')?.foo(); - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, - { - code: ` - import { LightningElement } from 'lwc'; - import tmplA from './a.html'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // this.foo(); + // } + // foo() { + // this.querySelectorAll('span')?.foo(); + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + // import tmplA from './a.html'; - export default class Foo extends LightningElement { - connectedCallback() { - this.foo(); - } - foo() { - doSomethingWith(this.lastChild); - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, - { - code: ` - import { LightningElement } from 'lwc'; - import tmplA from './a.html'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // this.foo(); + // } + // foo() { + // doSomethingWith(this.lastChild); + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + // import tmplA from './a.html'; - export default class Foo extends LightningElement { - connectedCallback() { - doSomethingWith(this.dispatchEvent); - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, - { - code: ` - import { LightningElement } from 'lwc'; - import tmplA from './a.html'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // doSomethingWith(this.dispatchEvent); + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + // import tmplA from './a.html'; - export default class Foo extends LightningElement { - connectedCallback() { - this.foo(); - } - renderedCallback() { - this.foo(); - } - foo() { - doSomethingWith(this.getBoundingClientRect); - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, - { - code: ` - import { LightningElement } from 'lwc'; - import tmplA from './a.html'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // this.foo(); + // } + // renderedCallback() { + // this.foo(); + // } + // foo() { + // doSomethingWith(this.getBoundingClientRect); + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + // import tmplA from './a.html'; - export default class Foo extends LightningElement { - connectedCallback() { - this.foo(); - } - renderedCallback() { - this.foo(); - } - foo() { - doSomethingWith(this.querySelector); - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, - { - code: ` - import { LightningElement } from 'lwc'; - import tmplA from './a.html'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // this.foo(); + // } + // renderedCallback() { + // this.foo(); + // } + // foo() { + // doSomethingWith(this.querySelector); + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; + // import tmplA from './a.html'; - export default class Foo extends LightningElement { - connectedCallback() { - this.foo(); - } - renderedCallbac() { - this.foo(); - } - foo() { - doSomethingWith(this.querySelectorAll); - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, - { - code: ` - import { LightningElement } from 'lwc'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // this.foo(); + // } + // renderedCallbac() { + // this.foo(); + // } + // foo() { + // doSomethingWith(this.querySelectorAll); + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; - export default class Foo extends LightningElement { - connectedCallback() { - this.querySelector?.('span').foo(); - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, - { - code: ` - import { LightningElement } from 'lwc'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // this.querySelector?.('span').foo(); + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; - export default class Foo extends LightningElement { - connectedCallback() { - this.querySelector?.('span')?.getAttribute('role'); - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, - { - code: ` - import { LightningElement } from 'lwc'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // this.querySelector?.('span')?.getAttribute('role'); + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; - export default class Foo extends LightningElement { - connectedCallback() { - this.querySelector?.('span')?.firstElementChild?.id; - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, - { - code: ` - import { LightningElement } from 'lwc'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // this.querySelector?.('span')?.firstElementChild?.id; + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; - export default class Foo extends LightningElement { - connectedCallback() { - this.querySelector?.('span').getAttribute('role'); - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, - { - code: ` - import { LightningElement } from 'lwc'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // this.querySelector?.('span').getAttribute('role'); + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; - export default class Foo extends LightningElement { - connectedCallback() { - this.querySelector?.('span').getAttribute?.('role').startsWith('button'); - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, - { - code: ` - import { LightningElement } from 'lwc'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // this.querySelector?.('span').getAttribute?.('role').startsWith('button'); + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; - export default class Foo extends LightningElement { - connectedCallback() { - this.querySelector?.('span')?.children?.item?.(0); - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, - { - code: ` - import { LightningElement } from 'lwc'; + // export default class Foo extends LightningElement { + // connectedCallback() { + // this.querySelector?.('span')?.children?.item?.(0); + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; - export default class Foo extends LightningElement { - connectedCallback() { - this.childNodes.item(0).textContent = 'foo'; - } - } - `, - errors: [ - { - messageId: 'propertyAccessFound', - }, - ], - }, + // export default class Foo extends LightningElement { + // connectedCallback() { + // this.childNodes.item(0).textContent = 'foo'; + // } + // } + // `, + // errors: [ + // { + // messageId: 'propertyAccessFound', + // }, + // ], + // }, ], }); From ed5fd4bbd35c2be378a0466fc289db979f17e030 Mon Sep 17 00:00:00 2001 From: achab9 Date: Thu, 14 Nov 2024 16:00:11 -0500 Subject: [PATCH 03/23] formatter --- lib/util/ssr.js | 15 ++- .../rules/no-unsupported-ssr-properties.js | 112 ++++++++---------- 2 files changed, 56 insertions(+), 71 deletions(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index fbb09aa..407226a 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -23,24 +23,24 @@ module.exports.originalIsSSREscape = function originalIsSSREscape(node) { (node.type === 'IfStatement' || node.type === 'ConditionalExpression') && (isMetaEnvCheck(node.test) || isWindowOrDocumentCheck(node.test)) ); -} +}; function checkConditionalStatements(test) { let node = test; console.log(`NODE TYPE: ${node.type}`); - + // Recursive Case: If the node is a logical expression, check its left and right parts. // TODO: Do we want to be calling this for BinaryExpression? if (node.type === 'LogicalExpression' || node.type === 'BinaryExpression') { console.log('Calling Left'); checkConditionalStatements(node.left); - + console.log('Calling Right'); checkConditionalStatements(node.right); } // Base Case: If the node is an Identifier or MemberExpression, don't need to continue. - // TODO: Do we want to be calling this for Literal? + // TODO: Do we want to be calling this for Literal? if (node.type === 'Identifier' || node.type === 'MemberExpression' || node.type === 'Literal') { if (node.type === 'Literal') console.log(node.value); if (node.type === 'MemberExpression') console.log(node.property.name); @@ -55,13 +55,12 @@ function checkConditionalStatements(test) { return false; } -// Questions: -// 1. Why is this getting called SO many times +// Questions: +// 1. Why is this getting called SO many times // 2. What is the nonSSR node.property.name // 3. What is the BinaryExpression it's calling on // 4. Why is it even calling checkConditionalStatement on BinaryExpression - // Shouldn't it only call if IfStatement or ConditionalExpression - +// Shouldn't it only call if IfStatement or ConditionalExpression function isMetaEnvCheck(test) { let node = test; diff --git a/test/lib/rules/no-unsupported-ssr-properties.js b/test/lib/rules/no-unsupported-ssr-properties.js index 81b6851..d7fda45 100644 --- a/test/lib/rules/no-unsupported-ssr-properties.js +++ b/test/lib/rules/no-unsupported-ssr-properties.js @@ -120,69 +120,68 @@ testRule('no-unsupported-ssr-properties', { } `, }, - // { - // code: ` - // import { LightningElement } from 'lwc'; + // { + // code: ` + // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // let randomOtherCheck = true; + // export default class Foo extends LightningElement { + // let randomOtherCheck = true; - // connectedCallback() { - // if (!import.meta.env.SSR && randomOtherCheck) { - // this.querySelector('span').getAttribute('role'); - // } - // } - // } - // `, - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; + // connectedCallback() { + // if (!import.meta.env.SSR && randomOtherCheck) { + // this.querySelector('span').getAttribute('role'); + // } + // } + // } + // `, + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // let randomOtherCheck = true; + // export default class Foo extends LightningElement { + // let randomOtherCheck = true; - // connectedCallback() { - // if (randomOtherCheck && !import.meta.env.SSR) { - // this.querySelector('span').getAttribute('role'); - // } - // } - // } - // `, - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; + // connectedCallback() { + // if (randomOtherCheck && !import.meta.env.SSR) { + // this.querySelector('span').getAttribute('role'); + // } + // } + // } + // `, + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // let [a, b, c, d] = [true, true, true, true]; + // export default class Foo extends LightningElement { + // let [a, b, c, d] = [true, true, true, true]; - // connectedCallback() { - // if (!a && b && !c && d && !import.meta.env.SSR) { - // this.querySelector('span').getAttribute('role'); - // } - // } - // } - // `, - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; + // connectedCallback() { + // if (!a && b && !c && d && !import.meta.env.SSR) { + // this.querySelector('span').getAttribute('role'); + // } + // } + // } + // `, + // }, + // { + // code: ` + // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // return isCSR ? this.template.querySelector('button') : null; - // } - // } - // `, - // }, + // export default class Foo extends LightningElement { + // connectedCallback() { + // return isCSR ? this.template.querySelector('button') : null; + // } + // } + // `, + // }, ], invalid: [ // { // code: ` // import { LightningElement } from 'lwc'; // import tmplA from './a.html'; - // export default class Foo extends LightningElement { // connectedCallback() { // this.querySelector('span')?.foo(); @@ -199,7 +198,6 @@ testRule('no-unsupported-ssr-properties', { // code: ` // import { LightningElement } from 'lwc'; // import tmplA from './a.html'; - // export default class Foo extends LightningElement { // connectedCallback() { // this.foo(); @@ -219,7 +217,6 @@ testRule('no-unsupported-ssr-properties', { // code: ` // import { LightningElement } from 'lwc'; // import tmplA from './a.html'; - // export default class Foo extends LightningElement { // connectedCallback() { // this.foo(); @@ -239,7 +236,6 @@ testRule('no-unsupported-ssr-properties', { // code: ` // import { LightningElement } from 'lwc'; // import tmplA from './a.html'; - // export default class Foo extends LightningElement { // connectedCallback() { // doSomethingWith(this.dispatchEvent); @@ -256,7 +252,6 @@ testRule('no-unsupported-ssr-properties', { // code: ` // import { LightningElement } from 'lwc'; // import tmplA from './a.html'; - // export default class Foo extends LightningElement { // connectedCallback() { // this.foo(); @@ -279,7 +274,6 @@ testRule('no-unsupported-ssr-properties', { // code: ` // import { LightningElement } from 'lwc'; // import tmplA from './a.html'; - // export default class Foo extends LightningElement { // connectedCallback() { // this.foo(); @@ -302,7 +296,6 @@ testRule('no-unsupported-ssr-properties', { // code: ` // import { LightningElement } from 'lwc'; // import tmplA from './a.html'; - // export default class Foo extends LightningElement { // connectedCallback() { // this.foo(); @@ -324,7 +317,6 @@ testRule('no-unsupported-ssr-properties', { // { // code: ` // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { // connectedCallback() { // this.querySelector?.('span').foo(); @@ -340,7 +332,6 @@ testRule('no-unsupported-ssr-properties', { // { // code: ` // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { // connectedCallback() { // this.querySelector?.('span')?.getAttribute('role'); @@ -356,7 +347,6 @@ testRule('no-unsupported-ssr-properties', { // { // code: ` // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { // connectedCallback() { // this.querySelector?.('span')?.firstElementChild?.id; @@ -372,7 +362,6 @@ testRule('no-unsupported-ssr-properties', { // { // code: ` // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { // connectedCallback() { // this.querySelector?.('span').getAttribute('role'); @@ -388,7 +377,6 @@ testRule('no-unsupported-ssr-properties', { // { // code: ` // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { // connectedCallback() { // this.querySelector?.('span').getAttribute?.('role').startsWith('button'); @@ -404,7 +392,6 @@ testRule('no-unsupported-ssr-properties', { // { // code: ` // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { // connectedCallback() { // this.querySelector?.('span')?.children?.item?.(0); @@ -420,7 +407,6 @@ testRule('no-unsupported-ssr-properties', { // { // code: ` // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { // connectedCallback() { // this.childNodes.item(0).textContent = 'foo'; From d8e13b6a4241bd99b1b277dd66bd2775ebd2aba5 Mon Sep 17 00:00:00 2001 From: achab9 Date: Mon, 18 Nov 2024 11:50:52 -0500 Subject: [PATCH 04/23] fixed returns --- lib/rule-helpers.js | 2 - lib/util/ssr.js | 37 +- .../rules/no-unsupported-ssr-properties.js | 764 +++++++++--------- 3 files changed, 391 insertions(+), 412 deletions(-) diff --git a/lib/rule-helpers.js b/lib/rule-helpers.js index 1bcd212..a528cd4 100644 --- a/lib/rule-helpers.js +++ b/lib/rule-helpers.js @@ -89,7 +89,6 @@ function reachableDuringSSRPartial() { reachableMethodThatWeAreIn = null; }, IfStatement: (node) => { - console.log('calling escape1()'); if (isSSREscape(node)) { skippedBlockThatWeAreIn = node; } @@ -100,7 +99,6 @@ function reachableDuringSSRPartial() { } }, ConditionalExpression: (node) => { - console.log('calling escape2()'); if (isSSREscape(node)) { skippedConditionThatWeAreIn = node; } diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 407226a..72dfc23 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -6,10 +6,10 @@ */ 'use strict'; +let ssrEscapeFound = false; + module.exports.isSSREscape = function isSSREscape(node) { if (node.type === 'IfStatement' || node.type === 'ConditionalExpression') { - console.log(`ISSSRESCPAE NODETYPE: ${node.type}`); - if (checkConditionalStatements(node.test) || isWindowOrDocumentCheck(node.test)) { return true; } @@ -27,50 +27,36 @@ module.exports.originalIsSSREscape = function originalIsSSREscape(node) { function checkConditionalStatements(test) { let node = test; - console.log(`NODE TYPE: ${node.type}`); // Recursive Case: If the node is a logical expression, check its left and right parts. - // TODO: Do we want to be calling this for BinaryExpression? - if (node.type === 'LogicalExpression' || node.type === 'BinaryExpression') { - console.log('Calling Left'); - checkConditionalStatements(node.left); - - console.log('Calling Right'); + if (node.type === 'LogicalExpression' || node.type === 'BinaryExpression') { + checkConditionalStatements(node.left) checkConditionalStatements(node.right); } // Base Case: If the node is an Identifier or MemberExpression, don't need to continue. - // TODO: Do we want to be calling this for Literal? if (node.type === 'Identifier' || node.type === 'MemberExpression' || node.type === 'Literal') { - if (node.type === 'Literal') console.log(node.value); - if (node.type === 'MemberExpression') console.log(node.property.name); - return false; + return ssrEscapeFound; } // Base Case: If the node is UnaryExpression, call isMetaEnvCheck(). if (node.type === 'UnaryExpression') { - return isMetaEnvCheck(node); + if (isMetaEnvCheck(node)) { + ssrEscapeFound = true; + } + + return ssrEscapeFound; } - return false; + return ssrEscapeFound; } -// Questions: -// 1. Why is this getting called SO many times -// 2. What is the nonSSR node.property.name -// 3. What is the BinaryExpression it's calling on -// 4. Why is it even calling checkConditionalStatement on BinaryExpression -// Shouldn't it only call if IfStatement or ConditionalExpression - function isMetaEnvCheck(test) { let node = test; if (!(node.type === 'UnaryExpression' && node.operator === '!')) return false; node = node.argument; - console.log(node.type); - console.log(`INSIDE ISMETAENVCHECK(): ${node.property.name}`); - if ( !( node.type === 'MemberExpression' && @@ -101,6 +87,7 @@ function isMetaEnvCheck(test) { return false; node = node.meta; + return node.type && node.name === 'import'; } diff --git a/test/lib/rules/no-unsupported-ssr-properties.js b/test/lib/rules/no-unsupported-ssr-properties.js index d7fda45..4c712aa 100644 --- a/test/lib/rules/no-unsupported-ssr-properties.js +++ b/test/lib/rules/no-unsupported-ssr-properties.js @@ -12,101 +12,101 @@ const { testRule } = require('../shared'); testRule('no-unsupported-ssr-properties', { valid: [ - // { - // code: ` - // import { LightningElement } from 'lwc'; - // import tmplA from './a.html'; + { + code: ` + import { LightningElement } from 'lwc'; + import tmplA from './a.html'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // // we can't use this.querySelector here - // } - // renderedCallback() { - // this.querySelector('span')?.foo(); - // } - // bar() { - // this.querySelector('span')?.foo(); - // } - // } - // `, - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // import tmplA from './a.html'; + export default class Foo extends LightningElement { + connectedCallback() { + // we can't use this.querySelector here + } + renderedCallback() { + this.querySelector('span')?.foo(); + } + bar() { + this.querySelector('span')?.foo(); + } + } + `, + }, + { + code: ` + import { LightningElement } from 'lwc'; + import tmplA from './a.html'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // // we can't use this.querySelector here - // } - // renderedCallback() { - // this.bar(); - // } - // bar() { - // this.querySelector('span')?.foo(); - // } - // } - // `, - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // import tmplA from './a.html'; + export default class Foo extends LightningElement { + connectedCallback() { + // we can't use this.querySelector here + } + renderedCallback() { + this.bar(); + } + bar() { + this.querySelector('span')?.foo(); + } + } + `, + }, + { + code: ` + import { LightningElement } from 'lwc'; + import tmplA from './a.html'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // // we can't use this.lastChild here - // } - // renderedCallback() { - // this.bar(); - // } - // bar() { - // doSomething(this.lastChild); - // } - // } - // `, - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // import tmplA from './a.html'; + export default class Foo extends LightningElement { + connectedCallback() { + // we can't use this.lastChild here + } + renderedCallback() { + this.bar(); + } + bar() { + doSomething(this.lastChild); + } + } + `, + }, + { + code: ` + import { LightningElement } from 'lwc'; + import tmplA from './a.html'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // // we can't use this.ownerDocument here - // } - // bar() { - // doSomething(this.ownerDocument); - // } - // } - // `, - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { + connectedCallback() { + // we can't use this.ownerDocument here + } + bar() { + doSomething(this.ownerDocument); + } + } + `, + }, + { + code: ` + import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // if(typeof document !== 'undefined') { - // doSomething(this.lastElementChild); - // } - // } - // } - // `, - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { + connectedCallback() { + if(typeof document !== 'undefined') { + doSomething(this.lastElementChild); + } + } + } + `, + }, + { + code: ` + import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // if (!import.meta.env.SSR) { - // this.querySelector('span').getAttribute('role'); - // } - // } - // } - // `, - // }, + export default class Foo extends LightningElement { + connectedCallback() { + if (!import.meta.env.SSR) { + this.querySelector('span').getAttribute('role'); + } + } + } + `, + }, { code: ` import { LightningElement } from 'lwc'; @@ -120,304 +120,298 @@ testRule('no-unsupported-ssr-properties', { } `, }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - - // export default class Foo extends LightningElement { - // let randomOtherCheck = true; - - // connectedCallback() { - // if (!import.meta.env.SSR && randomOtherCheck) { - // this.querySelector('span').getAttribute('role'); - // } - // } - // } - // `, - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - - // export default class Foo extends LightningElement { - // let randomOtherCheck = true; - - // connectedCallback() { - // if (randomOtherCheck && !import.meta.env.SSR) { - // this.querySelector('span').getAttribute('role'); - // } - // } - // } - // `, - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - - // export default class Foo extends LightningElement { - // let [a, b, c, d] = [true, true, true, true]; - - // connectedCallback() { - // if (!a && b && !c && d && !import.meta.env.SSR) { - // this.querySelector('span').getAttribute('role'); - // } - // } - // } - // `, - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; + { + code: ` + import { LightningElement } from 'lwc'; + + export default class Foo extends LightningElement { + connectedCallback() { + if (!import.meta.env.SSR && randomOtherCheck) { + this.querySelector('span').getAttribute('role'); + } + } + } + `, + }, + { + code: ` + import { LightningElement } from 'lwc'; + + export default class Foo extends LightningElement { + connectedCallback() { + if (randomOtherCheck && !import.meta.env.SSR) { + this.querySelector('span').getAttribute('role'); + } + } + } + `, + }, + { + code: ` + import { LightningElement } from 'lwc'; + + export default class Foo extends LightningElement { + connectedCallback() { + if (!a && b && !c && d && !import.meta.env.SSR) { + this.querySelector('span').getAttribute('role'); + } + } + } + `, + }, + { + code: ` + import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // return isCSR ? this.template.querySelector('button') : null; - // } - // } - // `, - // }, + export default class Foo extends LightningElement { + connectedCallback() { + return isCSR ? this.template.querySelector('button') : null; + } + } + `, + }, ], invalid: [ - // { - // code: ` - // import { LightningElement } from 'lwc'; - // import tmplA from './a.html'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // this.querySelector('span')?.foo(); - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // import tmplA from './a.html'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // this.foo(); - // } - // foo() { - // this.querySelectorAll('span')?.foo(); - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // import tmplA from './a.html'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // this.foo(); - // } - // foo() { - // doSomethingWith(this.lastChild); - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // import tmplA from './a.html'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // doSomethingWith(this.dispatchEvent); - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // import tmplA from './a.html'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // this.foo(); - // } - // renderedCallback() { - // this.foo(); - // } - // foo() { - // doSomethingWith(this.getBoundingClientRect); - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // import tmplA from './a.html'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // this.foo(); - // } - // renderedCallback() { - // this.foo(); - // } - // foo() { - // doSomethingWith(this.querySelector); - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // import tmplA from './a.html'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // this.foo(); - // } - // renderedCallbac() { - // this.foo(); - // } - // foo() { - // doSomethingWith(this.querySelectorAll); - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // this.querySelector?.('span').foo(); - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // this.querySelector?.('span')?.getAttribute('role'); - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // this.querySelector?.('span')?.firstElementChild?.id; - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // this.querySelector?.('span').getAttribute('role'); - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // this.querySelector?.('span').getAttribute?.('role').startsWith('button'); - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // this.querySelector?.('span')?.children?.item?.(0); - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, - // { - // code: ` - // import { LightningElement } from 'lwc'; - // export default class Foo extends LightningElement { - // connectedCallback() { - // this.childNodes.item(0).textContent = 'foo'; - // } - // } - // `, - // errors: [ - // { - // messageId: 'propertyAccessFound', - // }, - // ], - // }, + { + code: ` + import { LightningElement } from 'lwc'; + import tmplA from './a.html'; + export default class Foo extends LightningElement { + connectedCallback() { + this.querySelector('span')?.foo(); + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, + { + code: ` + import { LightningElement } from 'lwc'; + import tmplA from './a.html'; + export default class Foo extends LightningElement { + connectedCallback() { + this.foo(); + } + foo() { + this.querySelectorAll('span')?.foo(); + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, + { + code: ` + import { LightningElement } from 'lwc'; + import tmplA from './a.html'; + export default class Foo extends LightningElement { + connectedCallback() { + this.foo(); + } + foo() { + doSomethingWith(this.lastChild); + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, + { + code: ` + import { LightningElement } from 'lwc'; + import tmplA from './a.html'; + export default class Foo extends LightningElement { + connectedCallback() { + doSomethingWith(this.dispatchEvent); + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, + { + code: ` + import { LightningElement } from 'lwc'; + import tmplA from './a.html'; + export default class Foo extends LightningElement { + connectedCallback() { + this.foo(); + } + renderedCallback() { + this.foo(); + } + foo() { + doSomethingWith(this.getBoundingClientRect); + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, + { + code: ` + import { LightningElement } from 'lwc'; + import tmplA from './a.html'; + export default class Foo extends LightningElement { + connectedCallback() { + this.foo(); + } + renderedCallback() { + this.foo(); + } + foo() { + doSomethingWith(this.querySelector); + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, + { + code: ` + import { LightningElement } from 'lwc'; + import tmplA from './a.html'; + export default class Foo extends LightningElement { + connectedCallback() { + this.foo(); + } + renderedCallbac() { + this.foo(); + } + foo() { + doSomethingWith(this.querySelectorAll); + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, + { + code: ` + import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { + connectedCallback() { + this.querySelector?.('span').foo(); + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, + { + code: ` + import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { + connectedCallback() { + this.querySelector?.('span')?.getAttribute('role'); + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, + { + code: ` + import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { + connectedCallback() { + this.querySelector?.('span')?.firstElementChild?.id; + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, + { + code: ` + import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { + connectedCallback() { + this.querySelector?.('span').getAttribute('role'); + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, + { + code: ` + import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { + connectedCallback() { + this.querySelector?.('span').getAttribute?.('role').startsWith('button'); + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, + { + code: ` + import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { + connectedCallback() { + this.querySelector?.('span')?.children?.item?.(0); + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, + { + code: ` + import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { + connectedCallback() { + this.childNodes.item(0).textContent = 'foo'; + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], + }, ], }); From a4601843eee8b32dc6993d934ddba4f795ad2656 Mon Sep 17 00:00:00 2001 From: achab9 Date: Mon, 18 Nov 2024 11:53:40 -0500 Subject: [PATCH 05/23] format --- lib/util/ssr.js | 8 +++----- test/lib/rules/no-unsupported-ssr-properties.js | 8 ++++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 72dfc23..80ffbc5 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -29,8 +29,8 @@ function checkConditionalStatements(test) { let node = test; // Recursive Case: If the node is a logical expression, check its left and right parts. - if (node.type === 'LogicalExpression' || node.type === 'BinaryExpression') { - checkConditionalStatements(node.left) + if (node.type === 'LogicalExpression' || node.type === 'BinaryExpression') { + checkConditionalStatements(node.left); checkConditionalStatements(node.right); } @@ -44,7 +44,7 @@ function checkConditionalStatements(test) { if (isMetaEnvCheck(node)) { ssrEscapeFound = true; } - + return ssrEscapeFound; } @@ -56,7 +56,6 @@ function isMetaEnvCheck(test) { if (!(node.type === 'UnaryExpression' && node.operator === '!')) return false; node = node.argument; - if ( !( node.type === 'MemberExpression' && @@ -87,7 +86,6 @@ function isMetaEnvCheck(test) { return false; node = node.meta; - return node.type && node.name === 'import'; } diff --git a/test/lib/rules/no-unsupported-ssr-properties.js b/test/lib/rules/no-unsupported-ssr-properties.js index 4c712aa..ffe693c 100644 --- a/test/lib/rules/no-unsupported-ssr-properties.js +++ b/test/lib/rules/no-unsupported-ssr-properties.js @@ -121,7 +121,7 @@ testRule('no-unsupported-ssr-properties', { `, }, { - code: ` + code: ` import { LightningElement } from 'lwc'; export default class Foo extends LightningElement { @@ -134,7 +134,7 @@ testRule('no-unsupported-ssr-properties', { `, }, { - code: ` + code: ` import { LightningElement } from 'lwc'; export default class Foo extends LightningElement { @@ -147,7 +147,7 @@ testRule('no-unsupported-ssr-properties', { `, }, { - code: ` + code: ` import { LightningElement } from 'lwc'; export default class Foo extends LightningElement { @@ -160,7 +160,7 @@ testRule('no-unsupported-ssr-properties', { `, }, { - code: ` + code: ` import { LightningElement } from 'lwc'; export default class Foo extends LightningElement { From 8405da20d36cf19a15b0b3b4105cf7359d2714f4 Mon Sep 17 00:00:00 2001 From: achab9 Date: Mon, 18 Nov 2024 12:41:08 -0500 Subject: [PATCH 06/23] variable reset --- lib/util/ssr.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 80ffbc5..111c325 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -10,6 +10,7 @@ let ssrEscapeFound = false; module.exports.isSSREscape = function isSSREscape(node) { if (node.type === 'IfStatement' || node.type === 'ConditionalExpression') { + ssrEscapeFound = false; if (checkConditionalStatements(node.test) || isWindowOrDocumentCheck(node.test)) { return true; } From 5bb6865f983a1c68cf7561178244b10230637671 Mon Sep 17 00:00:00 2001 From: achab9 Date: Mon, 18 Nov 2024 12:42:24 -0500 Subject: [PATCH 07/23] get rid of original --- lib/analyze-component.js | 4 ++-- lib/util/ssr.js | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/analyze-component.js b/lib/analyze-component.js index d6c1667..e97dc3f 100644 --- a/lib/analyze-component.js +++ b/lib/analyze-component.js @@ -6,7 +6,7 @@ */ 'use strict'; const { walk } = require('./walk'); -const { originalIsSSREscape } = require('./util/ssr'); +const { isSSREscape } = require('./util/ssr'); const componentCache = new WeakMap(); @@ -109,7 +109,7 @@ function getMethodInterdependencies(classDecl) { const methodName = methodDefNode.key.name; walk(methodDefNode.value.body, (node, _parent, { skip }) => { - if (originalIsSSREscape(node)) { + if (isSSREscape(node)) { skip(); } if ( diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 111c325..78bb5e6 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -19,13 +19,6 @@ module.exports.isSSREscape = function isSSREscape(node) { return false; }; -module.exports.originalIsSSREscape = function originalIsSSREscape(node) { - return ( - (node.type === 'IfStatement' || node.type === 'ConditionalExpression') && - (isMetaEnvCheck(node.test) || isWindowOrDocumentCheck(node.test)) - ); -}; - function checkConditionalStatements(test) { let node = test; From 9458166abb74b73f994cb3a771edf5bcabc1f15e Mon Sep 17 00:00:00 2001 From: achab9 Date: Tue, 19 Nov 2024 10:34:21 -0500 Subject: [PATCH 08/23] operator and invalid test --- lib/util/ssr.js | 2 +- .../lib/rules/no-unsupported-ssr-properties.js | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 78bb5e6..cb8dbef 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -35,7 +35,7 @@ function checkConditionalStatements(test) { // Base Case: If the node is UnaryExpression, call isMetaEnvCheck(). if (node.type === 'UnaryExpression') { - if (isMetaEnvCheck(node)) { + if (node.operator === '!' && isMetaEnvCheck(node)) { ssrEscapeFound = true; } diff --git a/test/lib/rules/no-unsupported-ssr-properties.js b/test/lib/rules/no-unsupported-ssr-properties.js index ffe693c..44d8529 100644 --- a/test/lib/rules/no-unsupported-ssr-properties.js +++ b/test/lib/rules/no-unsupported-ssr-properties.js @@ -413,5 +413,23 @@ testRule('no-unsupported-ssr-properties', { }, ], }, + { + code: ` + import { LightningElement } from 'lwc'; + + export default class Foo extends LightningElement { + connectedCallback() { + if (!a && b && !c && d) { + this.querySelector('span').getAttribute('role'); + } + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + } + ] + }, ], }); From 61da9ee8a7ddeb6220c3ef12419f8d42949d9aef Mon Sep 17 00:00:00 2001 From: achab9 Date: Thu, 21 Nov 2024 16:23:29 -0500 Subject: [PATCH 09/23] remove ssrEscapeFound --- lib/util/ssr.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index cb8dbef..12316e4 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -6,11 +6,8 @@ */ 'use strict'; -let ssrEscapeFound = false; - module.exports.isSSREscape = function isSSREscape(node) { if (node.type === 'IfStatement' || node.type === 'ConditionalExpression') { - ssrEscapeFound = false; if (checkConditionalStatements(node.test) || isWindowOrDocumentCheck(node.test)) { return true; } @@ -24,25 +21,26 @@ function checkConditionalStatements(test) { // Recursive Case: If the node is a logical expression, check its left and right parts. if (node.type === 'LogicalExpression' || node.type === 'BinaryExpression') { - checkConditionalStatements(node.left); - checkConditionalStatements(node.right); + const rightNodeConditional = checkConditionalStatements(node.right); + + if (!rightNodeConditional) { + return checkConditionalStatements(node.left); + } else if (rightNodeConditional) { + return true; + } } // Base Case: If the node is an Identifier or MemberExpression, don't need to continue. if (node.type === 'Identifier' || node.type === 'MemberExpression' || node.type === 'Literal') { - return ssrEscapeFound; + return false; } // Base Case: If the node is UnaryExpression, call isMetaEnvCheck(). - if (node.type === 'UnaryExpression') { - if (node.operator === '!' && isMetaEnvCheck(node)) { - ssrEscapeFound = true; - } - - return ssrEscapeFound; + if (node.type === 'UnaryExpression' && node.operator === '!') { + return isMetaEnvCheck(node); } - return ssrEscapeFound; + return false; } function isMetaEnvCheck(test) { From a6051feee042fa866c3a32040a79eb9dd2f23dfe Mon Sep 17 00:00:00 2001 From: achab9 Date: Thu, 21 Nov 2024 16:51:40 -0500 Subject: [PATCH 10/23] ignore or symbol --- lib/util/ssr.js | 4 ++ .../rules/no-unsupported-ssr-properties.js | 67 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 12316e4..3de1258 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -21,6 +21,10 @@ function checkConditionalStatements(test) { // Recursive Case: If the node is a logical expression, check its left and right parts. if (node.type === 'LogicalExpression' || node.type === 'BinaryExpression') { + if (node.operator === '||') { + return false; + } + const rightNodeConditional = checkConditionalStatements(node.right); if (!rightNodeConditional) { diff --git a/test/lib/rules/no-unsupported-ssr-properties.js b/test/lib/rules/no-unsupported-ssr-properties.js index 44d8529..b67d44e 100644 --- a/test/lib/rules/no-unsupported-ssr-properties.js +++ b/test/lib/rules/no-unsupported-ssr-properties.js @@ -159,6 +159,19 @@ testRule('no-unsupported-ssr-properties', { } `, }, + { + code: ` + import { LightningElement } from 'lwc'; + + export default class Foo extends LightningElement { + connectedCallback() { + if (a && (b && !import.meta.env.SSR)) { + this.querySelector('span').getAttribute('role'); + } + } + } + `, + }, { code: ` import { LightningElement } from 'lwc'; @@ -431,5 +444,59 @@ testRule('no-unsupported-ssr-properties', { } ] }, + { + code: ` + import { LightningElement } from 'lwc'; + + export default class Foo extends LightningElement { + connectedCallback() { + if (a && (b || !import.meta.env.SSR)) { + this.querySelector('span').getAttribute('role'); + } + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + } + ] + }, + { + code: ` + import { LightningElement } from 'lwc'; + + export default class Foo extends LightningElement { + connectedCallback() { + if (a || (b || !import.meta.env.SSR)) { + this.querySelector('span').getAttribute('role'); + } + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + } + ] + }, + { + code: ` + import { LightningElement } from 'lwc'; + + export default class Foo extends LightningElement { + connectedCallback() { + if (a || (b && !import.meta.env.SSR)) { + this.querySelector('span').getAttribute('role'); + } + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + } + ] + }, ], }); From 5bcd21c57c9154299b10f0c6e3b619ec7cb67a84 Mon Sep 17 00:00:00 2001 From: achab9 Date: Fri, 22 Nov 2024 11:07:20 -0500 Subject: [PATCH 11/23] spaces --- test/lib/rules/no-unsupported-ssr-properties.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/lib/rules/no-unsupported-ssr-properties.js b/test/lib/rules/no-unsupported-ssr-properties.js index b67d44e..5f0741d 100644 --- a/test/lib/rules/no-unsupported-ssr-properties.js +++ b/test/lib/rules/no-unsupported-ssr-properties.js @@ -324,6 +324,7 @@ testRule('no-unsupported-ssr-properties', { { code: ` import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { connectedCallback() { this.querySelector?.('span').foo(); @@ -339,6 +340,7 @@ testRule('no-unsupported-ssr-properties', { { code: ` import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { connectedCallback() { this.querySelector?.('span')?.getAttribute('role'); @@ -354,6 +356,7 @@ testRule('no-unsupported-ssr-properties', { { code: ` import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { connectedCallback() { this.querySelector?.('span')?.firstElementChild?.id; @@ -369,6 +372,7 @@ testRule('no-unsupported-ssr-properties', { { code: ` import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { connectedCallback() { this.querySelector?.('span').getAttribute('role'); @@ -384,6 +388,7 @@ testRule('no-unsupported-ssr-properties', { { code: ` import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { connectedCallback() { this.querySelector?.('span').getAttribute?.('role').startsWith('button'); @@ -399,6 +404,7 @@ testRule('no-unsupported-ssr-properties', { { code: ` import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { connectedCallback() { this.querySelector?.('span')?.children?.item?.(0); @@ -414,6 +420,7 @@ testRule('no-unsupported-ssr-properties', { { code: ` import { LightningElement } from 'lwc'; + export default class Foo extends LightningElement { connectedCallback() { this.childNodes.item(0).textContent = 'foo'; From 51fbf1cf7f8ddcb7876f2da6ddada0fe091a99a4 Mon Sep 17 00:00:00 2001 From: achab9 Date: Fri, 22 Nov 2024 11:08:24 -0500 Subject: [PATCH 12/23] spaces --- test/lib/rules/no-unsupported-ssr-properties.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/lib/rules/no-unsupported-ssr-properties.js b/test/lib/rules/no-unsupported-ssr-properties.js index 5f0741d..c888ace 100644 --- a/test/lib/rules/no-unsupported-ssr-properties.js +++ b/test/lib/rules/no-unsupported-ssr-properties.js @@ -189,6 +189,7 @@ testRule('no-unsupported-ssr-properties', { code: ` import { LightningElement } from 'lwc'; import tmplA from './a.html'; + export default class Foo extends LightningElement { connectedCallback() { this.querySelector('span')?.foo(); @@ -205,6 +206,7 @@ testRule('no-unsupported-ssr-properties', { code: ` import { LightningElement } from 'lwc'; import tmplA from './a.html'; + export default class Foo extends LightningElement { connectedCallback() { this.foo(); @@ -224,6 +226,7 @@ testRule('no-unsupported-ssr-properties', { code: ` import { LightningElement } from 'lwc'; import tmplA from './a.html'; + export default class Foo extends LightningElement { connectedCallback() { this.foo(); @@ -243,6 +246,7 @@ testRule('no-unsupported-ssr-properties', { code: ` import { LightningElement } from 'lwc'; import tmplA from './a.html'; + export default class Foo extends LightningElement { connectedCallback() { doSomethingWith(this.dispatchEvent); @@ -259,6 +263,7 @@ testRule('no-unsupported-ssr-properties', { code: ` import { LightningElement } from 'lwc'; import tmplA from './a.html'; + export default class Foo extends LightningElement { connectedCallback() { this.foo(); @@ -281,6 +286,7 @@ testRule('no-unsupported-ssr-properties', { code: ` import { LightningElement } from 'lwc'; import tmplA from './a.html'; + export default class Foo extends LightningElement { connectedCallback() { this.foo(); @@ -303,6 +309,7 @@ testRule('no-unsupported-ssr-properties', { code: ` import { LightningElement } from 'lwc'; import tmplA from './a.html'; + export default class Foo extends LightningElement { connectedCallback() { this.foo(); @@ -420,7 +427,7 @@ testRule('no-unsupported-ssr-properties', { { code: ` import { LightningElement } from 'lwc'; - + export default class Foo extends LightningElement { connectedCallback() { this.childNodes.item(0).textContent = 'foo'; From db05587a8c73c08cd110bc339f57cebdb8b48d8e Mon Sep 17 00:00:00 2001 From: achab9 Date: Fri, 22 Nov 2024 11:09:15 -0500 Subject: [PATCH 13/23] spaces --- test/lib/rules/no-unsupported-ssr-properties.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lib/rules/no-unsupported-ssr-properties.js b/test/lib/rules/no-unsupported-ssr-properties.js index c888ace..1b73f1f 100644 --- a/test/lib/rules/no-unsupported-ssr-properties.js +++ b/test/lib/rules/no-unsupported-ssr-properties.js @@ -286,7 +286,7 @@ testRule('no-unsupported-ssr-properties', { code: ` import { LightningElement } from 'lwc'; import tmplA from './a.html'; - + export default class Foo extends LightningElement { connectedCallback() { this.foo(); @@ -395,7 +395,7 @@ testRule('no-unsupported-ssr-properties', { { code: ` import { LightningElement } from 'lwc'; - + export default class Foo extends LightningElement { connectedCallback() { this.querySelector?.('span').getAttribute?.('role').startsWith('button'); From 54c8123075cca64186bf4c86ff7edb611f36ef2e Mon Sep 17 00:00:00 2001 From: a-chabot <90475490+a-chabot@users.noreply.github.com> Date: Wed, 27 Nov 2024 10:01:44 -0500 Subject: [PATCH 14/23] Update lib/util/ssr.js Co-authored-by: Nolan Lawson --- lib/util/ssr.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 3de1258..e8e8760 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -27,11 +27,7 @@ function checkConditionalStatements(test) { const rightNodeConditional = checkConditionalStatements(node.right); - if (!rightNodeConditional) { - return checkConditionalStatements(node.left); - } else if (rightNodeConditional) { - return true; - } + return !!rightNodeConditional || checkConditionalStatements(node.left) } // Base Case: If the node is an Identifier or MemberExpression, don't need to continue. From 8d09a50a24f6c83cd80235fe79e78b5a14f6fa86 Mon Sep 17 00:00:00 2001 From: achab9 Date: Wed, 27 Nov 2024 10:02:43 -0500 Subject: [PATCH 15/23] remove extra base case bc default is false --- lib/util/ssr.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index e8e8760..54b01e1 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -30,11 +30,6 @@ function checkConditionalStatements(test) { return !!rightNodeConditional || checkConditionalStatements(node.left) } - // Base Case: If the node is an Identifier or MemberExpression, don't need to continue. - if (node.type === 'Identifier' || node.type === 'MemberExpression' || node.type === 'Literal') { - return false; - } - // Base Case: If the node is UnaryExpression, call isMetaEnvCheck(). if (node.type === 'UnaryExpression' && node.operator === '!') { return isMetaEnvCheck(node); From 9a4555264f06123e5c09bff9431694001f95b4b1 Mon Sep 17 00:00:00 2001 From: achab9 Date: Wed, 27 Nov 2024 10:04:53 -0500 Subject: [PATCH 16/23] binary expressions --- lib/util/ssr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 54b01e1..d415617 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -21,7 +21,7 @@ function checkConditionalStatements(test) { // Recursive Case: If the node is a logical expression, check its left and right parts. if (node.type === 'LogicalExpression' || node.type === 'BinaryExpression') { - if (node.operator === '||') { + if (node.operator === '||' || node.operator === '>' || node.operator === '>>') { return false; } From 8dec5dc93103f49d561b1e35fa19c80765144326 Mon Sep 17 00:00:00 2001 From: achab9 Date: Wed, 27 Nov 2024 10:45:32 -0500 Subject: [PATCH 17/23] expand conditional statements --- lib/util/ssr.js | 22 +++++++------ .../rules/no-unsupported-ssr-properties.js | 31 +++++++++++++++++++ 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index d415617..eb3e30a 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -8,7 +8,7 @@ module.exports.isSSREscape = function isSSREscape(node) { if (node.type === 'IfStatement' || node.type === 'ConditionalExpression') { - if (checkConditionalStatements(node.test) || isWindowOrDocumentCheck(node.test)) { + if (checkConditionalStatements(node.test)) { return true; } } @@ -19,20 +19,24 @@ module.exports.isSSREscape = function isSSREscape(node) { function checkConditionalStatements(test) { let node = test; + // Base Case: If the node is UnaryExpression, call isMetaEnvCheck(). + if (node.type === 'UnaryExpression' && node.operator === '!') { + return isMetaEnvCheck(node); + } + + // Base Case: If the node is a BinaryExpresion, call isWindowOrDocumentCheck(). + if (node.type === 'BinaryExpression' && node.operator === '!==') { + return isWindowOrDocumentCheck(node); + } + // Recursive Case: If the node is a logical expression, check its left and right parts. - if (node.type === 'LogicalExpression' || node.type === 'BinaryExpression') { + if (node.type === 'LogicalExpression' || (node.type === 'BinaryExpression' && node.operator != '!===')) { if (node.operator === '||' || node.operator === '>' || node.operator === '>>') { return false; } const rightNodeConditional = checkConditionalStatements(node.right); - - return !!rightNodeConditional || checkConditionalStatements(node.left) - } - - // Base Case: If the node is UnaryExpression, call isMetaEnvCheck(). - if (node.type === 'UnaryExpression' && node.operator === '!') { - return isMetaEnvCheck(node); + return !!rightNodeConditional || checkConditionalStatements(node.left); } return false; diff --git a/test/lib/rules/no-unsupported-ssr-properties.js b/test/lib/rules/no-unsupported-ssr-properties.js index 1b73f1f..9814470 100644 --- a/test/lib/rules/no-unsupported-ssr-properties.js +++ b/test/lib/rules/no-unsupported-ssr-properties.js @@ -183,6 +183,19 @@ testRule('no-unsupported-ssr-properties', { } `, }, + { + code: ` + import { LightningElement } from 'lwc'; + + export default class Foo extends LightningElement { + connectedCallback() { + if (randomOtherCheck && typeof window !== 'undefined') { + this.querySelector('span').getAttribute('role'); + } + } + } + `, + }, ], invalid: [ { @@ -512,5 +525,23 @@ testRule('no-unsupported-ssr-properties', { } ] }, + { + code: ` + import { LightningElement } from 'lwc'; + + export default class Foo extends LightningElement { + connectedCallback() { + if (randomOtherCheck && typeof window == 'undefined') { + this.querySelector('span').getAttribute('role'); + } + } + } + `, + errors: [ + { + messageId: 'propertyAccessFound', + } + ] + }, ], }); From a4148518ea2de40ab430494a82c31a3887081353 Mon Sep 17 00:00:00 2001 From: achab9 Date: Mon, 2 Dec 2024 11:20:13 -0500 Subject: [PATCH 18/23] linter --- lib/util/ssr.js | 5 +- .../rules/no-unsupported-ssr-properties.js | 54 +++++++++---------- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index eb3e30a..63ae41c 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -30,7 +30,10 @@ function checkConditionalStatements(test) { } // Recursive Case: If the node is a logical expression, check its left and right parts. - if (node.type === 'LogicalExpression' || (node.type === 'BinaryExpression' && node.operator != '!===')) { + if ( + node.type === 'LogicalExpression' || + (node.type === 'BinaryExpression' && node.operator != '!===') + ) { if (node.operator === '||' || node.operator === '>' || node.operator === '>>') { return false; } diff --git a/test/lib/rules/no-unsupported-ssr-properties.js b/test/lib/rules/no-unsupported-ssr-properties.js index 9814470..96c14d6 100644 --- a/test/lib/rules/no-unsupported-ssr-properties.js +++ b/test/lib/rules/no-unsupported-ssr-properties.js @@ -454,7 +454,7 @@ testRule('no-unsupported-ssr-properties', { ], }, { - code: ` + code: ` import { LightningElement } from 'lwc'; export default class Foo extends LightningElement { @@ -465,11 +465,11 @@ testRule('no-unsupported-ssr-properties', { } } `, - errors: [ - { - messageId: 'propertyAccessFound', - } - ] + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], }, { code: ` @@ -483,11 +483,11 @@ testRule('no-unsupported-ssr-properties', { } } `, - errors: [ - { - messageId: 'propertyAccessFound', - } - ] + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], }, { code: ` @@ -501,11 +501,11 @@ testRule('no-unsupported-ssr-properties', { } } `, - errors: [ - { - messageId: 'propertyAccessFound', - } - ] + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], }, { code: ` @@ -519,14 +519,14 @@ testRule('no-unsupported-ssr-properties', { } } `, - errors: [ - { - messageId: 'propertyAccessFound', - } - ] + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], }, { - code: ` + code: ` import { LightningElement } from 'lwc'; export default class Foo extends LightningElement { @@ -537,11 +537,11 @@ testRule('no-unsupported-ssr-properties', { } } `, - errors: [ - { - messageId: 'propertyAccessFound', - } - ] + errors: [ + { + messageId: 'propertyAccessFound', + }, + ], }, ], }); From 2f4505db4efb5cc9d44e092448741f736f01cd03 Mon Sep 17 00:00:00 2001 From: achab9 Date: Wed, 4 Dec 2024 10:19:24 -0500 Subject: [PATCH 19/23] nolan review notes --- lib/util/ssr.js | 18 ++++++++---------- .../lib/rules/no-unsupported-ssr-properties.js | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 63ae41c..94e3163 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -7,10 +7,11 @@ 'use strict'; module.exports.isSSREscape = function isSSREscape(node) { - if (node.type === 'IfStatement' || node.type === 'ConditionalExpression') { - if (checkConditionalStatements(node.test)) { - return true; - } + if ( + (node.type === 'IfStatement' || node.type === 'ConditionalExpression') && + checkConditionalStatements(node.test) + ) { + return true; } return false; @@ -24,17 +25,14 @@ function checkConditionalStatements(test) { return isMetaEnvCheck(node); } - // Base Case: If the node is a BinaryExpresion, call isWindowOrDocumentCheck(). + // Base Case: If the node is a `!==` BinaryExpresion, call isWindowOrDocumentCheck(). if (node.type === 'BinaryExpression' && node.operator === '!==') { return isWindowOrDocumentCheck(node); } // Recursive Case: If the node is a logical expression, check its left and right parts. - if ( - node.type === 'LogicalExpression' || - (node.type === 'BinaryExpression' && node.operator != '!===') - ) { - if (node.operator === '||' || node.operator === '>' || node.operator === '>>') { + if (node.type === 'LogicalExpression') { + if (node.operator === '||') { return false; } diff --git a/test/lib/rules/no-unsupported-ssr-properties.js b/test/lib/rules/no-unsupported-ssr-properties.js index 96c14d6..0694ce8 100644 --- a/test/lib/rules/no-unsupported-ssr-properties.js +++ b/test/lib/rules/no-unsupported-ssr-properties.js @@ -178,7 +178,7 @@ testRule('no-unsupported-ssr-properties', { export default class Foo extends LightningElement { connectedCallback() { - return isCSR ? this.template.querySelector('button') : null; + return !import.meta.env.SSR ? this.querySelector('button') : null; } } `, From d893920dd82934b8eca841f0b910dfd80f40b839 Mon Sep 17 00:00:00 2001 From: achab9 Date: Wed, 4 Dec 2024 10:30:35 -0500 Subject: [PATCH 20/23] simplify logical expressions --- lib/util/ssr.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 94e3163..50e3ec9 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -31,11 +31,7 @@ function checkConditionalStatements(test) { } // Recursive Case: If the node is a logical expression, check its left and right parts. - if (node.type === 'LogicalExpression') { - if (node.operator === '||') { - return false; - } - + if (node.type === 'LogicalExpression' && node.operator === '&&') { const rightNodeConditional = checkConditionalStatements(node.right); return !!rightNodeConditional || checkConditionalStatements(node.left); } From 759bd26a133830c57d61bfa19e9b2c98195a96d8 Mon Sep 17 00:00:00 2001 From: a-chabot <90475490+a-chabot@users.noreply.github.com> Date: Wed, 4 Dec 2024 15:18:52 -0500 Subject: [PATCH 21/23] Update lib/util/ssr.js with ! Co-authored-by: Nolan Lawson --- lib/util/ssr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 50e3ec9..46c3390 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -20,7 +20,7 @@ module.exports.isSSREscape = function isSSREscape(node) { function checkConditionalStatements(test) { let node = test; - // Base Case: If the node is UnaryExpression, call isMetaEnvCheck(). + // Base Case: If the node is a `!` UnaryExpression, call isMetaEnvCheck(). if (node.type === 'UnaryExpression' && node.operator === '!') { return isMetaEnvCheck(node); } From b071787f684edf494ce3b5e07743908dbaf3f984 Mon Sep 17 00:00:00 2001 From: a-chabot <90475490+a-chabot@users.noreply.github.com> Date: Wed, 4 Dec 2024 15:19:08 -0500 Subject: [PATCH 22/23] Update lib/util/ssr.js with && Co-authored-by: Nolan Lawson --- lib/util/ssr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index 46c3390..ba7e0a3 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -30,7 +30,7 @@ function checkConditionalStatements(test) { return isWindowOrDocumentCheck(node); } - // Recursive Case: If the node is a logical expression, check its left and right parts. + // Recursive Case: If the node is a `&&` logical expression, check its left and right parts. if (node.type === 'LogicalExpression' && node.operator === '&&') { const rightNodeConditional = checkConditionalStatements(node.right); return !!rightNodeConditional || checkConditionalStatements(node.left); From 26b8e233dbafde66024c6e93b588eb309e8aa1e9 Mon Sep 17 00:00:00 2001 From: achab9 Date: Wed, 4 Dec 2024 15:20:16 -0500 Subject: [PATCH 23/23] remove !! --- lib/util/ssr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util/ssr.js b/lib/util/ssr.js index ba7e0a3..069eb84 100644 --- a/lib/util/ssr.js +++ b/lib/util/ssr.js @@ -33,7 +33,7 @@ function checkConditionalStatements(test) { // Recursive Case: If the node is a `&&` logical expression, check its left and right parts. if (node.type === 'LogicalExpression' && node.operator === '&&') { const rightNodeConditional = checkConditionalStatements(node.right); - return !!rightNodeConditional || checkConditionalStatements(node.left); + return rightNodeConditional || checkConditionalStatements(node.left); } return false;