Skip to content

Commit

Permalink
♻️ Migrate cli to ESM (#926)
Browse files Browse the repository at this point in the history
* 🔧 Update `engines.node` in package.json
* ✨ Add `module` type to package.json
* ⬆️ Bump outdated dependencies
* ♻️ Migrate to ESModules
* ✅ Fix jest config
* ✅ Fix tests in ESM (#925)
* 🔧 Use babel-plugin-module-extension-resolver`
* 🐛 Migrate from require to readFileSync.
* ✅ Import mockProcessExit from jest-mock-process.
* ✅ Use dynamic imports instead of require.
* ♻️ Extract `getFile` function for configuration vault

Co-authored-by: Aadit M Shah <aaditmshah@aadit.codes>
  • Loading branch information
carloscuesta and aaditmshah committed Sep 29, 2022
1 parent 2782bd6 commit b8baee0
Show file tree
Hide file tree
Showing 20 changed files with 1,340 additions and 1,261 deletions.
30 changes: 30 additions & 0 deletions babel.config.json
@@ -0,0 +1,30 @@
{
"presets": [
"@babel/preset-flow"
],
"plugins": [
[
"module-resolver",
{
"alias": {
"@utils": "./src/utils",
"@commands": "./src/commands",
"@constants": "./src/constants"
}
}
],
"@babel/plugin-syntax-import-assertions",
"module-extension-resolver"
],
"env": {
"test": {
"presets": [
"@babel/preset-env",
"@babel/preset-flow"
],
"plugins": [
"babel-plugin-transform-import-meta"
]
}
}
}
50 changes: 16 additions & 34 deletions package.json
@@ -1,9 +1,10 @@
{
"name": "gitmoji-cli",
"version": "6.3.0",
"type": "module",
"description": "A gitmoji client for using emojis on commit messages.",
"engines": {
"node": ">=14"
"node": ">=14.16"
},
"bin": {
"gitmoji": "lib/cli.js"
Expand Down Expand Up @@ -43,26 +44,29 @@
},
"homepage": "https://github.com/carloscuesta/gitmoji-cli#readme",
"dependencies": {
"chalk": "4.1.0",
"chalk": "^5.0.1",
"conf": "10.2.0",
"execa": "5.1.1",
"execa": "^6.1.0",
"fuse.js": "6.6.2",
"inquirer": "8.2.4",
"inquirer": "8.x",
"inquirer-autocomplete-prompt": "2.0.0",
"meow": "9.0.0",
"node-fetch": "2.6.7",
"ora": "5.4.1",
"path-exists": "4.0.0",
"meow": "^10.1.3",
"node-fetch": "^3.2.10",
"ora": "^6.1.2",
"path-exists": "^5.0.0",
"proxy-agent": "5.0.0",
"update-notifier": "5.1.0",
"update-notifier": "^6.0.2",
"validator": "^13.7.0"
},
"devDependencies": {
"@babel/cli": "7.18.10",
"@babel/core": "7.19.1",
"@babel/plugin-syntax-import-assertions": "^7.18.6",
"@babel/preset-env": "7.19.1",
"@babel/preset-flow": "7.18.6",
"babel-plugin-module-extension-resolver": "^1.0.0-rc.2",
"babel-plugin-module-resolver": "^4.1.0",
"babel-plugin-transform-import-meta": "^2.2.0",
"codecov": "3.8.3",
"flow-bin": "^0.187.0",
"husky": "8.0.1",
Expand All @@ -73,31 +77,6 @@
"pkg": "5.8.0",
"prettier": "2.7.1"
},
"babel": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "12"
}
}
],
"@babel/preset-flow"
],
"plugins": [
[
"module-resolver",
{
"alias": {
"@utils": "./src/utils",
"@commands": "./src/commands",
"@constants": "./src/constants"
}
}
]
]
},
"jest": {
"coverageDirectory": "./coverage/",
"collectCoverage": true,
Expand All @@ -110,7 +89,10 @@
"setupFiles": [
"./test/setupTests.js"
],
"transformIgnorePatterns": [],
"moduleNameMapper": {
"^#ansi-styles$": "<rootDir>/node_modules/chalk/source/vendor/ansi-styles/index.js",
"^#supports-color$": "<rootDir>/node_modules/chalk/source/vendor/supports-color/index.js",
"@utils/(.*)$": "<rootDir>/src/utils/$1",
"@commands/(.*)$": "<rootDir>/src/commands/$1",
"@constants/(.*)$": "<rootDir>/src/constants/$1"
Expand Down
11 changes: 8 additions & 3 deletions src/cli.js
Expand Up @@ -2,13 +2,17 @@
// @flow
import meow from 'meow'
import updateNotifier from 'update-notifier'
import { readFileSync } from 'fs'

import pkg from '../package.json'
import commands from './commands'
import FLAGS from '@constants/flags'
import findGitmojiCommand from '@utils/findGitmojiCommand'
import commands from './commands'

const packageJson: Object = readFileSync(
new URL('../package.json', import.meta.url)
)

updateNotifier({ pkg }).notify({ isGlobal: true })
updateNotifier({ pkg: JSON.parse(packageJson) }).notify({ isGlobal: true })

const cli = meow(
`
Expand All @@ -28,6 +32,7 @@ const cli = meow(
$ gitmoji bug linter -s
`,
{
importMeta: { url: import.meta.url },
flags: {
[FLAGS.COMMIT]: { type: 'boolean', alias: 'c' },
[FLAGS.CONFIG]: { type: 'boolean', alias: 'g' },
Expand Down
5 changes: 3 additions & 2 deletions src/commands/commit/prompts.js
@@ -1,15 +1,16 @@
// @flow
import inquirer from 'inquirer'
import inquirerAutocompletePrompt from 'inquirer-autocomplete-prompt'

import configurationVault from '@utils/configurationVault'
import filterGitmojis from '@utils/filterGitmojis'
import getDefaultCommitContent from '@utils/getDefaultCommitContent'
import { type CommitOptions } from './index'
import { type CommitOptions } from '.'
import guard from './guard'

const TITLE_MAX_LENGTH_COUNT: number = 48

inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'))
inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt)

export type Gitmoji = {
code: string,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/commit/withClient/index.js
@@ -1,5 +1,5 @@
// @flow
import execa from 'execa'
import { execa } from 'execa'
import fs from 'fs'
import chalk from 'chalk'

Expand Down
2 changes: 1 addition & 1 deletion src/commands/commit/withHook/index.js
@@ -1,5 +1,5 @@
// @flow
import execa from 'execa'
import { execa } from 'execa'
import fs from 'fs'

import { type Answers } from '../prompts'
Expand Down
2 changes: 1 addition & 1 deletion src/commands/config/guard.js
@@ -1,5 +1,5 @@
import chalk from 'chalk'
import isURL from 'validator/lib/isURL'
import isURL from 'validator/lib/isURL.js'

const errors = {
url: chalk.red('Enter a valid API URL')
Expand Down
19 changes: 14 additions & 5 deletions src/utils/configurationVault/getConfiguration.js
@@ -1,6 +1,7 @@
import Conf from 'conf'
import { cwd } from 'process'
import pathExists from 'path-exists'
import { readFileSync } from 'fs'
import { pathExistsSync } from 'path-exists'

import { CONFIG, EMOJI_COMMIT_FORMATS } from '@constants/configuration'

Expand All @@ -23,19 +24,27 @@ const LOCAL_CONFIGURATION: typeof Conf = new Conf({
}
})

const getFile = (path: string): Buffer | void => {
try {
return JSON.parse(readFileSync(path))
} catch (error) {
return
}
}

const getConfiguration = (): { get: Function, set: Function } => {
const loadConfig = (): {
[$Values<typeof CONFIG>]: string | boolean
} => {
const packageJson = `${cwd()}/package.json`
const configurationFile = `${cwd()}/.gitmojirc.json`

if (pathExists.sync(packageJson) && require(packageJson)?.gitmoji) {
return require(packageJson).gitmoji
if (pathExistsSync(packageJson) && getFile(packageJson)?.gitmoji) {
return getFile(packageJson)?.gitmoji
}

if (pathExists.sync(configurationFile) && require(configurationFile)) {
return require(configurationFile)
if (pathExistsSync(configurationFile) && getFile(configurationFile)) {
return getFile(configurationFile)
}

return LOCAL_CONFIGURATION.store
Expand Down
6 changes: 3 additions & 3 deletions src/utils/emojisCache.js
Expand Up @@ -2,7 +2,7 @@
import fs from 'fs'
import os from 'os'
import path from 'path'
import pathExists from 'path-exists'
import { pathExistsSync } from 'path-exists'

export const GITMOJI_CACHE: Object = {
FOLDER: '.gitmoji',
Expand All @@ -16,7 +16,7 @@ export const CACHE_PATH: string = path.join(
)

const createEmojis = (emojis: Array<Object>): void => {
if (!pathExists.sync(path.dirname(CACHE_PATH))) {
if (!pathExistsSync(path.dirname(CACHE_PATH))) {
fs.mkdirSync(path.dirname(CACHE_PATH))
}

Expand All @@ -31,7 +31,7 @@ const getEmojis = (): Array<Object> => {
}
}

const isAvailable = (): boolean => pathExists.sync(CACHE_PATH)
const isAvailable = (): boolean => pathExistsSync(CACHE_PATH)

export default {
createEmojis,
Expand Down
2 changes: 1 addition & 1 deletion src/utils/getAbsoluteHooksPath.js
@@ -1,5 +1,5 @@
// @flow
import execa from 'execa'
import { execa } from 'execa'
import path from 'path'

const getAbsoluteHooksPath = async (hookName: string): Promise<string> => {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/getDefaultCommitContent.js
@@ -1,7 +1,7 @@
// @flow
import fs from 'fs'

import { type CommitOptions } from '@commands/commit/index'
import { type CommitOptions } from '@commands/commit'
import COMMIT_MODES from '@constants/commit'

const COMMIT_FILE_PATH_INDEX = 3
Expand Down
1 change: 1 addition & 0 deletions test/__snapshots__/cli.spec.js.snap
Expand Up @@ -58,6 +58,7 @@ exports[`cli should match meow with cli information 1`] = `
"type": "boolean",
},
},
"importMeta": "import.meta.url",
},
],
]
Expand Down
2 changes: 2 additions & 0 deletions test/cli.spec.js
Expand Up @@ -16,6 +16,8 @@ describe('cli', () => {
})

