From 464b5652834dc438a722e52b25fe1fecb4d1b9d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Tue, 19 Dec 2023 13:52:42 +0100 Subject: [PATCH] ci: Remove unnecessary async/await, enable await-thenable linting rule (no-changelog) (#8076) ## Summary We accidentally made some functions `async` in https://github.com/n8n-io/n8n/pull/7846 This PR reverts that change. ## Review / Merge checklist - [x] PR title and summary are descriptive. --- packages/@n8n_io/eslint-config/base.js | 4 +++- packages/cli/package.json | 2 +- packages/cli/src/ActiveWorkflowRunner.ts | 4 ++-- packages/cli/src/CredentialsHelper.ts | 2 +- packages/cli/src/Server.ts | 2 +- .../cli/src/UserManagement/PermissionChecker.ts | 2 +- .../cli/src/UserManagement/UserManagementHelper.ts | 6 +++--- packages/cli/src/WorkflowHelpers.ts | 2 +- packages/cli/src/commands/start.ts | 2 -- .../src/controllers/passwordReset.controller.ts | 2 +- .../controllers/workflowStatistics.controller.ts | 2 +- .../src/credentials/credentials.controller.ee.ts | 4 ++-- .../cli/src/credentials/credentials.controller.ts | 4 ++-- .../cli/src/credentials/credentials.service.ee.ts | 2 +- .../cli/src/credentials/credentials.service.ts | 4 ++-- packages/cli/src/databases/entities/User.ts | 2 +- .../repositories/sharedCredentials.repository.ts | 2 +- packages/cli/src/decorators/registerController.ts | 2 +- packages/cli/src/executions/executions.service.ts | 2 +- packages/cli/src/workflows/workflow.service.ts | 6 +++--- .../workflowHistory/workflowHistory.service.ee.ts | 2 +- .../cli/src/workflows/workflows.controller.ee.ts | 4 ++-- packages/cli/src/workflows/workflows.controller.ts | 2 +- .../sharedCredentials.repository.test.ts | 14 ++++++-------- packages/nodes-base/nodes/Redis/Redis.node.ts | 12 +----------- packages/workflow/test/RoutingNode.test.ts | 2 +- pnpm-lock.yaml | 10 ++++++---- 27 files changed, 47 insertions(+), 57 deletions(-) diff --git a/packages/@n8n_io/eslint-config/base.js b/packages/@n8n_io/eslint-config/base.js index e10f90372b..c3b0b54460 100644 --- a/packages/@n8n_io/eslint-config/base.js +++ b/packages/@n8n_io/eslint-config/base.js @@ -153,6 +153,9 @@ const config = (module.exports = { */ '@typescript-eslint/array-type': ['error', { default: 'array-simple' }], + /** https://typescript-eslint.io/rules/await-thenable/ */ + '@typescript-eslint/await-thenable': 'error', + /** * https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-ts-comment.md */ @@ -477,7 +480,6 @@ const config = (module.exports = { process.env.NODE_ENV === 'development' ? 'warn' : 'error', // TODO: Remove these - '@typescript-eslint/await-thenable': 'off', '@typescript-eslint/ban-ts-comment': 'off', '@typescript-eslint/naming-convention': 'off', 'import/no-duplicates': 'off', diff --git a/packages/cli/package.json b/packages/cli/package.json index 968b80a49e..7d7d0e6288 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -76,7 +76,7 @@ "@types/formidable": "^3.4.0", "@types/json-diff": "^1.0.0", "@types/jsonwebtoken": "^9.0.1", - "@types/localtunnel": "^1.9.0", + "@types/localtunnel": "^2.0.4", "@types/lodash": "^4.14.195", "@types/passport-jwt": "^3.0.6", "@types/psl": "^1.1.0", diff --git a/packages/cli/src/ActiveWorkflowRunner.ts b/packages/cli/src/ActiveWorkflowRunner.ts index 72ec73da36..a12ea36c5b 100644 --- a/packages/cli/src/ActiveWorkflowRunner.ts +++ b/packages/cli/src/ActiveWorkflowRunner.ts @@ -276,7 +276,7 @@ export class ActiveWorkflowRunner implements IWebhookManager { * Get the IDs of active workflows from storage. */ async allActiveInStorage(options?: { user: User; scope: Scope | Scope[] }) { - const isFullAccess = !options?.user || (await options.user.hasGlobalScope(options.scope)); + const isFullAccess = !options?.user || options.user.hasGlobalScope(options.scope); const activationErrors = await this.activationErrorsService.getAll(); @@ -291,7 +291,7 @@ export class ActiveWorkflowRunner implements IWebhookManager { .filter((workflowId) => !activationErrors[workflowId]); } - const where = await whereClause({ + const where = whereClause({ user: options.user, globalScope: 'workflow:list', entityType: 'workflow', diff --git a/packages/cli/src/CredentialsHelper.ts b/packages/cli/src/CredentialsHelper.ts index 6354755438..5920986de9 100644 --- a/packages/cli/src/CredentialsHelper.ts +++ b/packages/cli/src/CredentialsHelper.ts @@ -579,7 +579,7 @@ export class CredentialsHelper extends ICredentialsHelper { credentialType, 'internal' as WorkflowExecuteMode, undefined, - await user.hasGlobalScope('externalSecret:use'), + user.hasGlobalScope('externalSecret:use'), ); } catch (error) { this.logger.debug('Credential test failed', error); diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 5e25d66b86..b46dcc2a71 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -466,7 +466,7 @@ export class Server extends AbstractServer { const shared = await Container.get(SharedWorkflowRepository).findOne({ relations: ['workflow'], - where: await whereClause({ + where: whereClause({ user: req.user, globalScope: 'workflow:read', entityType: 'workflow', diff --git a/packages/cli/src/UserManagement/PermissionChecker.ts b/packages/cli/src/UserManagement/PermissionChecker.ts index 6fb85281e8..b9099915e0 100644 --- a/packages/cli/src/UserManagement/PermissionChecker.ts +++ b/packages/cli/src/UserManagement/PermissionChecker.ts @@ -32,7 +32,7 @@ export class PermissionChecker { relations: ['globalRole'], }); - if (await user.hasGlobalScope('workflow:execute')) return; + if (user.hasGlobalScope('workflow:execute')) return; // allow if all creds used in this workflow are a subset of // all creds accessible to users who have access to this workflow diff --git a/packages/cli/src/UserManagement/UserManagementHelper.ts b/packages/cli/src/UserManagement/UserManagementHelper.ts index dd53a76324..6b9b1a0eaf 100644 --- a/packages/cli/src/UserManagement/UserManagementHelper.ts +++ b/packages/cli/src/UserManagement/UserManagementHelper.ts @@ -58,7 +58,7 @@ export function rightDiff( * Build a `where` clause for a TypeORM entity search, * checking for member access if the user is not an owner. */ -export async function whereClause({ +export function whereClause({ user, entityType, globalScope, @@ -70,10 +70,10 @@ export async function whereClause({ globalScope: Scope; entityId?: string; roles?: string[]; -}): Promise { +}): WhereClause { const where: WhereClause = entityId ? { [entityType]: { id: entityId } } : {}; - if (!(await user.hasGlobalScope(globalScope))) { + if (!user.hasGlobalScope(globalScope)) { where.user = { id: user.id }; if (roles?.length) { where.role = { name: In(roles) }; diff --git a/packages/cli/src/WorkflowHelpers.ts b/packages/cli/src/WorkflowHelpers.ts index 477d0565dd..84b06a492f 100644 --- a/packages/cli/src/WorkflowHelpers.ts +++ b/packages/cli/src/WorkflowHelpers.ts @@ -422,7 +422,7 @@ export async function replaceInvalidCredentials(workflow: WorkflowEntity): Promi */ export async function getSharedWorkflowIds(user: User, roles?: RoleNames[]): Promise { const where: FindOptionsWhere = {}; - if (!(await user.hasGlobalScope('workflow:read'))) { + if (!user.hasGlobalScope('workflow:read')) { where.userId = user.id; } if (roles?.length) { diff --git a/packages/cli/src/commands/start.ts b/packages/cli/src/commands/start.ts index 0ea89dc3b6..e2eeecc981 100644 --- a/packages/cli/src/commands/start.ts +++ b/packages/cli/src/commands/start.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/await-thenable */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { Container } from 'typedi'; @@ -316,7 +315,6 @@ export class Start extends BaseCommand { const port = config.getEnv('port'); - // @ts-ignore const webhookTunnel = await localtunnel(port, tunnelSettings); process.env.WEBHOOK_URL = `${webhookTunnel.url}/`; diff --git a/packages/cli/src/controllers/passwordReset.controller.ts b/packages/cli/src/controllers/passwordReset.controller.ts index 463e46d9ca..06b1dd250c 100644 --- a/packages/cli/src/controllers/passwordReset.controller.ts +++ b/packages/cli/src/controllers/passwordReset.controller.ts @@ -96,7 +96,7 @@ export class PasswordResetController { if ( isSamlCurrentAuthenticationMethod() && !( - (user && (await user.hasGlobalScope('user:resetPassword'))) === true || + (user && user.hasGlobalScope('user:resetPassword')) === true || user?.settings?.allowSSOManualLogin === true ) ) { diff --git a/packages/cli/src/controllers/workflowStatistics.controller.ts b/packages/cli/src/controllers/workflowStatistics.controller.ts index 4a868bdc2e..2eb9e0dcac 100644 --- a/packages/cli/src/controllers/workflowStatistics.controller.ts +++ b/packages/cli/src/controllers/workflowStatistics.controller.ts @@ -37,7 +37,7 @@ export class WorkflowStatisticsController { const workflowId = req.params.id; const allowed = await this.sharedWorkflowRepository.exist({ relations: ['workflow'], - where: await whereClause({ + where: whereClause({ user, globalScope: 'workflow:read', entityType: 'workflow', diff --git a/packages/cli/src/credentials/credentials.controller.ee.ts b/packages/cli/src/credentials/credentials.controller.ee.ts index 6de562b9dd..c2f23d9b15 100644 --- a/packages/cli/src/credentials/credentials.controller.ee.ts +++ b/packages/cli/src/credentials/credentials.controller.ee.ts @@ -50,7 +50,7 @@ EECredentialsController.get( const userSharing = credential.shared?.find((shared) => shared.user.id === req.user.id); - if (!userSharing && !(await req.user.hasGlobalScope('credential:read'))) { + if (!userSharing && !req.user.hasGlobalScope('credential:read')) { throw new UnauthorizedError('Forbidden.'); } @@ -130,7 +130,7 @@ EECredentialsController.put( if (!ownsCredential || !credential) { credential = undefined; // Allow owners/admins to share - if (await req.user.hasGlobalScope('credential:share')) { + if (req.user.hasGlobalScope('credential:share')) { const sharedRes = await EECredentials.getSharing(req.user, credentialId, { allowGlobalScope: true, globalScope: 'credential:share', diff --git a/packages/cli/src/credentials/credentials.controller.ts b/packages/cli/src/credentials/credentials.controller.ts index 9223f7a0f3..82f6bad527 100644 --- a/packages/cli/src/credentials/credentials.controller.ts +++ b/packages/cli/src/credentials/credentials.controller.ts @@ -163,7 +163,7 @@ credentialsController.patch( ); } - if (sharing.role.name !== 'owner' && !(await req.user.hasGlobalScope('credential:update'))) { + if (sharing.role.name !== 'owner' && !req.user.hasGlobalScope('credential:update')) { Container.get(Logger).info( 'Attempt to update credential blocked due to lack of permissions', { @@ -232,7 +232,7 @@ credentialsController.delete( ); } - if (sharing.role.name !== 'owner' && !(await req.user.hasGlobalScope('credential:delete'))) { + if (sharing.role.name !== 'owner' && !req.user.hasGlobalScope('credential:delete')) { Container.get(Logger).info( 'Attempt to delete credential blocked due to lack of permissions', { diff --git a/packages/cli/src/credentials/credentials.service.ee.ts b/packages/cli/src/credentials/credentials.service.ee.ts index 418c674bb8..627af5c678 100644 --- a/packages/cli/src/credentials/credentials.service.ee.ts +++ b/packages/cli/src/credentials/credentials.service.ee.ts @@ -40,7 +40,7 @@ export class EECredentialsService extends CredentialsService { // Omit user from where if the requesting user has relevant // global credential permissions. This allows the user to // access credentials they don't own. - if (!options.allowGlobalScope || !(await user.hasGlobalScope(options.globalScope))) { + if (!options.allowGlobalScope || !user.hasGlobalScope(options.globalScope)) { where.userId = user.id; } diff --git a/packages/cli/src/credentials/credentials.service.ts b/packages/cli/src/credentials/credentials.service.ts index e684423922..ab5e237977 100644 --- a/packages/cli/src/credentials/credentials.service.ts +++ b/packages/cli/src/credentials/credentials.service.ts @@ -88,7 +88,7 @@ export class CredentialsService { ) { const findManyOptions = this.toFindManyOptions(options.listQueryOptions); - const returnAll = (await user.hasGlobalScope('credential:list')) && !options.onlyOwn; + const returnAll = user.hasGlobalScope('credential:list') && !options.onlyOwn; const isDefaultSelect = !options.listQueryOptions?.select; if (returnAll) { @@ -150,7 +150,7 @@ export class CredentialsService { // Omit user from where if the requesting user has relevant // global credential permissions. This allows the user to // access credentials they don't own. - if (!options.allowGlobalScope || !(await user.hasGlobalScope(options.globalScope))) { + if (!options.allowGlobalScope || !user.hasGlobalScope(options.globalScope)) { Object.assign(where, { userId: user.id, role: { name: 'owner' }, diff --git a/packages/cli/src/databases/entities/User.ts b/packages/cli/src/databases/entities/User.ts index d3d8a7122d..974315cc08 100644 --- a/packages/cli/src/databases/entities/User.ts +++ b/packages/cli/src/databases/entities/User.ts @@ -134,7 +134,7 @@ export class User extends WithTimestamps implements IUser { return STATIC_SCOPE_MAP[this.globalRole?.name] ?? []; } - async hasGlobalScope(scope: Scope | Scope[], scopeOptions?: ScopeOptions): Promise { + hasGlobalScope(scope: Scope | Scope[], scopeOptions?: ScopeOptions): boolean { return hasScope( scope, { diff --git a/packages/cli/src/databases/repositories/sharedCredentials.repository.ts b/packages/cli/src/databases/repositories/sharedCredentials.repository.ts index 2ba0af3484..6467de4dec 100644 --- a/packages/cli/src/databases/repositories/sharedCredentials.repository.ts +++ b/packages/cli/src/databases/repositories/sharedCredentials.repository.ts @@ -15,7 +15,7 @@ export class SharedCredentialsRepository extends Repository { relations: ['credentials'], where: { credentialsId, - ...(!(await user.hasGlobalScope('credential:read')) ? { userId: user.id } : {}), + ...(!user.hasGlobalScope('credential:read') ? { userId: user.id } : {}), }, }); if (!sharedCredential) return null; diff --git a/packages/cli/src/decorators/registerController.ts b/packages/cli/src/decorators/registerController.ts index 1900aa4c7d..ccc097dde9 100644 --- a/packages/cli/src/decorators/registerController.ts +++ b/packages/cli/src/decorators/registerController.ts @@ -68,7 +68,7 @@ export const createGlobalScopeMiddleware = if (!user) return res.status(401).json({ status: 'error', message: 'Unauthorized' }); - const hasScopes = await user.hasGlobalScope(scopes); + const hasScopes = user.hasGlobalScope(scopes); if (!hasScopes) { return res.status(403).json({ status: 'error', message: 'Unauthorized' }); } diff --git a/packages/cli/src/executions/executions.service.ts b/packages/cli/src/executions/executions.service.ts index ab9999d81f..6790636346 100644 --- a/packages/cli/src/executions/executions.service.ts +++ b/packages/cli/src/executions/executions.service.ts @@ -155,7 +155,7 @@ export class ExecutionsService { filter, sharedWorkflowIds, executingWorkflowIds, - await req.user.hasGlobalScope('workflow:list'), + req.user.hasGlobalScope('workflow:list'), ); const formattedExecutions = await Container.get(ExecutionRepository).searchExecutions( diff --git a/packages/cli/src/workflows/workflow.service.ts b/packages/cli/src/workflows/workflow.service.ts index 68af5795d5..7a37d7ba7a 100644 --- a/packages/cli/src/workflows/workflow.service.ts +++ b/packages/cli/src/workflows/workflow.service.ts @@ -71,7 +71,7 @@ export class WorkflowService { // Omit user from where if the requesting user has relevant // global workflow permissions. This allows the user to // access workflows they don't own. - if (!options.allowGlobalScope || !(await user.hasGlobalScope(options.globalScope))) { + if (!options.allowGlobalScope || !user.hasGlobalScope(options.globalScope)) { where.userId = user.id; } @@ -215,7 +215,7 @@ export class WorkflowService { ): Promise { const shared = await this.sharedWorkflowRepository.findOne({ relations: ['workflow', 'role'], - where: await whereClause({ + where: whereClause({ user, globalScope: 'workflow:update', entityType: 'workflow', @@ -482,7 +482,7 @@ export class WorkflowService { const sharedWorkflow = await this.sharedWorkflowRepository.findOne({ relations: ['workflow', 'role'], - where: await whereClause({ + where: whereClause({ user, globalScope: 'workflow:delete', entityType: 'workflow', diff --git a/packages/cli/src/workflows/workflowHistory/workflowHistory.service.ee.ts b/packages/cli/src/workflows/workflowHistory/workflowHistory.service.ee.ts index 2b5852f23b..853c7260f5 100644 --- a/packages/cli/src/workflows/workflowHistory/workflowHistory.service.ee.ts +++ b/packages/cli/src/workflows/workflowHistory/workflowHistory.service.ee.ts @@ -21,7 +21,7 @@ export class WorkflowHistoryService { private async getSharedWorkflow(user: User, workflowId: string): Promise { return this.sharedWorkflowRepository.findOne({ where: { - ...(!(await user.hasGlobalScope('workflow:read')) && { userId: user.id }), + ...(!user.hasGlobalScope('workflow:read') && { userId: user.id }), workflowId, }, }); diff --git a/packages/cli/src/workflows/workflows.controller.ee.ts b/packages/cli/src/workflows/workflows.controller.ee.ts index 20cce56506..900c8d3660 100644 --- a/packages/cli/src/workflows/workflows.controller.ee.ts +++ b/packages/cli/src/workflows/workflows.controller.ee.ts @@ -67,7 +67,7 @@ EEWorkflowController.put( if (!ownsWorkflow || !workflow) { workflow = undefined; // Allow owners/admins to share - if (await req.user.hasGlobalScope('workflow:share')) { + if (req.user.hasGlobalScope('workflow:share')) { const sharedRes = await Container.get(WorkflowService).getSharing(req.user, workflowId, { allowGlobalScope: true, globalScope: 'workflow:share', @@ -136,7 +136,7 @@ EEWorkflowController.get( } const userSharing = workflow.shared?.find((shared) => shared.user.id === req.user.id); - if (!userSharing && !(await req.user.hasGlobalScope('workflow:read'))) { + if (!userSharing && !req.user.hasGlobalScope('workflow:read')) { throw new UnauthorizedError( 'You do not have permission to access this workflow. Ask the owner to share it with you', ); diff --git a/packages/cli/src/workflows/workflows.controller.ts b/packages/cli/src/workflows/workflows.controller.ts index de53ed1dfe..b32ddce0ad 100644 --- a/packages/cli/src/workflows/workflows.controller.ts +++ b/packages/cli/src/workflows/workflows.controller.ts @@ -209,7 +209,7 @@ workflowsController.get( const shared = await Container.get(SharedWorkflowRepository).findOne({ relations, - where: await whereClause({ + where: whereClause({ user: req.user, entityType: 'workflow', globalScope: 'workflow:read', diff --git a/packages/cli/test/unit/repositories/sharedCredentials.repository.test.ts b/packages/cli/test/unit/repositories/sharedCredentials.repository.test.ts index 3755fff579..f14c2ee354 100644 --- a/packages/cli/test/unit/repositories/sharedCredentials.repository.test.ts +++ b/packages/cli/test/unit/repositories/sharedCredentials.repository.test.ts @@ -24,20 +24,18 @@ describe('SharedCredentialsRepository', () => { sharedCredential.credentials = mock({ id: credentialsId }); const owner = mock({ isOwner: true, - hasGlobalScope: async (scope) => { - return hasScope(scope, { + hasGlobalScope: (scope) => + hasScope(scope, { global: ownerPermissions, - }); - }, + }), }); const member = mock({ isOwner: false, id: 'test', - hasGlobalScope: async (scope) => { - return hasScope(scope, { + hasGlobalScope: (scope) => + hasScope(scope, { global: memberPermissions, - }); - }, + }), }); beforeEach(() => { diff --git a/packages/nodes-base/nodes/Redis/Redis.node.ts b/packages/nodes-base/nodes/Redis/Redis.node.ts index c3c602a1d4..9d7a3fc65b 100644 --- a/packages/nodes-base/nodes/Redis/Redis.node.ts +++ b/packages/nodes-base/nodes/Redis/Redis.node.ts @@ -1,7 +1,6 @@ import util from 'util'; import type { IExecuteFunctions, - GenericValue, ICredentialDataDecryptedObject, ICredentialsDecrypted, ICredentialTestFunctions, @@ -757,17 +756,8 @@ export class Redis implements INodeType { continue; } - const promises: { - [key: string]: GenericValue; - } = {}; - for (const keyName of keys) { - promises[keyName] = await getValue(client, keyName); - } - - for (const keyName of keys) { - // eslint-disable-next-line @typescript-eslint/await-thenable - item.json[keyName] = await promises[keyName]; + item.json[keyName] = await getValue(client, keyName); } returnItems.push(item); } else if (operation === 'set') { diff --git a/packages/workflow/test/RoutingNode.test.ts b/packages/workflow/test/RoutingNode.test.ts index a2ca525ba7..9496e84d6a 100644 --- a/packages/workflow/test/RoutingNode.test.ts +++ b/packages/workflow/test/RoutingNode.test.ts @@ -706,7 +706,7 @@ describe('RoutingNode', () => { mode, ); - const result = await routingNode.getRequestOptionsFromParameters( + const result = routingNode.getRequestOptionsFromParameters( executeSingleFunctions, testData.input.nodeTypeProperties, itemIndex, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 003363da8e..5069628119 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -749,8 +749,8 @@ importers: specifier: ^9.0.1 version: 9.0.1 '@types/localtunnel': - specifier: ^1.9.0 - version: 1.9.0 + specifier: ^2.0.4 + version: 2.0.4 '@types/lodash': specifier: ^4.14.195 version: 4.14.195 @@ -9357,8 +9357,10 @@ packages: /@types/linkify-it@3.0.2: resolution: {integrity: sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==} - /@types/localtunnel@1.9.0: - resolution: {integrity: sha512-3YxO7RHRrmtYNX6Rhkr97bnXHrF1Ckfo4axENWLcBXWi+8B1WsNbqPqe5Eg6TA5survjAWWvLTu1KQesuLHVgQ==} + /@types/localtunnel@2.0.4: + resolution: {integrity: sha512-7WM5nlEfEKp8MpwthPa2utdy+f/7ZBxMPzu8qw6EijFFTcpzh5CXgt2YoncxWAZNOPNieMofXCKFudtDEY4bag==} + dependencies: + '@types/node': 18.16.16 dev: true /@types/lodash-es@4.17.6: