Skip to content

Commit

Permalink
refactor: Migrate the whole project from cjs to esm (#137)
Browse files Browse the repository at this point in the history
  • Loading branch information
afc163 authored Sep 24, 2024
1 parent f061005 commit 78d22d3
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 89 deletions.
9 changes: 8 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,19 @@ on:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16, 18, 20]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- uses: oven-sh/setup-bun@v2
- run: bun i
- run: bun run lint
- run: bun run coverage
- uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
token: ${{ secrets.CODECOV_TOKEN }}
18 changes: 10 additions & 8 deletions bin/fanyi.js → bin/fanyi.mjs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#!/usr/bin/env -S node --no-deprecation

const { Command } = require('commander');
const chalk = require('chalk');
const updateNotifier = require('update-notifier');
const pkg = require('../package.json');
const config = require('../lib/config');
const { searchList } = require('../lib/searchHistory');
import { readFile } from 'node:fs/promises';
import chalk from 'chalk';
import { Command } from 'commander';
import updateNotifier from 'update-notifier';
import config from '../lib/config.mjs';
import { searchList } from '../lib/searchHistory.mjs';

const pkg = JSON.parse(await readFile(new URL('../package.json', import.meta.url)));

updateNotifier({ pkg }).notify();
const program = new Command();
Expand Down Expand Up @@ -82,6 +84,6 @@ if (!process.argv.slice(2).length) {
async function runFY(options = {}) {
const defaultOptions = await config.load();
const mergedOptions = { ...defaultOptions, ...options };
const fanyi = require('..');
fanyi(program.args.join(' '), mergedOptions);
const fanyi = await import('../index.mjs');
fanyi.default(program.args.join(' '), mergedOptions);
}
Binary file modified bun.lockb
Binary file not shown.
16 changes: 8 additions & 8 deletions index.js → index.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const { Groq } = require('groq-sdk');
const print = require('./lib/print');
const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args));
const { XMLParser } = require('fast-xml-parser');
const ora = require('ora');
const gradient = require('gradient-string');
import { XMLParser } from 'fast-xml-parser';
import gradient from 'gradient-string';
import { Groq } from 'groq-sdk';
import fetch from 'node-fetch';
import ora from 'ora';
import { printIciba } from './lib/iciba.mjs';

