Skip to content

Commit a1100c2

Browse files
authored
Only enable Node lint rules for Node files (#3672)
In a previous commit, we mistakenly introduced a Node-specific function for testing deep equality, and this ended up crashing the extension. This would usually have been caught by our ESLint rules, as they prohibit use of Node libraries by default. However, the ESLint configuration for this repo imports rules from our `@metamask/eslint-config-nodejs` package and applies them to all files, marking everything as Node-compatible, thereby allowing such usage. This is incorrect: these rules should only apply to test files and scripts. This commit fix the ESLint configuration to match. Doing so revealed a couple of categories of violations, which this commit also fixes: - Some packages import and make use of EventEmitter from Node's `events` module. We add a notice to the README for these packages which advises consumers that these packages are designed to be used in a Node-compatible environment. - Some packages import and make use of Node's `assert` module to check values at runtime. It isn't strictly necessary to use this module, and so we replace its usage with simpler code. - Some packages import and make use of Node's `inspect` utility function. We don't strictly need this either, and we replace its usage with simpler code as well.
1 parent a3e603c commit a1100c2

File tree

17 files changed

+100
-59
lines changed

17 files changed

+100
-59
lines changed

.eslintrc.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
module.exports = {
22
root: true,
3-
extends: ['@metamask/eslint-config', '@metamask/eslint-config-nodejs'],
3+
extends: ['@metamask/eslint-config'],
44
ignorePatterns: [
55
'!.eslintrc.js',
6-
'!jest.config.js',
6+
'!.prettierrc.js',
77
'node_modules',
88
'**/dist',
99
'**/docs',
@@ -12,6 +12,19 @@ module.exports = {
1212
'scripts/create-package/package-template',
1313
],
1414
overrides: [
15+
{
16+
files: [
17+
'**/jest.config.js',
18+
'**/jest.environment.js',
19+
'**/tests/**/*.{ts,js}',
20+
'*.js',
21+
'*.test.{ts,js}',
22+
'scripts/*.ts',
23+
'scripts/create-package/*.ts',
24+
'yarn.config.cjs',
25+
],
26+
extends: ['@metamask/eslint-config-nodejs'],
27+
},
1528
{
1629
files: ['*.test.{ts,js}', '**/tests/**/*.{ts,js}'],
1730
extends: ['@metamask/eslint-config-jest'],

packages/message-manager/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ or
1010

1111
`npm install @metamask/message-manager`
1212

13+
## Compatibility
14+
15+
This package relies implicitly upon the `EventEmitter` module. This module is available natively in Node.js, but when using this package for the browser, make sure to use a polyfill such as `events`.
16+
1317
## Contributing
1418

1519
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).

packages/message-manager/src/AbstractMessageManager.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import type { BaseConfig, BaseState } from '@metamask/base-controller';
22
import { BaseControllerV1 } from '@metamask/base-controller';
33
import type { ApprovalType } from '@metamask/controller-utils';
44
import type { Hex, Json } from '@metamask/utils';
5+
// This package purposefully relies on Node's EventEmitter module.
6+
// eslint-disable-next-line import/no-nodejs-modules
57
import { EventEmitter } from 'events';
68
import { v1 as random } from 'uuid';
79

packages/network-controller/src/NetworkController.ts

Lines changed: 42 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,11 @@ import { errorCodes } from '@metamask/rpc-errors';
1919
import { createEventEmitterProxy } from '@metamask/swappable-obj-proxy';
2020
import type { SwappableProxy } from '@metamask/swappable-obj-proxy';
2121
import type { Hex } from '@metamask/utils';
22-
import { isStrictHexString, hasProperty, isPlainObject } from '@metamask/utils';
23-
import { strict as assert } from 'assert';
22+
import { hasProperty, isPlainObject, isStrictHexString } from '@metamask/utils';
2423
import type { Draft } from 'immer';
2524
import type { Logger } from 'loglevel';
2625
import { createSelector } from 'reselect';
2726
import * as URI from 'uri-js';
28-
import { inspect } from 'util';
2927
import { v4 as uuidV4 } from 'uuid';
3028

3129
import { INFURA_BLOCKED_KEY, NetworkStatus } from './constants';
@@ -515,7 +513,7 @@ function getDefaultNetworkConfigurationsByChainId(): Record<
515513
>((obj, infuraNetworkType) => {
516514
const chainId = ChainId[infuraNetworkType];
517515
const rpcEndpointUrl =
518-
// False negative - this is a string.
516+
// This ESLint rule mistakenly produces an error.
519517
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
520518
`https://${infuraNetworkType}.infura.io/v3/{infuraProjectId}` as const;
521519

@@ -788,9 +786,9 @@ function validateNetworkControllerState(state: NetworkState) {
788786

789787
if (!networkClientIds.includes(state.selectedNetworkClientId)) {
790788
throw new Error(
791-
`NetworkController state is invalid: \`selectedNetworkClientId\` ${inspect(
792-
state.selectedNetworkClientId,
793-
)} does not refer to an RPC endpoint within a network configuration`,
789+
// This ESLint rule mistakenly produces an error.
790+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
791+
`NetworkController state is invalid: \`selectedNetworkClientId\` '${state.selectedNetworkClientId}' does not refer to an RPC endpoint within a network configuration`,
794792
);
795793
}
796794
}
@@ -1354,19 +1352,16 @@ export class NetworkController extends BaseController<
13541352
* removed in a future release
13551353
*/
13561354
async setProviderType(type: InfuraNetworkType) {
1357-
assert.notStrictEqual(
1358-
type,
1359-
NetworkType.rpc,
1360-
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
1361-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
1362-
`NetworkController - cannot call "setProviderType" with type "${NetworkType.rpc}". Use "setActiveNetwork"`,
1363-
);
1364-
assert.ok(
1365-
isInfuraNetworkType(type),
1366-
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
1367-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
1368-
`Unknown Infura provider type "${type}".`,
1369-
);
1355+
if ((type as unknown) === NetworkType.rpc) {
1356+
throw new Error(
1357+
// This ESLint rule mistakenly produces an error.
1358+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
1359+
`NetworkController - cannot call "setProviderType" with type "${NetworkType.rpc}". Use "setActiveNetwork"`,
1360+
);
1361+
}
1362+
if (!isInfuraNetworkType(type)) {
1363+
throw new Error(`Unknown Infura provider type "${String(type)}".`);
1364+
}
13701365

13711366
await this.setActiveNetwork(type);
13721367
}
@@ -1635,9 +1630,7 @@ export class NetworkController extends BaseController<
16351630

16361631
if (existingNetworkConfiguration === undefined) {
16371632
throw new Error(
1638-
`Could not update network: Cannot find network configuration for chain ${inspect(
1639-
chainId,
1640-
)}`,
1633+
`Could not update network: Cannot find network configuration for chain '${chainId}'`,
16411634
);
16421635
}
16431636

@@ -1802,7 +1795,7 @@ export class NetworkController extends BaseController<
18021795
})
18031796
) {
18041797
throw new Error(
1805-
// False negative - this is a string.
1798+
// This ESLint rule mistakenly produces an error.
18061799
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
18071800
`Could not update network: Cannot update RPC endpoints in such a way that the selected network '${this.state.selectedNetworkClientId}' would be removed without a replacement. Choose a different RPC endpoint as the selected network via the \`replacementSelectedRpcEndpointIndex\` option.`,
18081801
);
@@ -1899,7 +1892,7 @@ export class NetworkController extends BaseController<
18991892

19001893
if (existingNetworkConfiguration === undefined) {
19011894
throw new Error(
1902-
`Cannot find network configuration for chain ${inspect(chainId)}`,
1895+
`Cannot find network configuration for chain '${chainId}'`,
19031896
);
19041897
}
19051898

@@ -2031,9 +2024,7 @@ export class NetworkController extends BaseController<
20312024
!isSafeChainId(networkFields.chainId)
20322025
) {
20332026
throw new Error(
2034-
`${errorMessagePrefix}: Invalid \`chainId\` ${inspect(
2035-
networkFields.chainId,
2036-
)} (must start with "0x" and not exceed the maximum)`,
2027+
`${errorMessagePrefix}: Invalid \`chainId\` '${networkFields.chainId}' (must start with "0x" and not exceed the maximum)`,
20372028
);
20382029
}
20392030

@@ -2046,13 +2037,13 @@ export class NetworkController extends BaseController<
20462037
if (existingNetworkConfigurationViaChainId !== undefined) {
20472038
if (existingNetworkConfiguration === null) {
20482039
throw new Error(
2049-
// False negative - these are strings.
2040+
// This ESLint rule mistakenly produces an error.
20502041
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
20512042
`Could not add network for chain ${args.networkFields.chainId} as another network for that chain already exists ('${existingNetworkConfigurationViaChainId.name}')`,
20522043
);
20532044
} else {
20542045
throw new Error(
2055-
// False negative - these are strings.
2046+
// This ESLint rule mistakenly produces an error.
20562047
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
20572048
`Cannot move network from chain ${existingNetworkConfiguration.chainId} to ${networkFields.chainId} as another network for that chain already exists ('${existingNetworkConfigurationViaChainId.name}')`,
20582049
);
@@ -2082,9 +2073,9 @@ export class NetworkController extends BaseController<
20822073
for (const rpcEndpointFields of networkFields.rpcEndpoints) {
20832074
if (!isValidUrl(rpcEndpointFields.url)) {
20842075
throw new Error(
2085-
`${errorMessagePrefix}: An entry in \`rpcEndpoints\` has invalid URL ${inspect(
2086-
rpcEndpointFields.url,
2087-
)}`,
2076+
// This ESLint rule mistakenly produces an error.
2077+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
2078+
`${errorMessagePrefix}: An entry in \`rpcEndpoints\` has invalid URL '${rpcEndpointFields.url}'`,
20882079
);
20892080
}
20902081
const networkClientId =
@@ -2113,13 +2104,9 @@ export class NetworkController extends BaseController<
21132104
)
21142105
) {
21152106
throw new Error(
2116-
`${errorMessagePrefix}: RPC endpoint '${
2117-
// This is a string.
2118-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
2119-
rpcEndpointFields.url
2120-
}' refers to network client ${inspect(
2121-
networkClientId,
2122-
)} that does not exist`,
2107+
// This is a string.
2108+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
2109+
`${errorMessagePrefix}: RPC endpoint '${rpcEndpointFields.url}' refers to network client '${networkClientId}' that does not exist`,
21232110
);
21242111
}
21252112

@@ -2149,15 +2136,19 @@ export class NetworkController extends BaseController<
21492136
URI.equal(rpcEndpointFields.url, existingRpcEndpoint.url),
21502137
);
21512138
if (rpcEndpoint) {
2152-
throw new Error(
2153-
mode === 'update'
2154-
? // False negative - these are strings.
2155-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
2156-
`Could not update network to point to same RPC endpoint as existing network for chain ${networkConfiguration.chainId} ('${networkConfiguration.name}')`
2157-
: // False negative - these are strings.
2158-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
2159-
`Could not add network that points to same RPC endpoint as existing network for chain ${networkConfiguration.chainId} ('${networkConfiguration.name}')`,
2160-
);
2139+
if (mode === 'update') {
2140+
throw new Error(
2141+
// This ESLint rule mistakenly produces an error.
2142+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
2143+
`Could not update network to point to same RPC endpoint as existing network for chain ${networkConfiguration.chainId} ('${networkConfiguration.name}')`,
2144+
);
2145+
} else {
2146+
throw new Error(
2147+
// This ESLint rule mistakenly produces an error.
2148+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
2149+
`Could not add network that points to same RPC endpoint as existing network for chain ${networkConfiguration.chainId} ('${networkConfiguration.name}')`,
2150+
);
2151+
}
21612152
}
21622153
}
21632154
}
@@ -2561,7 +2552,7 @@ export class NetworkController extends BaseController<
25612552
/* istanbul ignore if */
25622553
if (!possibleAutoManagedNetworkClient) {
25632554
throw new Error(
2564-
`No Infura network client found with ID ${inspect(networkClientId)}`,
2555+
`No Infura network client found with ID '${networkClientId}'`,
25652556
);
25662557
}
25672558

@@ -2573,9 +2564,7 @@ export class NetworkController extends BaseController<
25732564
];
25742565

