Skip to content

Commit

Permalink
Merge pull request #13 from florianldt/config-file-support
Browse files Browse the repository at this point in the history
Config file support
  • Loading branch information
florianldt authored Sep 20, 2022
2 parents 0749a5d + d0fe37b commit 4a1f129
Show file tree
Hide file tree
Showing 12 changed files with 125 additions and 102 deletions.
2 changes: 0 additions & 2 deletions .env.example

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -168,5 +168,6 @@ examples/
!examples/Localizable-empty.strings
!examples/Localizable.badExt
!examples/Localizable.strings
.jeromerc.json

# End of https://www.toptal.com/developers/gitignore/api/vim,node,macos
101 changes: 20 additions & 81 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"axios": "^0.27.2",
"chalk": "^4.1.2",
"commander": "^9.4.0",
"dotenv": "^16.0.2",
"cosmiconfig": "^7.0.1",
"ora": "^5.4.1",
"qs": "^6.11.0"
}
Expand Down
18 changes: 13 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/usr/bin/env node

import { AxiosError } from 'axios';
import { Command, Option } from 'commander';
import ora from 'ora';

import {
extractConfig,
papagoLocals,
parseFile,
renderErrorLogs,
Expand All @@ -15,6 +15,8 @@ import {
writeFile,
} from './lib';
import {
ConfigFileNotFoundError,
ConfigPropertyNotFoundError,
FileInvalidExtensionError,
FileNotExistError,
PapagoError,
Expand Down Expand Up @@ -58,13 +60,15 @@ program.parse();
const { input, source, target } = program.opts<CLIArgs>();

async function main() {
renderHeaderLogs(version, input, source, target);

const testInputSpinner = ora();
const translationSpinner = ora();
const writeSpinner = ora();

try {
const { config, configPath } = extractConfig();

renderHeaderLogs(version, configPath, input, source, target);

testInputSpinner.start(`Testing input file: ${input}`);
testInput(input);
testInputSpinner.succeed(`Valid input file: ${input}`);
Expand All @@ -74,7 +78,7 @@ async function main() {
translationSpinner.start(
`Translating ${papagoLocals[source]} to ${papagoLocals[target]}`,
);
const translations = await translate(keyValues, source, target);
const translations = await translate(config, keyValues, source, target);
translationSpinner.succeed(
`Translated ${papagoLocals[source]} to ${papagoLocals[target]}`,
);
Expand All @@ -86,7 +90,11 @@ async function main() {
renderFooterLogs();
process.exit(0);
} catch (e) {
if (
if (e instanceof ConfigFileNotFoundError) {
renderHeaderLogs(version, null, input, source, target);
} else if (e instanceof ConfigPropertyNotFoundError) {
renderHeaderLogs(version, e.configPath, input, source, target);
} else if (
e instanceof FileNotExistError ||
e instanceof FileInvalidExtensionError
) {
Expand Down
17 changes: 17 additions & 0 deletions src/lib/errors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
/* eslint-disable max-classes-per-file -- Error subclasses only */
class ConfigFileNotFoundError extends Error {
constructor() {
super('Config file not found.');
}
}

class ConfigPropertyNotFoundError extends Error {
public configPath: string;

constructor(property: string, configPath: string) {
super(`Property \`${property}\` not found in the config file.`);
this.configPath = configPath;
}
}

class FileNotExistError extends Error {
constructor() {
super('File does not exist.');
Expand All @@ -24,6 +39,8 @@ class PapagoError extends Error {
}

export {
ConfigFileNotFoundError,
ConfigPropertyNotFoundError,
FileInvalidExtensionError,
FileNotExistError,
NothingToTranslateError,
Expand Down
38 changes: 38 additions & 0 deletions src/lib/extractConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { cosmiconfigSync } from 'cosmiconfig';

import { ConfigFileNotFoundError, ConfigPropertyNotFoundError } from './errors';

import { Config } from '../types';

type Result = {
config: Config;
configPath: string;
};

function extractConfig(): Result {
const config = cosmiconfigSync('jerome').search();

if (!config) {
throw new ConfigFileNotFoundError();
}

const castedConfig = config.config as Config;

if (!castedConfig.X_NAVER_CLIENT_ID) {
throw new ConfigPropertyNotFoundError(
'X_NAVER_CLIENT_ID',
config.filepath,
);
}

if (!castedConfig.X_NAVER_CLIENT_SECRET) {
throw new ConfigPropertyNotFoundError(
'X_NAVER_CLIENT_SECRET',
config.filepath,
);
}

return { config: config.config, configPath: config.filepath };
}

export default extractConfig;
2 changes: 2 additions & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import extractConfig from './extractConfig';
import extractKeyValues from './extractKeyValues';
import extractText from './extractText';
import hasValidExtension from './hasValidExtension';
Expand All @@ -9,6 +10,7 @@ import { translate } from './translate';
import writeFile from './writeFile';

export {
extractConfig,
extractKeyValues,
extractText,
hasValidExtension,
Expand Down
2 changes: 2 additions & 0 deletions src/lib/logging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PapagoLocalKeys } from '../types';
/* eslint-disable no-console */
function renderHeaderLogs(
version: string,
configPath: string | null,
input: string,
source: PapagoLocalKeys,
target: PapagoLocalKeys,
Expand All @@ -17,6 +18,7 @@ function renderHeaderLogs(
console.log(` \\____/ \\___|_| \\___/|_| |_| |_|\\___| v${version}`);

console.log();
console.log(`${chalk.bold('Config:')} ${configPath ?? ''}`);
console.log(`${chalk.bold('Input:')} ${input}`);
console.log(`${chalk.bold('Source:')} ${source}`);
console.log(`${chalk.bold('Target:')} ${target}`);
Expand Down
19 changes: 13 additions & 6 deletions src/lib/translate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ import axios from 'axios';

import { buildTextPackets, requestsBuilder, translate } from './translate';

import { KeyValues } from '../types';
import { Config, KeyValues } from '../types';

jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;

const dummyConfig: Config = {
X_NAVER_CLIENT_ID: '',
X_NAVER_CLIENT_SECRET: '',
};

describe('buildTextPackets', () => {
test('should return empty array as keyValues is empty', () => {
expect(buildTextPackets([])).toEqual([]);
Expand Down Expand Up @@ -52,13 +57,13 @@ describe('buildTextPackets', () => {

describe('requestsBuilder', () => {
test('should return empty array as packets is empty', () => {
expect(requestsBuilder([], 'ko', 'en')).toEqual([]);
expect(requestsBuilder(dummyConfig, [], 'ko', 'en')).toEqual([]);
});

test('should return 3 requests', () => {
expect(requestsBuilder(['홈', '홈', '홈'], 'ko', 'en').length).toEqual(
3,
);
expect(
requestsBuilder(dummyConfig, ['홈', '홈', '홈'], 'ko', 'en').length,
).toEqual(3);
});
});

Expand Down Expand Up @@ -89,7 +94,9 @@ describe('translate', () => {
{ key: '6788d684', value: '그럼요!' },
];
mockedAxios.post.mockResolvedValue({ data });
await expect(translate(keyValues, 'ko', 'en')).resolves.toEqual(
await expect(
translate(dummyConfig, keyValues, 'ko', 'en'),
).resolves.toEqual(
'Home\n\nMy Carrot\n\nDoes the Carrot App help you keep alive?\n\nNo.\n\nOf course!',
);
});
Expand Down
19 changes: 12 additions & 7 deletions src/lib/translate.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import axios, { AxiosError, AxiosRequestHeaders, AxiosResponse } from 'axios';
import dotenv from 'dotenv';
import { stringify } from 'qs';

import { KeyValues, PapagoFailureResponse, PapagoOkResponse } from '../types';
import {
Config,
KeyValues,
PapagoFailureResponse,
PapagoOkResponse,
} from '../types';
import { PapagoError } from './errors';

dotenv.config();

function buildTextPackets(keyValues: KeyValues): string[] {
const max = 5000;
const packets: string[] = [];
Expand Down Expand Up @@ -39,14 +41,16 @@ function buildTextPackets(keyValues: KeyValues): string[] {
}

function requestsBuilder(
config: Config,
packets: string[],
baseLocal: string,
toLocal: string,
): Promise<AxiosResponse<PapagoOkResponse>>[] {
const { X_NAVER_CLIENT_ID, X_NAVER_CLIENT_SECRET } = config;
const baseUrl = 'https://openapi.naver.com/v1/papago/n2mt';
const headers: AxiosRequestHeaders = {
'X-Naver-Client-Id': process.env.X_NAVER_CLIENT_ID ?? '',
'X-Naver-Client-Secret': process.env.X_NAVER_CLIENT_SECRET ?? '',
'X-Naver-Client-Id': X_NAVER_CLIENT_ID,
'X-Naver-Client-Secret': X_NAVER_CLIENT_SECRET,
};

const requests: Promise<AxiosResponse<PapagoOkResponse>>[] = [];
Expand All @@ -70,12 +74,13 @@ function requestsBuilder(
}

async function translate(
config: Config,
keyValues: KeyValues,
baseLocal: string,
toLocals: string,
): Promise<string> {
const packets = buildTextPackets(keyValues);
const requests = requestsBuilder(packets, baseLocal, toLocals);
const requests = requestsBuilder(config, packets, baseLocal, toLocals);

return Promise.all(requests)
.then((responses) => {
Expand Down
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ type CLIArgs = {
target: PapagoLocalKeys;
};

type Config = {
X_NAVER_CLIENT_ID: string;
X_NAVER_CLIENT_SECRET: string;
};

type KeyValues = {
key: string;
value: string;
Expand Down Expand Up @@ -38,6 +43,7 @@ type PapagoFailureResponse = {

export type {
CLIArgs,
Config,
KeyValues,
PapagoFailureResponse,
PapagoLocalKeys,
Expand Down

0 comments on commit 4a1f129

Please sign in to comment.