Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript migration #174

Merged
merged 28 commits into from
Mar 28, 2023
Merged

TypeScript migration #174

merged 28 commits into from
Mar 28, 2023

Conversation

mikesposito
Copy link
Member

@mikesposito mikesposito commented Mar 2, 2023

This PR converts the package from JavaScript to TypeScript, adding needed devDependencies and configurations to make it work. The linting pipeline has also been updated, bringing some changes to the code to make it compliant with the latest module template version.

  • Typed LedgerBridgeKeyring class
  • Typed LedgerBridgeKeyring class tests
  • Changed eslint config
  • Changed private methods to use sharp notation (changed also tests to not spy/mock private methods, see TypeScript migration #174 (comment))
  • Added prettier
  • Added typedoc
  • Added depcheck and related package.json scripts
  • Added Build step in circle-ci (migration from circle-ci to github actions to be done in a different PR)
  • Removed padLeftEven, normalize, toAscii as unused

Fixes #23
Fixes #164

src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
`${apiUrl}/api?module=account&action=txlist&address=${address}&tag=latest&page=1&offset=1`,
);
const parsedResponse = await response.json();
if (parsedResponse.status !== '0' && parsedResponse.result.length > 0) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Again, maybe out of the scope of the MR, but this if statement is a bit verbose. It could be safely refactored to something that, IMO, is more readable, like this:

    const parsedRes = await response.json();
    const resExists = parsedRes.status !== '0' && parsedRes.result?.length;

    return resExists;

At the very least, it could just be shortened to

return parsedResponse.status !== '0' && parsedResponse.result.length > 0


hdPath = hdPathString;

paths: Record<string, number> = {};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These Record's for this.paths and this.accountDetails could be made readonly via Readonly<Record<...>>, the only thing it has very slight chance of breakage depending on how the app is handled. Maybe best to allow these objects to be mutable

@mikesposito mikesposito marked this pull request as ready for review March 7, 2023 10:31
@mikesposito mikesposito requested a review from a team as a code owner March 7, 2023 10:31
return tmp.join('/');
}

private _sendMessage(
Copy link
Member Author

@mikesposito mikesposito Mar 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be changed to sharp notation too, but at this moment most of the tests spy this method

(See also #174 (comment))

Copy link
Member Author

@mikesposito mikesposito Mar 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can spy and stub the iframe content window postMessage method and call the respective callback, instead of stubbing sendMessage, taking for granted that whenever postMessage is called, a callback fn has been added to keyring.messageCallbacks, so we can manually call it passing the desired iframe message response:

        sandbox.on(
          keyring?.iframe?.contentWindow as Window,
          'postMessage',
          (msg) => {
            keyring.messageCallbacks[msg.messageId]?.({
              ...msg,
              success: true,
              payload: { foo: 'bar' },
            });
          },
        );

src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
Copy link

@mcmire mcmire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I skimmed over the JavaScript versions of ledger-bridge-keyring and the test file and compared with the TypeScript files and didn't see any glaring differences, but I'll do a more in-depth check later. In the meantime I've left some comments around the TypeScript implementation.

.prettierrc.js Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
'0x6772C4B1E841b295960Bb4662dceD9bb71726357',
'0x41bEAD6585eCA6c79B553Ca136f0DFA78A006899',
'0xf37559520757223264ee707d4e3fdfaa118db9bd',
] as const;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Do we need this array to be an exact length, and/or is a function expecting an argument with a type of, say, '0xf37559520757223264ee707d4e3fdfaa118db9bd'? If not, it seems like this wouldn't need to be as const.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove as const but then the type of fakeAccounts would be Array<string | undefined>, so we'll have to use an optional chain or a cast on each test where we use those, even if we know they are valid

src/ledger-bridge-keyring.test.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.test.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.test.ts Show resolved Hide resolved
src/ledger-bridge-keyring.test.ts Outdated Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
.eslintrc.js Outdated
},
],