25752566
if (!possibleAutoManagedNetworkClient) {
2576-
throw new Error(
2577-
`No network client found with ID ${inspect(networkClientId)}`,
2578-
);
2567+
throw new Error(`No network client found with ID '${networkClientId}'`);
25792568
}
25802569

25812570
autoManagedNetworkClient = possibleAutoManagedNetworkClient;

packages/signature-controller/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ or
1010

1111
`npm install @metamask/signature-controller`
1212

13+
## Compatibility
14+
15+
This package relies implicitly upon the `EventEmitter` module. This module is available natively in Node.js, but when using this package for the browser, make sure to use a polyfill such as `events`.
16+
1317
## Contributing
1418

1519
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).

packages/signature-controller/src/SignatureController.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import {
2929
} from '@metamask/logging-controller';
3030
import type { NetworkControllerGetNetworkClientByIdAction } from '@metamask/network-controller';
3131
import type { Hex, Json } from '@metamask/utils';
32+
// This package purposefully relies on Node's EventEmitter module.
33+
// eslint-disable-next-line import/no-nodejs-modules
3234
import EventEmitter from 'events';
3335
import { v1 as random } from 'uuid';
3436

packages/transaction-controller/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ or
1010

1111
`npm install @metamask/transaction-controller`
1212

13+
## Compatibility
14+
15+
This package relies implicitly upon the `EventEmitter` module. This module is available natively in Node.js, but when using this package for the browser, make sure to use a polyfill such as `events`.
16+
1317
## Contributing
1418