it('should match meow with cli information', () => {
meow.mock.calls[0][1].importMeta = 'import.meta.url'

expect(meow.mock.calls).toMatchSnapshot()
})

Expand Down
17 changes: 8 additions & 9 deletions test/commands/commit.spec.js
@@ -1,8 +1,8 @@
import inquirer from 'inquirer'
import execa from 'execa'
import { execa } from 'execa'
import fs from 'fs'
import chalk from 'chalk'
const mockProcess = require('jest-mock-process')
import { mockProcessExit } from 'jest-mock-process'

import configurationVault from '@utils/configurationVault'
import getDefaultCommitContent from '@utils/getDefaultCommitContent'
Expand Down Expand Up @@ -162,7 +162,7 @@ describe('commit command', () => {
Promise.resolve(stubs.clientCommitAnswers)
)
getEmojis.mockResolvedValue(stubs.gitmojis)
mockProcess.mockProcessExit()
mockProcessExit()
process.argv[3] = stubs.argv
process.argv[COMMIT_MESSAGE_SOURCE] = undefined
getDefaultCommitContent.mockReturnValueOnce(
Expand Down Expand Up @@ -192,7 +192,7 @@ describe('commit command', () => {
Promise.resolve(stubs.clientCommitAnswersWithScope)
)
getEmojis.mockResolvedValue(stubs.gitmojis)
mockProcess.mockProcessExit()
mockProcessExit()
process.argv[3] = stubs.argv
process.argv[COMMIT_MESSAGE_SOURCE] = stubs.commitSource
getDefaultCommitContent.mockReturnValueOnce(
Expand Down Expand Up @@ -223,7 +223,7 @@ describe('commit command', () => {
Simulation needed because if we just mock process exit, then the code execution resume in the test.
*/
process.argv[COMMIT_MESSAGE_SOURCE] = stubs.commitSource
mockProcess.mockProcessExit(new Error('ProcessExit0'))
mockProcessExit(new Error('ProcessExit0'))
execa.mockReturnValueOnce(Promise.resolve(stubs.gitAbsoluteDir))
// mock that we found one of the rebase trigger (file existence in .git)
fs.existsSync.mockReturnValueOnce(true)
Expand All @@ -245,7 +245,7 @@ describe('commit command', () => {
when the hook mode detect that the user is rebasing. (Simulated to not kill the tests)
Simulation needed because if we just mock process exit, then the code execution resume in the test.
*/
mockProcess.mockProcessExit(new Error('ProcessExit0'))
mockProcessExit(new Error('ProcessExit0'))
execa.mockReturnValueOnce(Promise.resolve(stubs.gitAbsoluteDir))
// mock that we are amending
process.argv[COMMIT_MESSAGE_SOURCE] = 'commit sha123'
Expand Down Expand Up @@ -282,7 +282,7 @@ describe('commit command', () => {
getEmojis.mockResolvedValue(stubs.gitmojis)

// Use an exception to suspend code execution to simulate process.exit
mockProcess.mockProcessExit(new Error('SIGINT'))
mockProcessExit(new Error('SIGINT'))
process.argv[3] = stubs.argv
process.argv[COMMIT_MESSAGE_SOURCE] = stubs.commitSource

Expand All @@ -303,7 +303,7 @@ describe('commit command', () => {

describe('with git auto merge trigger by git pull', () => {
it('should cancel the hook', async () => {
mockProcess.mockProcessExit(new Error('ProcessExit0'))
mockProcessExit(new Error('ProcessExit0'))
execa.mockReturnValueOnce(Promise.resolve(stubs.gitAbsoluteDir))
// mock that we are merging
process.argv[3] = '.git/MERGE_MSG'
Expand All @@ -318,7 +318,6 @@ describe('commit command', () => {
expect(process.exit).toHaveBeenCalledWith(0)
})
})

})

describe('guard', () => {
Expand Down
3 changes: 3 additions & 0 deletions test/setupTests.js
Expand Up @@ -3,6 +3,9 @@ import fetchMock from 'jest-fetch-mock'
jest.setMock('node-fetch', fetchMock)
jest.mock('path-exists')
jest.mock('fs')
jest
.requireMock('fs')
.readFileSync.mockImplementation(jest.requireActual('fs').readFileSync)
jest.mock('ora', () =>
jest.fn().mockReturnValue({
start: jest.fn(function () {
Expand Down

0 comments on commit b8baee0

Please sign in to comment.