diff --git a/.eslintrc.json b/.eslintrc.json index 30149ce..bcfae6d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,7 +3,8 @@ "es2021": true, "node": true }, - "extends": "standard", + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": "latest", "sourceType": "module" diff --git a/.gitignore b/.gitignore index 61b7f20..6fc64df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /node_modules +/@types npm-debug.log .DS_Store diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..d47b72b --- /dev/null +++ b/index.d.ts @@ -0,0 +1,54 @@ +import { Transform } from "readable-stream"; + +import {Buffer} from "safe-buffer"; + +export declare module 'encoding' { + export function convert(buf: Buffer, toCharset: string, fromCharset: string): Buffer; +} + +export interface Compiler { + _table: GetTextTranslations; + compile(): Buffer; +} + +export interface GetTextComment { + translator?: string; + reference?: string; + extracted?: string; + flag?: string; + previous?: string; +} + +export interface GetTextTranslation { + msgctxt?: string; + msgid: string; + msgid_plural?: string; + msgstr: string[]; + comments?: GetTextComment; +} + +export interface GetTextTranslations { + charset: string; + headers: { [headerName: string]: string }; + translations: { [msgctxt: string]: { [msgId: string]: GetTextTranslation } }; +} + +export interface parserOptions { + defaultCharset?: string; + validation?: boolean; +} + +export interface po { + parse: (buffer: Buffer | string, defaultCharset?: string) => GetTextTranslations; + compile: (table: GetTextTranslations, options?: parserOptions) => Buffer; + createParseStream: (options?: parserOptions, transformOptions?: import('readable-stream').TransformOptions) => Transform; +} + +export interface mo { + parse: (buffer: Buffer | string, defaultCharset?: string) => GetTextTranslations; + compile: (table: GetTextTranslations, options?: parserOptions) => Buffer; +} + +export * from "./@types"; + +export default { po, mo } as { po: po, mo: mo }; diff --git a/index.js b/index.js index fab9b44..1f5a96c 100644 --- a/index.js +++ b/index.js @@ -3,12 +3,24 @@ import poCompiler from './lib/pocompiler.js'; import moParser from './lib/moparser.js'; import moCompiler from './lib/mocompiler.js'; +/** + * Translation parser and compiler for PO files + * @see https://www.gnu.org/software/gettext/manual/html_node/PO.html + * + * @type {import("./index.d.ts").po} po + */ export const po = { parse: poParser.parse, createParseStream: poParser.stream, compile: poCompiler }; +/** + * Translation parser and compiler for PO files + * @see https://www.gnu.org/software/gettext/manual/html_node/MO.html + * + * @type {import("./index.d.ts").mo} mo + */ export const mo = { parse: moParser, compile: moCompiler diff --git a/lib/mocompiler.js b/lib/mocompiler.js index 9715d63..9e8747d 100644 --- a/lib/mocompiler.js +++ b/lib/mocompiler.js @@ -7,20 +7,21 @@ import contentType from 'content-type'; * Exposes general compiler function. Takes a translation * object as a parameter and returns binary MO object * - * @param {Object} table Translation object + * @param {import('./index.d.ts').GetTextTranslations} table Translation object * @return {Buffer} Compiled binary MO object */ export default function (table) { const compiler = new Compiler(table); return compiler.compile(); -}; +} /** * Creates a MO compiler object. * * @constructor - * @param {Object} table Translation table as defined in the README + * @param {import('./index.d.ts').GetTextTranslations} table Translation table as defined in the README + * @return {import('./index.d.ts').Compiler} Compiler */ function Compiler (table = {}) { this._table = table; @@ -148,7 +149,7 @@ Compiler.prototype._generateList = function () { /** * Calculate buffer size for the final binary object * - * @param {Array} list An array of translation strings from _generateList + * @param {import('./index.d.ts').GetTextTranslations} list An array of translation strings from _generateList * @return {Object} Size data of {msgid, msgstr, total} */ Compiler.prototype._calculateSize = function (list) { @@ -183,7 +184,7 @@ Compiler.prototype._calculateSize = function (list) { /** * Generates the binary MO object from the translation list * - * @param {Array} list translation list + * @param {import('./index.d.ts').GetTextTranslations} list translation list * @param {Object} size Byte size information * @return {Buffer} Compiled MO object */ diff --git a/lib/moparser.js b/lib/moparser.js index 09c10f8..0054710 100644 --- a/lib/moparser.js +++ b/lib/moparser.js @@ -12,7 +12,7 @@ export default function (buffer, defaultCharset) { const parser = new Parser(buffer, defaultCharset); return parser.parse(); -}; +} /** * Creates a MO parser object. diff --git a/lib/pocompiler.js b/lib/pocompiler.js index f4baa0a..c08671b 100644 --- a/lib/pocompiler.js +++ b/lib/pocompiler.js @@ -14,7 +14,7 @@ export default function (table, options) { const compiler = new Compiler(table, options); return compiler.compile(); -}; +} /** * Creates a PO compiler object. diff --git a/lib/poparser.js b/lib/poparser.js index 77b8b12..70cce36 100644 --- a/lib/poparser.js +++ b/lib/poparser.js @@ -14,18 +14,18 @@ export function parse (input, options = {}) { const parser = new Parser(input, options); return parser.parse(); -}; +} /** * Parses a PO stream, emits translation table in object mode * - * @typedef {{ defaultCharset: strubg, validation: boolean }} Options + * @typedef {{ defaultCharset: string, validation: boolean }} Options * @param {Options} [options] Optional options with defaultCharset and validation * @param {import('readable-stream').TransformOptions} [transformOptions] Optional stream options */ export function stream (options = {}, transformOptions = {}) { return new PoParserTransform(options, transformOptions); -}; +} /** * Creates a PO parser object. If PO object is a string, @@ -515,7 +515,7 @@ Parser.prototype._finalize = function (tokens) { /** * Creates a transform stream for parsing PO input * - * @typedef {{ defaultCharset: strubg, validation: boolean }} Options + * @typedef {{ defaultCharset: string, validation: boolean }} Options * @constructor * @param {Options} options Optional options with defaultCharset and validation * @param {import('readable-stream').TransformOptions} transformOptions Optional stream options diff --git a/lib/shared.js b/lib/shared.js index 8cf706c..5e2d3a5 100644 --- a/lib/shared.js +++ b/lib/shared.js @@ -45,8 +45,8 @@ export function parseHeader (str = '') { * @param {Object} [headers = {}] An object with parsed headers * @returns {number} Parsed result */ -export function parseNPluralFromHeadersSafely (headers = {}, fallback = 1) { - const pluralForms = headers[PLURAL_FORMS]; +export function parseNPluralFromHeadersSafely (headers, fallback = 1) { + const pluralForms = headers ? headers[PLURAL_FORMS] : false; if (!pluralForms) { return fallback; @@ -101,7 +101,7 @@ export function formatCharset (charset = 'iso-8859-1', defaultCharset = 'iso-885 * * @param {String} str PO formatted string to be folded * @param {Number} [maxLen=76] Maximum allowed length for folded lines - * @return {Array} An array of lines + * @return {string[]} An array of lines */ export function foldLine (str, maxLen = 76) { const lines = []; diff --git a/package.json b/package.json index d01f014..dfc5bba 100644 --- a/package.json +++ b/package.json @@ -22,9 +22,11 @@ "test-generate-mo": "msgfmt test/fixtures/latin13.po -o test/fixtures/latin13.mo & msgfmt test/fixtures/utf8.po -o test/fixtures/utf8.mo & msgfmt test/fixtures/obsolete.po -o test/fixtures/obsolete.mo", "test": "mocha", "preversion": "npm run lint && npm test", - "postversion": "git push && git push --tags" + "postversion": "git push && git push --tags", + "prepublish": "tsc && npm run lint && npm run test" }, "main": "./index.js", + "types": "./index.d.ts", "license": "MIT", "dependencies": { "content-type": "^1.0.5", @@ -33,13 +35,20 @@ "safe-buffer": "^5.2.1" }, "devDependencies": { + "@types/chai": "latest", + "@types/content-type": "^1.1.8", + "@types/mocha": "latest", + "@types/readable-stream": "^4.0.11", + "@typescript-eslint/eslint-plugin": "^6.18.1", + "@typescript-eslint/parser": "^6.14.0", "chai": "^5.0.3", "eslint": "^8.56.0", "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.29.1", "eslint-plugin-n": "^16.6.2", "eslint-plugin-promise": "^6.1.1", - "mocha": "^10.3.0" + "mocha": "^10.3.0", + "typescript": "^5.4.4" }, "keywords": [ "i18n", diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1564f0f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + "noImplicitAny": true, + "removeComments": false, + "module": "Node16", + "moduleResolution": "Node16", + "target": "ES2015", + + // Strict mode + "strict": true, + + // Allow javascript files + "allowJs": true, + + // Check js files for errors + "checkJs": false, + + // Output d.ts files to @types + "outDir": "@types", + + // Generate d.ts files + "declaration": true, + + // This compiler run should + // only output d.ts files + "emitDeclarationOnly": true, + // Minify + "pretty": false, + // Skip lib check when compiling + "skipLibCheck": true + }, + "include": [ + "lib/**/*.js", + "index.d.ts" + ] +}