1519
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).

packages/transaction-controller/src/TransactionController.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ import { errorCodes, rpcErrors, providerErrors } from '@metamask/rpc-errors';
4646
import type { Hex } from '@metamask/utils';
4747
import { add0x, hexToNumber } from '@metamask/utils';
4848
import { Mutex } from 'async-mutex';
49+
// This package purposefully relies on Node's EventEmitter module.
50+
// eslint-disable-next-line import/no-nodejs-modules
4951
import { EventEmitter } from 'events';
5052
import { cloneDeep, mapValues, merge, pickBy, sortBy } from 'lodash';
5153
import { v1 as random } from 'uuid';

packages/transaction-controller/src/helpers/GasFeePoller.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import type {
66
import type { NetworkClientId, Provider } from '@metamask/network-controller';
77
import type { Hex } from '@metamask/utils';
88
import { createModuleLogger } from '@metamask/utils';
9+
// This package purposefully relies on Node's EventEmitter module.
10+
// eslint-disable-next-line import/no-nodejs-modules
911
import EventEmitter from 'events';
1012

1113
import { projectLogger } from '../logger';

packages/transaction-controller/src/helpers/IncomingTransactionHelper.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import type { AccountsController } from '@metamask/accounts-controller';
22
import type { BlockTracker } from '@metamask/network-controller';
33
import type { Hex } from '@metamask/utils';
44
import { Mutex } from 'async-mutex';
5+
// This package purposefully relies on Node's EventEmitter module.
6+
// eslint-disable-next-line import/no-nodejs-modules
57
import EventEmitter from 'events';
68

79
import {

packages/transaction-controller/src/helpers/MethodDataHelper.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import type { NetworkClientId, Provider } from '@metamask/network-controller';
22
import { createModuleLogger } from '@metamask/utils';
33
import { Mutex } from 'async-mutex';
44
import { MethodRegistry } from 'eth-method-registry';
5+
// This package purposefully relies on Node's EventEmitter module.
6+
// eslint-disable-next-line import/no-nodejs-modules
57
import EventEmitter from 'events';
68

79
import { projectLogger } from '../logger';

packages/transaction-controller/src/helpers/PendingTransactionTracker.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import type {
44
BlockTracker,
55
NetworkClientId,
66
} from '@metamask/network-controller';
7+
// This package purposefully relies on Node's EventEmitter module.
8+
// eslint-disable-next-line import/no-nodejs-modules
79
import EventEmitter from 'events';
810
import { cloneDeep, merge } from 'lodash';
911

packages/user-operation-controller/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ or
1010

1111
`npm install @metamask/user-operation-controller`
1212

13+
## Compatibility
14+
15+
This package relies implicitly upon the `EventEmitter` module. This module is available natively in Node.js, but when using this package for the browser, make sure to use a polyfill such as `events`.
16+
1317
## Contributing
1418

1519
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).

packages/user-operation-controller/src/UserOperationController.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import {
2525
type TransactionType,
2626
} from '@metamask/transaction-controller';
2727
import { add0x } from '@metamask/utils';
28+
// This package purposefully relies on Node's EventEmitter module.
29+
// eslint-disable-next-line import/no-nodejs-modules
2830
import EventEmitter from 'events';
2931
import type { Patch } from 'immer';
3032
import { cloneDeep } from 'lodash';

packages/user-operation-controller/src/helpers/PendingUserOperationTracker.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import type {
77
} from '@metamask/network-controller';
88
import { BlockTrackerPollingControllerOnly } from '@metamask/polling-controller';
99
import { createModuleLogger, type Hex } from '@metamask/utils';
10+
// This package purposefully relies on Node's EventEmitter module.
11+
// eslint-disable-next-line import/no-nodejs-modules
1012
import EventEmitter from 'events';
1113

1214
import { projectLogger } from '../logger';

scripts/create-package/utils.test.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ jest.mock('fs', () => ({
1414
mkdir: jest.fn(),
1515
readFile: jest.fn(),
1616
writeFile: jest.fn(),
17+
stat: jest.fn(),
1718
},
1819
}));
1920

@@ -86,7 +87,9 @@ describe('create-package/utils', () => {
8687
nodeVersions: '>=18.0.0',
8788
};
8889

89-
(fs.existsSync as jest.Mock).mockReturnValueOnce(false);
90+
(fs.promises.stat as jest.Mock).mockResolvedValueOnce({
91+
isDirectory: () => false,
92+
});
9093

9194
(fsUtils.readAllFiles as jest.Mock).mockResolvedValueOnce({
9295
'src/index.ts': 'export default 42;',
@@ -167,7 +170,9 @@ describe('create-package/utils', () => {
167170
nodeVersions: '20.0.0',
168171
};
169172

170-
(fs.existsSync as jest.Mock).mockReturnValueOnce(true);
173+
(fs.promises.stat as jest.Mock).mockResolvedValueOnce({
174+
isDirectory: () => true,
175+
});
171176

172177
await expect(
173178
finalizeAndWriteData(packageData, monorepoFileData),

0 commit comments

Comments
 (0)