const gradients = [
'cristal',
Expand All @@ -21,7 +21,7 @@ const gradients = [
'rainbow',
];

module.exports = async (word, options) => {
export default async (word, options) => {
console.log('');
const { iciba, groq, GROQ_API_KEY } = options;
const endcodedWord = encodeURIComponent(word);
Expand All @@ -37,7 +37,7 @@ module.exports = async (word, options) => {
const parser = new XMLParser();
const result = parser.parse(xml);
spinner.stop();
print.iciba(result.dict, options);
printIciba(result.dict, options);
} catch (error) {
spinner.fail('访问 iciba 失败,请检查网络');
}
Expand Down
27 changes: 13 additions & 14 deletions lib/config.js → lib/config.mjs
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
const homedir = process.env.HOME || require('node:os').homedir();
const path = require('node:path');
const fs = require('node:fs');
const chalk = require('chalk');
const configDir = path.resolve(homedir, '.config', 'fanyi');
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
import { homedir } from 'node:os';
import path from 'node:path';
import { Chalk } from 'chalk';

const configDir = path.resolve(homedir(), '.config', 'fanyi');
const configPath = path.resolve(configDir, '.fanyirc');

// 初始化一个带颜色的 chalk 实例
const chalkInstance = new chalk.Instance({ level: 3 });
const chalk = new Chalk({ level: 3 });

const config = {
async load(path = configPath) {
const emptyObj = {};
if (fs.existsSync(path) && fs.statSync(path).isFile()) {
const content = fs.readFileSync(path, 'utf-8');
if (existsSync(path) && statSync(path).isFile()) {
const content = readFileSync(path, 'utf-8');
try {
return JSON.parse(content.toString());
} catch (e) {
Expand All @@ -26,11 +27,9 @@ const config = {
const defaultOptions = await config.load(path);
const mergedOptions = { ...defaultOptions, ...options };
const content = JSON.stringify(mergedOptions, null, 2);
fs.existsSync(configDir) || fs.mkdirSync(configDir, { recursive: true });
fs.writeFileSync(path, content);
console.log(
`${chalkInstance.bgGreen(JSON.stringify(options))} config saved at ${chalkInstance.gray(path)}:`,
);
existsSync(configDir) || mkdirSync(configDir, { recursive: true });
writeFileSync(path, content);
console.log(`${chalk.bgGreen(JSON.stringify(options))} config saved at ${chalk.gray(path)}:`);
for (const [key, value] of Object.entries(options)) {
console.log(`${chalk.cyan(key)}: ${chalk.yellow(value)}`);
}
Expand All @@ -40,4 +39,4 @@ const config = {
},
};

module.exports = config;
export default config;
45 changes: 17 additions & 28 deletions lib/print.js → lib/iciba.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
const { saveHistory } = require('./searchHistory');
let chalk = require('chalk');
import { Chalk } from 'chalk';
import { saveHistory } from './searchHistory.mjs';

exports.iciba = (data, options = {}) => {
if (options.color === false) {
chalk = initChalkWithNoColor();
function log(message, indentNum = 1) {
let indent = '';
for (let i = 1; i < indentNum; i += 1) {
indent += ' ';
}
console.log(indent, message || '');
}

export function printIciba(data, options = {}) {
const chalk = new Chalk({ level: options.color === false ? 0 : 3 });

const highlight = (string, key, defaultColor = 'gray') =>
string
.replace(new RegExp(`(.*)(${key})(.*)`, 'gi'), `$1$2${chalk[defaultColor]('$3')}`)
.replace(new RegExp(`(.*?)(${key})`, 'gi'), chalk[defaultColor]('$1') + chalk.yellow('$2'));

let firstLine = '';
const means = [];
Expand Down Expand Up @@ -53,27 +64,5 @@ exports.iciba = (data, options = {}) => {
log();
log(chalk.gray('-----'));
log();
saveHistory(data.key[0], means);
};

function log(message, indentNum = 1) {
let indent = '';
for (let i = 1; i < indentNum; i += 1) {
indent += ' ';
}
console.log(indent, message || '');
}

function highlight(string, key, defaultColor = 'gray') {
return string
.replace(new RegExp(`(.*)(${key})(.*)`, 'gi'), `$1$2${chalk[defaultColor]('$3')}`)
.replace(new RegExp(`(.*?)(${key})`, 'gi'), chalk[defaultColor]('$1') + chalk.yellow('$2'));
}

function initChalkWithNoColor() {
try {
return new chalk.constructor({ enabled: false });
} catch (e) {
return new chalk.Instance({ level: 0 });
}
saveHistory(data.key, means);
}
33 changes: 16 additions & 17 deletions lib/searchHistory.js → lib/searchHistory.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
const fs = require('fs-extra');
const path = require('node:path');
const chalk = require('chalk');
const dayjs = require('dayjs');
import { readFileSync, writeFile } from 'node:fs';
import { homedir } from 'node:os';
import path from 'node:path';
import chalk from 'chalk';
import dayjs from 'dayjs';
import { ensureFileSync } from './utils.mjs';

const homedir = process.env.HOME || require('node:os').homedir();
const searchFilePath = path.resolve(homedir, '.config', 'fanyi', 'searchHistory.txt');
const searchFilePath = path.resolve(homedir(), '.config', 'fanyi', 'searchHistory.txt');

const DAY_SPLIT = 'day-';
const WORD_MEAN_SPLIT = ' ';
Expand All @@ -27,22 +28,21 @@ function getTargetContent(content, startDay, endDay) {
//${WORD_MEAN_SPLIT}v. 命名
// 👆👆👆
function genWordMean(word, means) {
const meansWithSplit = means.join(`\n${WORD_MEAN_SPLIT}`);
return `${word}\n${WORD_MEAN_SPLIT}${meansWithSplit}\n`;
return `${word}\n${WORD_MEAN_SPLIT}${means.join(`\n${WORD_MEAN_SPLIT}`)}\n`;
}

function getDaySplit(someDay) {
return `${DAY_SPLIT}${someDay}:`;
}

exports.searchList = (args) => {
export const searchList = (args) => {
const { someDay, recentDays, showFile } = args;
console.log();
console.log(chalk.gray('fanyi history:'));
console.log();
let targetContent;
fs.ensureFileSync(searchFilePath);
const data = fs.readFileSync(searchFilePath);
ensureFileSync(searchFilePath);
const data = readFileSync(searchFilePath);
const content = data.toString();
let targetDay = dayjs(someDay).format('YYYY-MM-DD');

Expand Down Expand Up @@ -97,23 +97,22 @@ exports.searchList = (args) => {
}
};

exports.saveHistory = (word, means) => {
export const saveHistory = (word, means) => {
try {
fs.ensureFileSync(searchFilePath);

const contentBuffer = fs.readFileSync(searchFilePath);
ensureFileSync(searchFilePath);
const contentBuffer = readFileSync(searchFilePath);
const content = contentBuffer.toString();
if (content.includes(today)) {
const targetContent = getTargetContent(content, today);
// 去重。当天已经查过的,不再写入
if (targetContent[0].includes(`${word}\n`)) {
return;
}
fs.writeFile(searchFilePath, genWordMean(word, means), { flag: 'a' }, (err) => {
writeFile(searchFilePath, genWordMean(word, means), { flag: 'a' }, (err) => {
if (err) throw err;
});
} else {
fs.writeFile(
writeFile(
searchFilePath,
`${getDaySplit(today)}\n${genWordMean(word, means)}\n`,
{ flag: 'a' },
Expand Down
26 changes: 26 additions & 0 deletions lib/utils.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
import path from 'node:path';

/**
* Ensure the file exists, if not, create it and its directory.
* @param {string} filePath - The path to the file.
*/
export function ensureFileSync(filePath) {
try {
// Check if the file already exists
if (!existsSync(filePath)) {
// Get the directory name of the file
const dir = path.dirname(filePath);

// Recursively create the directory if it doesn't exist
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}

// Create an empty file
writeFileSync(filePath, '');
}
} catch (error) {
console.error(`Error ensuring file: ${error.message}`);
}
}
24 changes: 13 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"author": "afc163 <[email protected]>",
"license": "MIT",
"bin": {
"fy": "bin/fanyi.js",
"fanyi": "bin/fanyi.js"
"fy": "bin/fanyi.mjs",
"fanyi": "bin/fanyi.mjs"
},
"keywords": ["chinese", "translator", "iciba", "groq", "llama", "cli", "fanyi"],
"engines": {
Expand All @@ -20,35 +20,37 @@
"readmeFilename": "README.md",
"files": ["index.js", "bin", "lib"],
"dependencies": {
"chalk": "^4.1.2",
"chalk": "^5.3.0",
"commander": "^12.1.0",
"dayjs": "^1.11.13",
"fast-xml-parser": "^4.5.0",
"fs-extra": "^11.2.0",
"gradient-string": "^2.0.2",
"groq-sdk": "^0.7.0",
"node-fetch": "^3.3.2",
"ora": "^5.4.1",
"update-notifier": "^5.1.0"
"ora": "^8.1.0",
"update-notifier": "^7.3.1"
},
"lint-staged": {
"*.{js,ts,json,yml}": ["biome check --write --files-ignore-unknown=true"]
"*.{js,mjs,ts,json,yml}": [
"biome check --write --files-ignore-unknown=true --no-errors-on-unmatched"
]
},
"devDependencies": {
"@biomejs/biome": "^1.9.0",
"@biomejs/biome": "^1.9.2",
"c8": "^10.1.2",
"husky": "^9.1.6",
"lint-staged": "^15.2.10",
"np": "^10.0.7",
"vitest": "^2.1.0"
"vitest": "^2.1.1"
},
"scripts": {
"test": "vitest run",
"test": "vitest run --test-timeout=20000",
"coverage": "c8 --reporter=lcov --reporter=text npm test",
"lint": "biome check .",
"format": "biome check . --write",
"prepublishOnly": "np --no-cleanup --no-publish",
"lint-staged": "lint-staged",
"prepare": "husky"
}
},
"type": "module"
}
10 changes: 8 additions & 2 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { fork } from 'node:child_process';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';

const scriptPath = path.resolve(__dirname, '../bin/fanyi.js');
const scriptPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../bin/fanyi.mjs');

const runScript = (args: string[] = []): Promise<{ stdout: string; stderr: string }> => {
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -31,8 +32,10 @@ const runScript = (args: string[] = []): Promise<{ stdout: string; stderr: strin

describe('fanyi CLI', () => {
it('should print translation of the word', async () => {
await runScript(['config', 'set', 'color', 'false']);
const { stdout } = await runScript(['hello']);
expect(stdout).toContain(`hello 英[ hə'ləʊ ] 美[ həˈloʊ ] ~ iciba.com`);
await runScript(['config', 'set', 'color', 'true']);
});

it('should print usage if no arguments are given', async () => {
Expand All @@ -59,7 +62,10 @@ describe('fanyi CLI', () => {
it('should print without color', async () => {
await runScript(['config', 'set', 'color', 'false']);
const { stdout } = await runScript(['hello']);
expect(stdout).toContain(`hello 英[ hə'ləʊ ] 美[ həˈloʊ ] ~ iciba.com`);
expect(stdout).not.toContain('\u001b[35m');
await runScript(['config', 'set', 'color', 'true']);
const { stdout: stdout2 } = await runScript(['hello']);
expect(stdout2).toContain('\u001b[35m');
});

it('should print config', async () => {
Expand Down

0 comments on commit 78d22d3

Please sign in to comment.