rules: {
'import/no-nodejs-modules': 'off',
'no-restricted-globals': [
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. It's too bad that there's not another way to do this. That said, nice job for reusing the list already defined in @metamask/eslint-config — we should use that technique more often.

@Gudahtt Do you have any suggestions for how we could make this better?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use this package, if we want to require this only be used in-browser: https://github.com/MetaMask/eslint-config/tree/main/packages/browser

If we're anticipating this will be used in a Node.js context, with polyfills for each referenced browser global, than this approach is probably best. The alternative would be to eslint-ignore each individual violation (though maybe we could do that in a nice way by bringing them all to the top of the module and reassigning them to variables).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps using the browser lint package here would be a good idea. This keyring does assume a browser context.

Copy link
Member Author

@mikesposito mikesposito Mar 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some lines, we use the Buffer Node.js built-in without using any particular import to handle that, and indeed after using @metamask/eslint-config-browser those Buffer.from(...) are marked as error.

Adding import { Buffer } from 'buffer'; should do the trick but I'm unsure how it worked up until now. Is that just a TS requirement in your opinion?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, great question. I would have expected it to fail prior to adding the browser config.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry, I misunderstood. So that global is available in Node.js and injected by the extension build system, that's why it had worked before. It would be ideal to remove that from this package, but allowing that global as an exception or importing it directly should work instead for now (either should be equivalent)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good example of why this browser ESLint package is useful; it can highlight undocumented requirements like this. Now we know that this package assumes there is a Buffer polyfill present. We could document that requirement in the README so third-parties know about that requirement.

Copy link
Member Author

@mikesposito mikesposito Mar 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure it is the best approach: I suppose that we are still in a Node environment when running unit tests, so @metamask/eslint-config-browser is used just on *.ts files, and I added @metamask/eslint-config-nodejs to *.test.ts files.
Additionally, as in tests we still need a couple of types from the DOM, I assigned those types to other variables on top of the file and eslint-ignored them: we are able to use those types as we set DOM as typescript build target

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds reasonable to me!

src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
@mikesposito mikesposito force-pushed the feat/typescript-migration branch from e232f31 to fe77538 Compare March 21, 2023 14:08
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.ts Outdated Show resolved Hide resolved
Copy link
Member

@Gudahtt Gudahtt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Just a few minor suggestions

src/ledger-bridge-keyring.test.ts Outdated Show resolved Hide resolved
src/ledger-bridge-keyring.test.ts Outdated Show resolved Hide resolved
Gudahtt
Gudahtt previously approved these changes Mar 24, 2023
Copy link
Member

@Gudahtt Gudahtt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I think there might be a couple of pending suggestions but nothing major left

@socket-security
Copy link

New dependency changes detected. Learn more about Socket for GitHub ↗︎

👍 No new dependency issues detected in pull request

Bot Commands

To ignore an alert, reply with a comment starting with @SocketSecurity ignore followed by a space separated list of package-name@version specifiers. e.g. @SocketSecurity ignore [email protected] bar@* or ignore all packages with @SocketSecurity ignore-all

Pull request alert summary
Issue Status
Install scripts ✅ 0 issues
Native code ✅ 0 issues
Bin script shell injection ✅ 0 issues
Unresolved require ✅ 0 issues
Invalid package.json ✅ 0 issues
HTTP dependency ✅ 0 issues
Git dependency ✅ 0 issues
Potential typo squat ✅ 0 issues
Known Malware ✅ 0 issues
Telemetry ✅ 0 issues
Protestware/Troll package ✅ 0 issues

📊 Modified Dependency Overview:

➕ Added Package Capability Access +/- Transitive Count Publisher
@types/[email protected] None +1 types
@metamask/[email protected] None +62 metamaskbot
@metamask/[email protected] None +3 metamaskbot
@metamask/[email protected] None +58 metamaskbot
@types/[email protected] None +1 types
[email protected] filesystem +0 typescript-bot
@metamask/[email protected] None +81 metamaskbot
@types/[email protected] None +1 types
[email protected] filesystem +48 mysticatea
@metamask/[email protected] None +61 metamaskbot
@types/[email protected] None +1 types
[email protected] filesystem +41 rumpl
[email protected] None +41 matzkoh
[email protected] filesystem, shell, environment +18 cspotcode
@types/[email protected] None +0 types
@types/[email protected] None +0 types
[email protected] None +46 lydell
[email protected] None +48 jounqin
[email protected] None +52 gajus
@typescript-eslint/[email protected] None +62 jameshenry
@types/[email protected] None +0 types
@typescript-eslint/[email protected] None +68 jameshenry
[email protected] filesystem, shell, environment +9 typedoc-bot
@ledgerhq/[email protected] None +14 sergii-shkolin
⬆️ Updated Package Version Diff Capability Access +/- Transitive Count Publisher
@metamask/[email protected] 3.2.0...11.1.0 None +57/-0 metamaskbot
[email protected] 6.3.0...10.1.0 None +49/-54 lo1tuma
[email protected] 6.8.0...8.36.0 filesystem, environment +45/-52 eslintbot

🚮 Removed packages: [email protected], [email protected]

@mikesposito mikesposito merged commit 875abfd into main Mar 28, 2023
@mikesposito mikesposito deleted the feat/typescript-migration branch March 28, 2023 13:15
This was referenced Jun 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bring linting pipeline in sync with module template Migrate to TypeScript
4 participants