snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
This commit is contained in:
237
packages/apps/base-runtime/src/lib/ast/operations.ts
Normal file
237
packages/apps/base-runtime/src/lib/ast/operations.ts
Normal file
@@ -0,0 +1,237 @@
|
||||
import type { AnyNode, AssignmentExpression, Function, AwaitExpression, Expression, Identifier, MethodDefinition, Property } from 'acorn';
|
||||
import type { FullAncestorWalkerCallback } from 'acorn-walk';
|
||||
|
||||
export type WalkerState = {
|
||||
isModified: boolean;
|
||||
functionIdentifiers: Set<string>;
|
||||
};
|
||||
|
||||
export function getFunctionIdentifier(ancestors: AnyNode[], functionNodeIndex: number) {
|
||||
const parent = ancestors[functionNodeIndex - 1];
|
||||
|
||||
// If there is a parent node and it's not a computed property, we can try to
|
||||
// extract an identifier for our function from it. This needs to be done first
|
||||
// because when functions are assigned to named symbols, this will be the only
|
||||
// way to call it, even if the function itself has an identifier
|
||||
// Consider the following block:
|
||||
//
|
||||
// const foo = function bar() {}
|
||||
//
|
||||
// Even though the function itself has a name, the only way to call it in the
|
||||
// program is wiht `foo()`
|
||||
if (parent && !(parent as Property | MethodDefinition).computed) {
|
||||
// Several node types can have an id prop of type Identifier
|
||||
const { id } = parent as unknown as { id?: Identifier };
|
||||
if (id?.type === 'Identifier') {
|
||||
return id.name;
|
||||
}
|
||||
|
||||
// Usually assignments to object properties (MethodDefinition, Property)
|
||||
const { key } = parent as MethodDefinition | Property;
|
||||
if (key?.type === 'Identifier') {
|
||||
return key.name;
|
||||
}
|
||||
|
||||
// Variable assignments have left hand side that can be used as Identifier
|
||||
const { left } = parent as AssignmentExpression;
|
||||
|
||||
// Simple assignment: `const fn = () => {}`
|
||||
if (left?.type === 'Identifier') {
|
||||
return left.name;
|
||||
}
|
||||
|
||||
// Object property assignment: `obj.fn = () => {}`
|
||||
if (left?.type === 'MemberExpression' && !left.computed) {
|
||||
return (left.property as Identifier).name;
|
||||
}
|
||||
}
|
||||
|
||||
// nodeIndex needs to be the index of a Function node (either FunctionDeclaration or FunctionExpression)
|
||||
const currentNode = ancestors[functionNodeIndex] as Function;
|
||||
|
||||
// Function declarations or expressions can be directly named
|
||||
if (currentNode.id?.type === 'Identifier') {
|
||||
return currentNode.id.name;
|
||||
}
|
||||
}
|
||||
|
||||
export function wrapWithAwait(node: Expression) {
|
||||
if (!node.type.endsWith('Expression')) {
|
||||
throw new Error(`Can't wrap "${node.type}" with await`);
|
||||
}
|
||||
|
||||
const innerNode: Expression = { ...node };
|
||||
|
||||
node.type = 'AwaitExpression';
|
||||
// starting here node has become an AwaitExpression
|
||||
(node as AwaitExpression).argument = innerNode;
|
||||
|
||||
Object.keys(node).forEach((key) => !['type', 'argument'].includes(key) && delete node[key as keyof AnyNode]);
|
||||
}
|
||||
|
||||
export function asyncifyScope(ancestors: AnyNode[], state: WalkerState) {
|
||||
const functionNodeIndex = ancestors.findLastIndex((n) => 'async' in n);
|
||||
if (functionNodeIndex === -1) return;
|
||||
|
||||
// At this point this is a node with an "async" property, so it has to be
|
||||
// of type Function - let TS know about that
|
||||
const functionScopeNode = ancestors[functionNodeIndex] as Function;
|
||||
|
||||
if (functionScopeNode.async) {
|
||||
return;
|
||||
}
|
||||
|
||||
functionScopeNode.async = true;
|
||||
|
||||
// If the parent of a function node is a call expression, we're talking about an IIFE
|
||||
// Should we care about this case as well?
|
||||
// const parentNode = ancestors[functionScopeIndex-1];
|
||||
// if (parentNode?.type === 'CallExpression' && ancestors[functionScopeIndex-2] && ancestors[functionScopeIndex-2].type !== 'AwaitExpression') {
|
||||
// pendingOperations.push(buildFunctionPredicate(getFunctionIdentifier(ancestors, functionScopeIndex-2)));
|
||||
// }
|
||||
|
||||
const identifier = getFunctionIdentifier(ancestors, functionNodeIndex);
|
||||
|
||||
// We can't fix calls of functions which name we can't determine at compile time
|
||||
if (!identifier) return;
|
||||
|
||||
state.functionIdentifiers.add(identifier);
|
||||
}
|
||||
|
||||
export function buildFixModifiedFunctionsOperation(functionIdentifiers: Set<string>): FullAncestorWalkerCallback<WalkerState> {
|
||||
return function _fixModifiedFunctionsOperation(node, state, ancestors) {
|
||||
if (node.type !== 'CallExpression') return;
|
||||
|
||||
// This node is a simple call to a function, like `fn()`
|
||||
let isWrappable = node.callee.type === 'Identifier' && functionIdentifiers.has(node.callee.name);
|
||||
|
||||
// This node is a call to an object property or instance method, like `obj.fn()`, but not computed like `obj[fn]()`
|
||||
isWrappable ||=
|
||||
node.callee.type === 'MemberExpression' &&
|
||||
!node.callee.computed &&
|
||||
node.callee.property?.type === 'Identifier' &&
|
||||
functionIdentifiers.has(node.callee.property.name);
|
||||
|
||||
// This is a weird dereferencing technique used by bundlers, and since we'll be dealing with bundled sources we have to check for it
|
||||
// e.g. `r=(0,fn)(e)`
|
||||
if (!isWrappable && node.callee.type === 'SequenceExpression') {
|
||||
const [, secondExpression] = node.callee.expressions;
|
||||
isWrappable = secondExpression?.type === 'Identifier' && functionIdentifiers.has(secondExpression.name);
|
||||
isWrappable ||=
|
||||
secondExpression?.type === 'MemberExpression' &&
|
||||
!secondExpression.computed &&
|
||||
secondExpression.property.type === 'Identifier' &&
|
||||
functionIdentifiers.has(secondExpression.property.name);
|
||||
}
|
||||
|
||||
if (!isWrappable) return;
|
||||
|
||||
// ancestors[ancestors.length-1] === node, so here we're checking for parent node
|
||||
const parentNode = ancestors[ancestors.length - 2];
|
||||
if (!parentNode || parentNode.type === 'AwaitExpression') return;
|
||||
|
||||
wrapWithAwait(node);
|
||||
asyncifyScope(ancestors, state);
|
||||
|
||||
state.isModified = true;
|
||||
};
|
||||
}
|
||||
|
||||
export const checkReassignmentOfModifiedIdentifiers: FullAncestorWalkerCallback<WalkerState> = (
|
||||
node,
|
||||
{ functionIdentifiers },
|
||||
_ancestors,
|
||||
) => {
|
||||
if (node.type === 'AssignmentExpression') {
|
||||
if (node.operator !== '=') return;
|
||||
|
||||
let identifier = '';
|
||||
|
||||
if (node.left.type === 'Identifier') identifier = node.left.name;
|
||||
|
||||
if (node.left.type === 'MemberExpression' && !node.left.computed) {
|
||||
identifier = (node.left.property as Identifier).name;
|
||||
}
|
||||
|
||||
if (!identifier || node.right.type !== 'Identifier' || !functionIdentifiers.has(node.right.name)) return;
|
||||
|
||||
functionIdentifiers.add(identifier);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.type === 'VariableDeclarator') {
|
||||
if (node.id.type !== 'Identifier' || functionIdentifiers.has(node.id.name)) return;
|
||||
|
||||
if (node.init?.type !== 'Identifier' || !functionIdentifiers.has(node.init?.name)) return;
|
||||
|
||||
functionIdentifiers.add(node.id.name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// "Property" is for plain objects, "PropertyDefinition" is for classes
|
||||
// but both share the same structure
|
||||
if (node.type === 'Property' || node.type === 'PropertyDefinition') {
|
||||
if (node.key.type !== 'Identifier' || functionIdentifiers.has(node.key.name)) return;
|
||||
|
||||
if (node.value?.type !== 'Identifier' || !functionIdentifiers.has(node.value.name)) return;
|
||||
|
||||
functionIdentifiers.add(node.key.name);
|
||||
}
|
||||
};
|
||||
|
||||
export const fixLivechatIsOnlineCalls: FullAncestorWalkerCallback<WalkerState> = (node, state, ancestors) => {
|
||||
if (node.type !== 'MemberExpression' || node.computed) return;
|
||||
|
||||
if ((node.property as Identifier).name !== 'isOnline') return;
|
||||
|
||||
if (node.object.type !== 'CallExpression') return;
|
||||
|
||||
if (node.object.callee.type !== 'MemberExpression') return;
|
||||
|
||||
if ((node.object.callee.property as Identifier).name !== 'getLivechatReader') return;
|
||||
|
||||
let parentIndex = ancestors.length - 2;
|
||||
let targetNode = ancestors[parentIndex];
|
||||
|
||||
if (targetNode.type !== 'CallExpression') {
|
||||
targetNode = node;
|
||||
} else {
|
||||
parentIndex--;
|
||||
}
|
||||
|
||||
// If we're already wrapped with an await, nothing to do
|
||||
if (ancestors[parentIndex].type === 'AwaitExpression') return;
|
||||
|
||||
// If we're in the middle of a chained member access, we can't wrap with await
|
||||
if (ancestors[parentIndex].type === 'MemberExpression') return;
|
||||
|
||||
wrapWithAwait(targetNode);
|
||||
asyncifyScope(ancestors, state);
|
||||
|
||||
state.isModified = true;
|
||||
};
|
||||
|
||||
export const fixRoomUsernamesCalls: FullAncestorWalkerCallback<WalkerState> = (node, state, ancestors) => {
|
||||
if (node.type !== 'MemberExpression' || node.computed) return;
|
||||
|
||||
if ((node.property as Identifier).name !== 'usernames') return;
|
||||
|
||||
let parentIndex = ancestors.length - 2;
|
||||
let targetNode = ancestors[parentIndex];
|
||||
|
||||
if (targetNode.type !== 'CallExpression') {
|
||||
targetNode = node;
|
||||
} else {
|
||||
parentIndex--;
|
||||
}
|
||||
|
||||
// If we're already wrapped with an await, nothing to do
|
||||
if (ancestors[parentIndex].type === 'AwaitExpression') return;
|
||||
|
||||
wrapWithAwait(targetNode);
|
||||
asyncifyScope(ancestors, state);
|
||||
|
||||
state.isModified = true;
|
||||
};
|
||||
Reference in New Issue
Block a user