Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .depcheckrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
"@lavamoat/preinstall-always-fail",
"@metamask/auto-changelog",
"@types/*",
"@yarnpkg/core",
"@yarnpkg/cli",
"@yarnpkg/core",
"@yarnpkg/fslib",
"clipanion",
"prettier-plugin-packagejson",
"rimraf",
"ts-node",
"typedoc"
]
Expand Down
File renamed without changes.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- **BREAKING:** The package is now ESM only ([#323](https://github.com/MetaMask/utils/pull/323))
- The CommonJS build is gone. `require('@metamask/utils')` now fails with `ERR_REQUIRE_ESM`; use `import` instead.
- `main` and `module` are removed. Both `.` and `./node` resolve through `exports` to a single `./dist/*.js` with `./dist/*.d.ts` types.
- Consumers already using `import` are unaffected.
- Bump `@ethereumjs/tx` from `^4.2.0` to `^5.4.0` ([#321](https://github.com/MetaMask/utils/pull/321))
- The deprecated `Keyring.signTransaction` now returns `LegacyTxData` rather than `TxData`. These describe the same shape: `@ethereumjs/tx@5` repurposed the name `TxData` for a map keyed by transaction type and renamed the old meaning to `LegacyTxData`. Implementations do not need changing.
- Bump `@metamask/scure-bip39` from `^2.0.3` to `^2.1.1` ([#311](https://github.com/MetaMask/utils/pull/311))
Expand Down
26 changes: 14 additions & 12 deletions constraints.pro
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,20 @@ gen_enforced_field(WorkspaceCwd, 'repository.url', 'https://github.com/MetaMask/
% The license for the package must be specified.
gen_enforced_field(WorkspaceCwd, 'license').

% The type definitions entrypoint the package must be `./dist/index.d.cts`.
gen_enforced_field(WorkspaceCwd, 'types', './dist/index.d.cts').

% The entrypoint for the package must be `./dist/index.cjs`.
gen_enforced_field(WorkspaceCwd, 'main', './dist/index.cjs').
gen_enforced_field(WorkspaceCwd, 'exports["."].require.types', './dist/index.d.cts').
gen_enforced_field(WorkspaceCwd, 'exports["."].require.default', './dist/index.cjs').

% The module entrypoint for the package must be `./dist/index.mjs`.
gen_enforced_field(WorkspaceCwd, 'module', './dist/index.mjs').
gen_enforced_field(WorkspaceCwd, 'exports["."].import.types', './dist/index.d.mts').
gen_enforced_field(WorkspaceCwd, 'exports["."].import.default', './dist/index.mjs').
% The package is ESM only, so there is no `main` or `module` entrypoint and no
% `require` condition. A single build serves both.
gen_enforced_field(WorkspaceCwd, 'type', 'module').

% The type definitions entrypoint for the package must be `./dist/index.d.ts`.
gen_enforced_field(WorkspaceCwd, 'types', './dist/index.d.ts').

% The entrypoint for the package must be `./dist/index.js`.
gen_enforced_field(WorkspaceCwd, 'exports["."].types', './dist/index.d.ts').
gen_enforced_field(WorkspaceCwd, 'exports["."].default', './dist/index.js').

% The Node specific entrypoint must be `./dist/node.js`.
gen_enforced_field(WorkspaceCwd, 'exports["./node"].types', './dist/node.d.ts').
gen_enforced_field(WorkspaceCwd, 'exports["./node"].default', './dist/node.js').

gen_enforced_field(WorkspaceCwd, 'exports["./package.json"]', './package.json').

Expand Down
28 changes: 28 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import base, { createConfig } from '@metamask/eslint-config';
import jest from '@metamask/eslint-config-jest';
import nodejs from '@metamask/eslint-config-nodejs';
import typescript from '@metamask/eslint-config-typescript';
import nodePlugin from 'eslint-plugin-n';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

Expand Down Expand Up @@ -85,6 +86,33 @@ const config = createConfig([
'import-x/ignore': ['uuid'],
},
},
{
// The package is ESM, so relative imports carry explicit `.js` specifiers.
// These are the same three rules core configures for that, verbatim.
// `import-x/extensions` does not support using ".js" for TypeScript
// files(?), so we load the `n` plugin and use `n/file-extension-in-import`
// instead.
plugins: { n: nodePlugin },

rules: {
'n/file-extension-in-import': ['error', 'always'],
'import-x/extensions': [
'error',
{
js: 'ignorePackages',
ts: 'never',
tsx: 'never',
json: 'always',
},
],
'import-x/no-useless-path-segments': [
'error',
{
noUselessIndex: false,
},
],
},
},
{
files: ['**/*.test-d.ts'],
rules: {
Expand Down
23 changes: 21 additions & 2 deletions jest.config.js → jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,12 @@ module.exports = {
// ],

// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
// moduleNameMapper: {},
// The sources are ESM and so use explicit `.js` specifiers on relative
// imports. The tests compile to CommonJS (see `transform` below), where those
// files are still `.ts`, so the extension is stripped back off here.
moduleNameMapper: {
'^(\\.{1,2}/.+)\\.js$': '$1',
},

// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
// modulePathIgnorePatterns: [],
Expand Down Expand Up @@ -187,7 +192,21 @@ module.exports = {
// timers: "real",

// A map from regular expressions to paths to transformers
// transform: undefined,
// The package is ESM, but Jest runs the tests as CommonJS. Overriding the
// module settings here compiles the sources to CommonJS for tests without
// affecting the published build.
transform: {
'^.+\\.tsx?$': [
'ts-jest',
{
tsconfig: {
module: 'CommonJS',
moduleResolution: 'Node',
verbatimModuleSyntax: false,
},
},
],
},

// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [
Expand Down
33 changes: 11 additions & 22 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,17 @@
"files": [
"dist"
],
"type": "module",
"sideEffects": false,
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.cts",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./node": {
"import": {
"types": "./dist/node.d.mts",
"default": "./dist/node.mjs"
},
"require": {
"types": "./dist/node.d.cts",
"default": "./dist/node.cjs"
}
"types": "./dist/node.d.ts",
"default": "./dist/node.js"
},
"./package.json": "./package.json"
},
Expand All @@ -46,8 +33,10 @@
"registry": "https://registry.npmjs.org/"
},
"scripts": {
"build": "ts-bridge --project tsconfig.build.json --clean",
"build": "tsc --project tsconfig.build.json",
"build:clean": "yarn build:only-clean && yarn build",
"build:docs": "typedoc",
"build:only-clean": "rimraf ./dist ./tsconfig.build.tsbuildinfo",
"lint": "yarn lint:eslint && yarn lint:constraints && yarn lint:misc --check && yarn lint:dependencies --check && yarn lint:changelog",
"lint:changelog": "auto-changelog validate --prettier",
"lint:constraints": "yarn constraints",
Expand All @@ -57,7 +46,7 @@
"lint:misc": "oxfmt --ignore-path .gitignore",
"prepack": "./scripts/prepack.sh",
"test": "yarn test:source && yarn test:types",
"test:source": "jest && jest-it-up",
"test:source": "jest && jest-it-up --config jest.config.cjs",
"test:types": "tsd --files 'src/*.test-d.ts'",
"test:watch": "jest --watch"
},
Expand All @@ -83,7 +72,6 @@
"@metamask/eslint-config-jest": "^15.0.0",
"@metamask/eslint-config-nodejs": "^15.0.0",
"@metamask/eslint-config-typescript": "^15.0.0",
"@ts-bridge/cli": "^0.6.4",
"@types/jest": "^30.0.0",
"@types/jest-when": "^3.5.3",
"@types/node": "~18.18.14",
Expand All @@ -104,6 +92,7 @@
"jest-when": "^3.7.0",
"oxfmt": "^0.44.0",
"prettier": "^3.3.3",
"rimraf": "^5.0.5",
"stdio-mock": "^1.2.0",
"ts-jest": "^29.4.11",
"ts-node": "^10.7.0",
Expand Down
2 changes: 1 addition & 1 deletion src/__fixtures__/coercions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Hex } from '../hex';
import type { Hex } from '../hex.js';

export const POSITIVE_INTEGERS = [0, 1, 10, 100, 1000, 123456789, 2147483647];
export const NEGATIVE_INTEGERS = [
Expand Down
10 changes: 5 additions & 5 deletions src/__fixtures__/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export * from './bytes';
export * from './caip-types';
export * from './coercions';
export * from './json';
export * from './numbers';
export * from './bytes.js';
export * from './caip-types.js';
export * from './coercions.js';
export * from './json.js';
export * from './numbers.js';
2 changes: 1 addition & 1 deletion src/assert.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
assertExhaustive,
AssertionError,
assertStruct,
} from './assert';
} from './assert.js';

jest.mock('@metamask/superstruct', () => ({
...jest.requireActual('@metamask/superstruct'),
Expand Down
2 changes: 1 addition & 1 deletion src/assert.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Struct } from '@metamask/superstruct';
import { assert as assertSuperstruct } from '@metamask/superstruct';

import { getErrorMessage } from './errors';
import { getErrorMessage } from './errors.js';

export type AssertionErrorConstructor =
| (new (args: { message: string }) => Error)
Expand Down
4 changes: 2 additions & 2 deletions src/base64.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { is, size, string } from '@metamask/superstruct';

import type { Base64Options } from './base64';
import { base64 } from './base64';
import type { Base64Options } from './base64.js';
import { base64 } from './base64.js';

describe('base64', () => {
it.each([
Expand Down
2 changes: 1 addition & 1 deletion src/base64.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Struct } from '@metamask/superstruct';
import { pattern } from '@metamask/superstruct';

import { assert } from './assert';
import { assert } from './assert.js';

export type Base64Options = {
/**
Expand Down
4 changes: 2 additions & 2 deletions src/bytes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
TWOS_COMPLEMENT_BYTES_FIXTURES,
UPPER_CASE_HEX_FIXTURES,
UTF_8_BYTES_FIXTURES,
} from './__fixtures__';
} from './__fixtures__/index.js';
import {
areUint8ArraysEqual,
assertIsBytes,
Expand All @@ -25,7 +25,7 @@ import {
signedBigIntToBytes,
stringToBytes,
valueToBytes,
} from './bytes';
} from './bytes.js';

describe('isBytes', () => {
it('returns true for a Node.js Buffer', () => {
Expand Down
6 changes: 3 additions & 3 deletions src/bytes.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { base64 } from '@scure/base';

import { assert } from './assert';
import type { Hex } from './hex';
import { add0x, assertIsHexString, remove0x } from './hex';
import { assert } from './assert.js';
import type { Hex } from './hex.js';
import { add0x, assertIsHexString, remove0x } from './hex.js';

// '0'.charCodeAt(0) === 48
const HEX_MINIMUM_NUMBER_CHARACTER = 48;
Expand Down
2 changes: 1 addition & 1 deletion src/caip-types.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
CaipChainId,
CaipNamespace,
CaipReference,
} from '.';
} from './index.js';

const embeddedString = 'test';

Expand Down
4 changes: 2 additions & 2 deletions src/caip-types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
CAIP_CHAIN_ID_FIXTURES,
CAIP_NAMESPACE_FIXTURES,
CAIP_REFERENCE_FIXTURES,
} from './__fixtures__';
} from './__fixtures__/index.js';
import {
CAIP_ACCOUNT_ADDRESS_REGEX,
CAIP_ASSET_NAMESPACE_REGEX,
Expand All @@ -34,7 +34,7 @@ import {
toCaipAssetId,
toCaipAssetType,
toCaipChainId,
} from './caip-types';
} from './caip-types.js';

describe('isCaipChainId', () => {
it.each(CAIP_CHAIN_ID_FIXTURES)(
Expand Down
2 changes: 1 addition & 1 deletion src/caip-types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Infer } from '@metamask/superstruct';

import { definePattern } from './superstruct';
import { definePattern } from './superstruct.js';

export const CAIP_CHAIN_ID_REGEX =
/^(?<namespace>[-a-z0-9]{3,8}):(?<reference>[-_a-zA-Z0-9]{1,32})$/u;
Expand Down
2 changes: 1 addition & 1 deletion src/checksum.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { is } from '@metamask/superstruct';

import { ChecksumStruct } from './checksum';
import { ChecksumStruct } from './checksum.js';

describe('ChecksumStruct', () => {
it('validates valid checksum', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/checksum.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { size, string } from '@metamask/superstruct';

import { base64 } from './base64';
import { base64 } from './base64.js';

export const ChecksumStruct = size(
base64(string(), { paddingRequired: true }),
Expand Down
13 changes: 9 additions & 4 deletions src/coercers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import {
HEX_STRINGS,
NEGATIVE_INTEGERS,
POSITIVE_INTEGERS,
} from './__fixtures__';
import { bytesToHex, hexToBytes } from './bytes';
import { createBigInt, createBytes, createHex, createNumber } from './coercers';
import { add0x } from './hex';
} from './__fixtures__/index.js';
import { bytesToHex, hexToBytes } from './bytes.js';
import {
createBigInt,
createBytes,
createHex,
createNumber,
} from './coercers.js';
import { add0x } from './hex.js';

describe('createNumber', () => {
it.each(POSITIVE_INTEGERS)(
Expand Down
8 changes: 4 additions & 4 deletions src/coercers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import {
union,
} from '@metamask/superstruct';

import { assert } from './assert';
import { bytesToHex, hexToBytes } from './bytes';
import type { Hex } from './hex';
import { StrictHexStruct } from './hex';
import { assert } from './assert.js';
import { bytesToHex, hexToBytes } from './bytes.js';
import type { Hex } from './hex.js';
import { StrictHexStruct } from './hex.js';

const NumberLikeStruct = union([number(), bigint(), string(), StrictHexStruct]);
const NumberCoercer = coerce(number(), NumberLikeStruct, Number);
Expand Down
2 changes: 1 addition & 1 deletion src/collections.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FrozenMap, FrozenSet } from './collections';
import { FrozenMap, FrozenSet } from './collections.js';

describe('FrozenMap', () => {
describe('immutability', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
isErrorWithMessage,
isErrorWithStack,
wrapError,
} from './errors';
} from './errors.js';

describe('isErrorWithCode', () => {
it('returns true if given an object that includes a "code" property', () => {
Expand Down
Loading
Loading