From 07ba4f870f65782118b868a84d5fb2cef85aa89a Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Fri, 5 Apr 2024 15:44:40 +0200 Subject: [PATCH 1/9] environment setup --- .eslintrc.json | 3 ++- .gitignore | 1 + package.json | 24 ++++++++++++++++++++---- tsconfig.json | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 tsconfig.json 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..51212ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /node_modules +lib npm-debug.log .DS_Store diff --git a/package.json b/package.json index d01f014..1e4a751 100644 --- a/package.json +++ b/package.json @@ -17,29 +17,45 @@ "engines": { "node": ">=18" }, + "files": [ + "lib", + "test", + "*.json", + "*.md", + "license.txt" + ], "scripts": { - "lint": "eslint lib/*.js test/*.js index.js", + "start": "tsc --watch", + "build": "tsc --build --clean ./index.ts", + "lint": "eslint src/*.js test/*.js", "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" }, - "main": "./index.js", + "main": "./lib/index.js", "license": "MIT", "dependencies": { + "@types/gettext-parser": "^4.0.4", "content-type": "^1.0.5", "encoding": "^0.1.13", "readable-stream": "^4.5.2", "safe-buffer": "^5.2.1" }, "devDependencies": { - "chai": "^5.0.3", + "@types/chai": "latest", + "@types/content-type": "^1.1.8", + "@types/mocha": "latest", + "@typescript-eslint/eslint-plugin": "^6.18.1", + "@typescript-eslint/parser": "^6.14.0", + "chai": "^5.1.0", "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.4.0", + "typescript": "^5.4.4" }, "keywords": [ "i18n", diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d06266a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,37 @@ +{ + "compilerOptions": { + "noImplicitAny": true, + "removeComments": true, + "module": "ESNext", + "moduleResolution": "Node", + "target": "ES2021", + "declaration": true, + "emitDeclarationOnly": false, + "preserveConstEnums": true, + "sourceMap": true, + "strict": false, + "allowJs": true, + "downlevelIteration": true, + "esModuleInterop": true, + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "rootDir": "src", + "outDir": "lib", + // Minify + "pretty": false, + // types + "typeRoots": [ + "src/types.d.ts", + "node_modules/@types", + "@types" + ], + "lib": [ + "dom", + "ESNext" + ] + }, + "include": [ + "./src/**/*" + ] +} From e3990ca240aad560511516d22ac57c6b1661deb7 Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Fri, 5 Apr 2024 15:45:28 +0200 Subject: [PATCH 2/9] moves the index file into /src --- index.js | 17 ----------------- src/index.d.ts | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/index.js | 27 +++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 17 deletions(-) delete mode 100644 index.js create mode 100644 src/index.d.ts create mode 100644 src/index.js diff --git a/index.js b/index.js deleted file mode 100644 index fab9b44..0000000 --- a/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import * as poParser from './lib/poparser.js'; -import poCompiler from './lib/pocompiler.js'; -import moParser from './lib/moparser.js'; -import moCompiler from './lib/mocompiler.js'; - -export const po = { - parse: poParser.parse, - createParseStream: poParser.stream, - compile: poCompiler -}; - -export const mo = { - parse: moParser, - compile: moCompiler -}; - -export default { mo, po }; diff --git a/src/index.d.ts b/src/index.d.ts new file mode 100644 index 0000000..ceeb996 --- /dev/null +++ b/src/index.d.ts @@ -0,0 +1,49 @@ +import { Transform } from "readable-stream"; +import {Buffer} from "safe-buffer"; + +export declare module 'encoding' { + export function convert(buf: Buffer, charset: 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 PoParser { + parse: (buffer: Buffer | string, defaultCharset?: string) => GetTextTranslations; + compile: (table: GetTextTranslations, options?: parserOptions) => Buffer; + createParseStream: (options?: parserOptions, transformOptions?: import('readable-stream').TransformOptions) => Transform; +} + +export interface MoParser { + parse: (buffer: Buffer | string, defaultCharset?: string) => GetTextTranslations; + compile: (table: GetTextTranslations, options?: parserOptions) => Buffer; +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..d5deb01 --- /dev/null +++ b/src/index.js @@ -0,0 +1,27 @@ +import * as poParser from './poparser.js'; +import poCompiler from './pocompiler.js'; +import moParser from './moparser.js'; +import moCompiler from './mocompiler.js'; + +/** + * Translation parser and compiler for PO files + * @see https://www.gnu.org/software/gettext/manual/html_node/PO.html + * + * @type {import("./index.js").PoParser} 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.js").MoParser} mo + */ +export const mo= { + parse: moParser, + compile: moCompiler +}; From 07d4b817061ce2660dd039bf3de1ee8f2fe76712 Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Fri, 5 Apr 2024 15:46:52 +0200 Subject: [PATCH 3/9] types for module functions --- {lib => src}/mocompiler.js | 19 +++++++++++-------- {lib => src}/moparser.js | 4 ++-- {lib => src}/pocompiler.js | 10 +++++----- {lib => src}/poparser.js | 18 ++++++++++-------- {lib => src}/shared.js | 10 +++++++--- 5 files changed, 35 insertions(+), 26 deletions(-) rename {lib => src}/mocompiler.js (91%) rename {lib => src}/moparser.js (98%) rename {lib => src}/pocompiler.js (97%) rename {lib => src}/poparser.js (97%) rename {lib => src}/shared.js (93%) diff --git a/lib/mocompiler.js b/src/mocompiler.js similarity index 91% rename from lib/mocompiler.js rename to src/mocompiler.js index 9715d63..98ee909 100644 --- a/lib/mocompiler.js +++ b/src/mocompiler.js @@ -1,28 +1,29 @@ import { Buffer } from 'safe-buffer'; import encoding from 'encoding'; -import { HEADERS, formatCharset, generateHeader, compareMsgid } from './shared.js'; +import { compareMsgid, formatCharset, generateHeader, HEADERS } from './shared.js'; 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.js').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.js').gettextTranslations} table Translation table as defined in the README + * @return {import('./index.js').Compiler} Compiler */ -function Compiler (table = {}) { +function Compiler (table ) { this._table = table; let { headers = {}, translations = {} } = this._table; @@ -70,6 +71,8 @@ function Compiler (table = {}) { this._writeFunc = 'writeUInt32LE'; this._handleCharset(); + + return this; } /** @@ -148,7 +151,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.js').GettextTranslations} list An array of translation strings from _generateList * @return {Object} Size data of {msgid, msgstr, total} */ Compiler.prototype._calculateSize = function (list) { @@ -183,7 +186,7 @@ Compiler.prototype._calculateSize = function (list) { /** * Generates the binary MO object from the translation list * - * @param {Array} list translation list + * @param {import('./index.js').GettextTranslations} list translation list * @param {Object} size Byte size information * @return {Buffer} Compiled MO object */ @@ -237,7 +240,7 @@ Compiler.prototype._build = function (list, size) { }; /** - * Compiles translation object into a binary MO object + * Compiles the translation object into a binary MO object * * @return {Buffer} Compiled MO object */ diff --git a/lib/moparser.js b/src/moparser.js similarity index 98% rename from lib/moparser.js rename to src/moparser.js index 09c10f8..1289f24 100644 --- a/lib/moparser.js +++ b/src/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. @@ -135,7 +135,7 @@ Parser.prototype._handleCharset = function (headers) { * Adds a translation to the translation object * * @param {String} msgid Original string - * @params {String} msgstr Translation for the original string + * @param {String} msgstr Translation for the original string */ Parser.prototype._addString = function (msgid, msgstr) { const translation = {}; diff --git a/lib/pocompiler.js b/src/pocompiler.js similarity index 97% rename from lib/pocompiler.js rename to src/pocompiler.js index f4baa0a..61a229f 100644 --- a/lib/pocompiler.js +++ b/src/pocompiler.js @@ -1,20 +1,20 @@ -import { Buffer } from 'safe-buffer'; -import encoding from 'encoding'; -import { HEADERS, foldLine, compareMsgid, formatCharset, generateHeader } from './shared.js'; +import { compareMsgid, foldLine, formatCharset, generateHeader, HEADERS } from './shared.js'; import contentType from 'content-type'; +import encoding from 'encoding'; /** * Exposes general compiler function. Takes a translation * object as a parameter and returns PO object * * @param {Object} table Translation object + * @param options * @return {Buffer} Compiled PO object */ export default function (table, options) { const compiler = new Compiler(table, options); return compiler.compile(); -}; +} /** * Creates a PO compiler object. @@ -72,7 +72,7 @@ function Compiler (table = {}, options = {}) { * @param {Object} comments A comments object * @return {String} A comment string for the PO file */ -Compiler.prototype._drawComments = function (comments) { +Compiler.prototype._drawComments = function (comments){ const lines = []; const types = [{ key: 'translator', diff --git a/lib/poparser.js b/src/poparser.js similarity index 97% rename from lib/poparser.js rename to src/poparser.js index 77b8b12..28af5dd 100644 --- a/lib/poparser.js +++ b/src/poparser.js @@ -1,5 +1,5 @@ import encoding from 'encoding'; -import { formatCharset, parseNPluralFromHeadersSafely, parseHeader } from './shared.js'; +import { formatCharset, parseHeader, parseNPluralFromHeadersSafely } from './shared.js'; import { Transform } from 'readable-stream'; import util from 'util'; @@ -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, @@ -68,7 +68,7 @@ Parser.prototype.parse = function () { /** * Detects charset for PO strings from the header * - * @param {Buffer} headers Header value + * @param buf PO string buffer to be parsed */ Parser.prototype._handleCharset = function (buf = '') { const str = buf.toString(); @@ -77,8 +77,8 @@ Parser.prototype._handleCharset = function (buf = '') { let match; if ((pos = str.search(/^\s*msgid/im)) >= 0) { - pos = pos + str.substr(pos + 5).search(/^\s*(msgid|msgctxt)/im); - headers = str.substr(0, pos >= 0 ? pos + 5 : str.length); + pos = pos + str.substring(pos + 5).search(/^\s*(msgid|msgctxt)/im); + headers = str.substring(0, pos >= 0 ? pos + 5 : str.length); } if ((match = headers.match(/[; ]charset\s*=\s*([\w-]+)(?:[\s;]|\\n)*"\s*$/mi))) { @@ -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 @@ -533,6 +533,8 @@ function PoParserTransform (options, transformOptions) { Transform.call(this, transformOptions); this._writableState.objectMode = false; this._readableState.objectMode = true; + + return this; } util.inherits(PoParserTransform, Transform); diff --git a/lib/shared.js b/src/shared.js similarity index 93% rename from lib/shared.js rename to src/shared.js index 8cf706c..c1da72a 100644 --- a/lib/shared.js +++ b/src/shared.js @@ -1,5 +1,7 @@ // see https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html + const PLURAL_FORMS = 'Plural-Forms'; + export const HEADERS = new Map([ ['project-id-version', 'Project-Id-Version'], ['report-msgid-bugs-to', 'Report-Msgid-Bugs-To'], @@ -43,10 +45,11 @@ export function parseHeader (str = '') { * Attempts to safely parse 'nplurals" value from "Plural-Forms" header * * @param {Object} [headers = {}] An object with parsed headers + * @param fallback {Number} Fallback value * @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; @@ -83,6 +86,7 @@ export function generateHeader (header = {}) { * Normalizes charset name. Converts utf8 to utf-8, WIN1257 to windows-1257 etc. * * @param {String} charset Charset name + * @param defaultCharset Default charset (default: 'iso-8859-1') * @return {String} Normalized charset name */ export function formatCharset (charset = 'iso-8859-1', defaultCharset = 'iso-8859-1') { @@ -101,7 +105,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 = []; From 053254dbe19ff48a4de519f9c60e283c6b1eb859 Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Sat, 6 Apr 2024 15:25:05 +0200 Subject: [PATCH 4/9] test path updated --- test/mo-compiler-test.js | 2 +- test/mo-parser-test.js | 2 +- test/module.mjs | 2 +- test/po-compiler-test.js | 2 +- test/po-obsolete-test.js | 2 +- test/po-parser-test.js | 2 +- test/shared.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/mo-compiler-test.js b/test/mo-compiler-test.js index 4796425..6405d7a 100644 --- a/test/mo-compiler-test.js +++ b/test/mo-compiler-test.js @@ -1,7 +1,7 @@ import * as chai from 'chai'; import { promisify } from 'util'; import path from 'path'; -import { mo } from '../index.js'; +import { mo } from '../src/index.js'; import { readFile as fsReadFile } from 'fs'; import { fileURLToPath } from 'url'; diff --git a/test/mo-parser-test.js b/test/mo-parser-test.js index 723368a..cf569dc 100644 --- a/test/mo-parser-test.js +++ b/test/mo-parser-test.js @@ -1,7 +1,7 @@ import * as chai from 'chai'; import { promisify } from 'util'; import path from 'path'; -import { mo } from '../index.js'; +import { mo } from '../src/index.js'; import { readFile as fsReadFile } from 'fs'; import { fileURLToPath } from 'url'; diff --git a/test/module.mjs b/test/module.mjs index 1796fd6..b1b48b0 100644 --- a/test/module.mjs +++ b/test/module.mjs @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { po, mo } from '../index.js'; +import { po, mo } from '../src/index.js'; describe('esm module', () => { it('should allow named imports', () => { diff --git a/test/po-compiler-test.js b/test/po-compiler-test.js index 18ad149..07000a9 100644 --- a/test/po-compiler-test.js +++ b/test/po-compiler-test.js @@ -3,7 +3,7 @@ import { promisify } from 'util'; import path from 'path'; import { readFile as fsReadFile } from 'fs'; import * as chai from 'chai'; -import { po } from '../index.js'; +import { po } from '../src/index.js'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); diff --git a/test/po-obsolete-test.js b/test/po-obsolete-test.js index f0e696f..10ec59d 100644 --- a/test/po-obsolete-test.js +++ b/test/po-obsolete-test.js @@ -3,7 +3,7 @@ import * as chai from 'chai'; import { promisify } from 'util'; import path from 'path'; import fs from 'fs'; -import * as gettextParser from '../index.js'; +import * as gettextParser from '../src/index.js'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); diff --git a/test/po-parser-test.js b/test/po-parser-test.js index 3a006c1..89b9e95 100644 --- a/test/po-parser-test.js +++ b/test/po-parser-test.js @@ -2,7 +2,7 @@ import * as chai from 'chai'; import { promisify } from 'util'; import path from 'path'; import fs from 'fs'; -import * as gettextParser from '../index.js'; +import * as gettextParser from '../src/index.js'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); diff --git a/test/shared.js b/test/shared.js index c40dfd6..7ca0a81 100644 --- a/test/shared.js +++ b/test/shared.js @@ -3,7 +3,7 @@ import * as chai from 'chai'; import { promisify } from 'util'; import path from 'path'; -import { formatCharset, parseHeader, generateHeader, foldLine, parseNPluralFromHeadersSafely } from '../lib/shared.js'; +import { formatCharset, parseHeader, generateHeader, foldLine, parseNPluralFromHeadersSafely } from '../src/shared.js'; import { readFile as fsReadFile } from 'fs'; import { fileURLToPath } from 'url'; From c367ef74b35813a734a08d69bd8a01e61763b7ba Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Sat, 6 Apr 2024 19:23:16 +0200 Subject: [PATCH 5/9] simplifies the build script add comments to types and types to package.json --- package.json | 4 ++-- tsconfig.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 1e4a751..08cadbe 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ ], "scripts": { "start": "tsc --watch", - "build": "tsc --build --clean ./index.ts", + "build": "tsc", "lint": "eslint src/*.js test/*.js", "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", @@ -34,9 +34,9 @@ "postversion": "git push && git push --tags" }, "main": "./lib/index.js", + "types": "./lib/index.d.ts", "license": "MIT", "dependencies": { - "@types/gettext-parser": "^4.0.4", "content-type": "^1.0.5", "encoding": "^0.1.13", "readable-stream": "^4.5.2", diff --git a/tsconfig.json b/tsconfig.json index d06266a..1b7d1bd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "noImplicitAny": true, - "removeComments": true, + "removeComments": false, "module": "ESNext", "moduleResolution": "Node", "target": "ES2021", From f18a1157fc991caee8fcde7f950064c817460a86 Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Thu, 11 Apr 2024 11:40:33 +0200 Subject: [PATCH 6/9] cleanup pr - revert unneeded changes in package.json - revert files moved to src - linting --- .gitignore | 2 +- src/index.d.ts => index.d.ts | 7 ++--- src/index.js => index.js | 16 ++++++----- {src => lib}/mocompiler.js | 18 ++++++------- {src => lib}/moparser.js | 0 {src => lib}/pocompiler.js | 8 +++--- {src => lib}/poparser.js | 2 +- {src => lib}/shared.js | 0 package.json | 22 +++++----------- test/mo-compiler-test.js | 2 +- test/mo-parser-test.js | 2 +- test/module.mjs | 2 +- test/po-compiler-test.js | 2 +- test/po-obsolete-test.js | 2 +- test/po-parser-test.js | 2 +- test/shared.js | 2 +- tsconfig.json | 51 ++++++++++++++++++------------------ 17 files changed, 67 insertions(+), 73 deletions(-) rename src/index.d.ts => index.d.ts (90%) rename src/index.js => index.js (57%) rename {src => lib}/mocompiler.js (91%) rename {src => lib}/moparser.js (100%) rename {src => lib}/pocompiler.js (97%) rename {src => lib}/poparser.js (99%) rename {src => lib}/shared.js (100%) diff --git a/.gitignore b/.gitignore index 51212ff..6fc64df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ /node_modules -lib +/@types npm-debug.log .DS_Store diff --git a/src/index.d.ts b/index.d.ts similarity index 90% rename from src/index.d.ts rename to index.d.ts index ceeb996..522d3ee 100644 --- a/src/index.d.ts +++ b/index.d.ts @@ -1,8 +1,9 @@ import { Transform } from "readable-stream"; + import {Buffer} from "safe-buffer"; export declare module 'encoding' { - export function convert(buf: Buffer, charset: string): Buffer; + export function convert(buf: Buffer, toCharset: string, fromCharset: string): Buffer; } export interface Compiler { @@ -37,13 +38,13 @@ export interface parserOptions { validation?: boolean; } -export interface PoParser { +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 MoParser { +export interface mo { parse: (buffer: Buffer | string, defaultCharset?: string) => GetTextTranslations; compile: (table: GetTextTranslations, options?: parserOptions) => Buffer; } diff --git a/src/index.js b/index.js similarity index 57% rename from src/index.js rename to index.js index d5deb01..1f5a96c 100644 --- a/src/index.js +++ b/index.js @@ -1,13 +1,13 @@ -import * as poParser from './poparser.js'; -import poCompiler from './pocompiler.js'; -import moParser from './moparser.js'; -import moCompiler from './mocompiler.js'; +import * as poParser from './lib/poparser.js'; +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.js").PoParser} po + * @type {import("./index.d.ts").po} po */ export const po = { parse: poParser.parse, @@ -19,9 +19,11 @@ export const po = { * Translation parser and compiler for PO files * @see https://www.gnu.org/software/gettext/manual/html_node/MO.html * - * @type {import("./index.js").MoParser} mo + * @type {import("./index.d.ts").mo} mo */ -export const mo= { +export const mo = { parse: moParser, compile: moCompiler }; + +export default { mo, po }; diff --git a/src/mocompiler.js b/lib/mocompiler.js similarity index 91% rename from src/mocompiler.js rename to lib/mocompiler.js index 98ee909..9e8747d 100644 --- a/src/mocompiler.js +++ b/lib/mocompiler.js @@ -1,13 +1,13 @@ import { Buffer } from 'safe-buffer'; import encoding from 'encoding'; -import { compareMsgid, formatCharset, generateHeader, HEADERS } from './shared.js'; +import { HEADERS, formatCharset, generateHeader, compareMsgid } from './shared.js'; import contentType from 'content-type'; /** * Exposes general compiler function. Takes a translation * object as a parameter and returns binary MO object * - * @param {import('./index.js').gettextTranslations} table Translation object + * @param {import('./index.d.ts').GetTextTranslations} table Translation object * @return {Buffer} Compiled binary MO object */ export default function (table) { @@ -20,10 +20,10 @@ export default function (table) { * Creates a MO compiler object. * * @constructor - * @param {import('./index.js').gettextTranslations} table Translation table as defined in the README - * @return {import('./index.js').Compiler} Compiler + * @param {import('./index.d.ts').GetTextTranslations} table Translation table as defined in the README + * @return {import('./index.d.ts').Compiler} Compiler */ -function Compiler (table ) { +function Compiler (table = {}) { this._table = table; let { headers = {}, translations = {} } = this._table; @@ -71,8 +71,6 @@ function Compiler (table ) { this._writeFunc = 'writeUInt32LE'; this._handleCharset(); - - return this; } /** @@ -151,7 +149,7 @@ Compiler.prototype._generateList = function () { /** * Calculate buffer size for the final binary object * - * @param {import('./index.js').GettextTranslations} 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) { @@ -186,7 +184,7 @@ Compiler.prototype._calculateSize = function (list) { /** * Generates the binary MO object from the translation list * - * @param {import('./index.js').GettextTranslations} list translation list + * @param {import('./index.d.ts').GetTextTranslations} list translation list * @param {Object} size Byte size information * @return {Buffer} Compiled MO object */ @@ -240,7 +238,7 @@ Compiler.prototype._build = function (list, size) { }; /** - * Compiles the translation object into a binary MO object + * Compiles translation object into a binary MO object * * @return {Buffer} Compiled MO object */ diff --git a/src/moparser.js b/lib/moparser.js similarity index 100% rename from src/moparser.js rename to lib/moparser.js diff --git a/src/pocompiler.js b/lib/pocompiler.js similarity index 97% rename from src/pocompiler.js rename to lib/pocompiler.js index 61a229f..f35e663 100644 --- a/src/pocompiler.js +++ b/lib/pocompiler.js @@ -1,6 +1,8 @@ -import { compareMsgid, foldLine, formatCharset, generateHeader, HEADERS } from './shared.js'; -import contentType from 'content-type'; +import { Buffer } from 'safe-buffer'; import encoding from 'encoding'; +import { HEADERS, foldLine, compareMsgid, formatCharset, generateHeader } from './shared.js'; +import contentType from 'content-type'; + /** * Exposes general compiler function. Takes a translation @@ -72,7 +74,7 @@ function Compiler (table = {}, options = {}) { * @param {Object} comments A comments object * @return {String} A comment string for the PO file */ -Compiler.prototype._drawComments = function (comments){ +Compiler.prototype._drawComments = function (comments) { const lines = []; const types = [{ key: 'translator', diff --git a/src/poparser.js b/lib/poparser.js similarity index 99% rename from src/poparser.js rename to lib/poparser.js index 28af5dd..0b9f403 100644 --- a/src/poparser.js +++ b/lib/poparser.js @@ -68,7 +68,7 @@ Parser.prototype.parse = function () { /** * Detects charset for PO strings from the header * - * @param buf PO string buffer to be parsed + * @param {Buffer} buf headers Header value */ Parser.prototype._handleCharset = function (buf = '') { const str = buf.toString(); diff --git a/src/shared.js b/lib/shared.js similarity index 100% rename from src/shared.js rename to lib/shared.js diff --git a/package.json b/package.json index 08cadbe..90d8e11 100644 --- a/package.json +++ b/package.json @@ -17,24 +17,15 @@ "engines": { "node": ">=18" }, - "files": [ - "lib", - "test", - "*.json", - "*.md", - "license.txt" - ], "scripts": { - "start": "tsc --watch", - "build": "tsc", - "lint": "eslint src/*.js test/*.js", + "lint": "eslint lib/*.js test/*.js index.js", "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": "./lib/index.js", - "types": "./lib/index.d.ts", + "main": "./index.js", "license": "MIT", "dependencies": { "content-type": "^1.0.5", @@ -46,15 +37,16 @@ "@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.1.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.4.0", + "mocha": "^10.3.0", "typescript": "^5.4.4" }, "keywords": [ diff --git a/test/mo-compiler-test.js b/test/mo-compiler-test.js index 6405d7a..4796425 100644 --- a/test/mo-compiler-test.js +++ b/test/mo-compiler-test.js @@ -1,7 +1,7 @@ import * as chai from 'chai'; import { promisify } from 'util'; import path from 'path'; -import { mo } from '../src/index.js'; +import { mo } from '../index.js'; import { readFile as fsReadFile } from 'fs'; import { fileURLToPath } from 'url'; diff --git a/test/mo-parser-test.js b/test/mo-parser-test.js index cf569dc..723368a 100644 --- a/test/mo-parser-test.js +++ b/test/mo-parser-test.js @@ -1,7 +1,7 @@ import * as chai from 'chai'; import { promisify } from 'util'; import path from 'path'; -import { mo } from '../src/index.js'; +import { mo } from '../index.js'; import { readFile as fsReadFile } from 'fs'; import { fileURLToPath } from 'url'; diff --git a/test/module.mjs b/test/module.mjs index b1b48b0..1796fd6 100644 --- a/test/module.mjs +++ b/test/module.mjs @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { po, mo } from '../src/index.js'; +import { po, mo } from '../index.js'; describe('esm module', () => { it('should allow named imports', () => { diff --git a/test/po-compiler-test.js b/test/po-compiler-test.js index 07000a9..18ad149 100644 --- a/test/po-compiler-test.js +++ b/test/po-compiler-test.js @@ -3,7 +3,7 @@ import { promisify } from 'util'; import path from 'path'; import { readFile as fsReadFile } from 'fs'; import * as chai from 'chai'; -import { po } from '../src/index.js'; +import { po } from '../index.js'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); diff --git a/test/po-obsolete-test.js b/test/po-obsolete-test.js index 10ec59d..f0e696f 100644 --- a/test/po-obsolete-test.js +++ b/test/po-obsolete-test.js @@ -3,7 +3,7 @@ import * as chai from 'chai'; import { promisify } from 'util'; import path from 'path'; import fs from 'fs'; -import * as gettextParser from '../src/index.js'; +import * as gettextParser from '../index.js'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); diff --git a/test/po-parser-test.js b/test/po-parser-test.js index 89b9e95..3a006c1 100644 --- a/test/po-parser-test.js +++ b/test/po-parser-test.js @@ -2,7 +2,7 @@ import * as chai from 'chai'; import { promisify } from 'util'; import path from 'path'; import fs from 'fs'; -import * as gettextParser from '../src/index.js'; +import * as gettextParser from '../index.js'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); diff --git a/test/shared.js b/test/shared.js index 7ca0a81..c40dfd6 100644 --- a/test/shared.js +++ b/test/shared.js @@ -3,7 +3,7 @@ import * as chai from 'chai'; import { promisify } from 'util'; import path from 'path'; -import { formatCharset, parseHeader, generateHeader, foldLine, parseNPluralFromHeadersSafely } from '../src/shared.js'; +import { formatCharset, parseHeader, generateHeader, foldLine, parseNPluralFromHeadersSafely } from '../lib/shared.js'; import { readFile as fsReadFile } from 'fs'; import { fileURLToPath } from 'url'; diff --git a/tsconfig.json b/tsconfig.json index 1b7d1bd..1564f0f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,36 +2,35 @@ "compilerOptions": { "noImplicitAny": true, "removeComments": false, - "module": "ESNext", - "moduleResolution": "Node", - "target": "ES2021", - "declaration": true, - "emitDeclarationOnly": false, - "preserveConstEnums": true, - "sourceMap": true, - "strict": false, + "module": "Node16", + "moduleResolution": "Node16", + "target": "ES2015", + + // Strict mode + "strict": true, + + // Allow javascript files "allowJs": true, - "downlevelIteration": true, - "esModuleInterop": true, - "skipLibCheck": true, - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "rootDir": "src", - "outDir": "lib", + + // 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, - // types - "typeRoots": [ - "src/types.d.ts", - "node_modules/@types", - "@types" - ], - "lib": [ - "dom", - "ESNext" - ] + // Skip lib check when compiling + "skipLibCheck": true }, "include": [ - "./src/**/*" + "lib/**/*.js", + "index.d.ts" ] } From 8306b11e85991d4ad2e7153b123280af233afbc6 Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Mon, 15 Apr 2024 18:51:52 +0200 Subject: [PATCH 7/9] revert types changes --- lib/mocompiler.js | 2 +- lib/moparser.js | 4 ++-- lib/pocompiler.js | 4 +--- lib/poparser.js | 14 ++++++-------- lib/shared.js | 4 ---- package.json | 1 + 6 files changed, 11 insertions(+), 18 deletions(-) diff --git a/lib/mocompiler.js b/lib/mocompiler.js index 9e8747d..0563fd6 100644 --- a/lib/mocompiler.js +++ b/lib/mocompiler.js @@ -14,7 +14,7 @@ export default function (table) { const compiler = new Compiler(table); return compiler.compile(); -} +}; /** * Creates a MO compiler object. diff --git a/lib/moparser.js b/lib/moparser.js index 1289f24..09c10f8 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. @@ -135,7 +135,7 @@ Parser.prototype._handleCharset = function (headers) { * Adds a translation to the translation object * * @param {String} msgid Original string - * @param {String} msgstr Translation for the original string + * @params {String} msgstr Translation for the original string */ Parser.prototype._addString = function (msgid, msgstr) { const translation = {}; diff --git a/lib/pocompiler.js b/lib/pocompiler.js index f35e663..f4baa0a 100644 --- a/lib/pocompiler.js +++ b/lib/pocompiler.js @@ -3,20 +3,18 @@ import encoding from 'encoding'; import { HEADERS, foldLine, compareMsgid, formatCharset, generateHeader } from './shared.js'; import contentType from 'content-type'; - /** * Exposes general compiler function. Takes a translation * object as a parameter and returns PO object * * @param {Object} table Translation object - * @param options * @return {Buffer} Compiled PO object */ 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 0b9f403..7a77e39 100644 --- a/lib/poparser.js +++ b/lib/poparser.js @@ -1,5 +1,5 @@ import encoding from 'encoding'; -import { formatCharset, parseHeader, parseNPluralFromHeadersSafely } from './shared.js'; +import { formatCharset, parseNPluralFromHeadersSafely, parseHeader } from './shared.js'; import { Transform } from 'readable-stream'; import util from 'util'; @@ -14,7 +14,7 @@ export function parse (input, options = {}) { const parser = new Parser(input, options); return parser.parse(); -} +}; /** * Parses a PO stream, emits translation table in object mode @@ -25,7 +25,7 @@ export function parse (input, options = {}) { */ export function stream (options = {}, transformOptions = {}) { return new PoParserTransform(options, transformOptions); -} +}; /** * Creates a PO parser object. If PO object is a string, @@ -68,7 +68,7 @@ Parser.prototype.parse = function () { /** * Detects charset for PO strings from the header * - * @param {Buffer} buf headers Header value + * @param {Buffer} headers Header value */ Parser.prototype._handleCharset = function (buf = '') { const str = buf.toString(); @@ -77,8 +77,8 @@ Parser.prototype._handleCharset = function (buf = '') { let match; if ((pos = str.search(/^\s*msgid/im)) >= 0) { - pos = pos + str.substring(pos + 5).search(/^\s*(msgid|msgctxt)/im); - headers = str.substring(0, pos >= 0 ? pos + 5 : str.length); + pos = pos + str.substr(pos + 5).search(/^\s*(msgid|msgctxt)/im); + headers = str.substr(0, pos >= 0 ? pos + 5 : str.length); } if ((match = headers.match(/[; ]charset\s*=\s*([\w-]+)(?:[\s;]|\\n)*"\s*$/mi))) { @@ -533,8 +533,6 @@ function PoParserTransform (options, transformOptions) { Transform.call(this, transformOptions); this._writableState.objectMode = false; this._readableState.objectMode = true; - - return this; } util.inherits(PoParserTransform, Transform); diff --git a/lib/shared.js b/lib/shared.js index c1da72a..5e2d3a5 100644 --- a/lib/shared.js +++ b/lib/shared.js @@ -1,7 +1,5 @@ // see https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html - const PLURAL_FORMS = 'Plural-Forms'; - export const HEADERS = new Map([ ['project-id-version', 'Project-Id-Version'], ['report-msgid-bugs-to', 'Report-Msgid-Bugs-To'], @@ -45,7 +43,6 @@ export function parseHeader (str = '') { * Attempts to safely parse 'nplurals" value from "Plural-Forms" header * * @param {Object} [headers = {}] An object with parsed headers - * @param fallback {Number} Fallback value * @returns {number} Parsed result */ export function parseNPluralFromHeadersSafely (headers, fallback = 1) { @@ -86,7 +83,6 @@ export function generateHeader (header = {}) { * Normalizes charset name. Converts utf8 to utf-8, WIN1257 to windows-1257 etc. * * @param {String} charset Charset name - * @param defaultCharset Default charset (default: 'iso-8859-1') * @return {String} Normalized charset name */ export function formatCharset (charset = 'iso-8859-1', defaultCharset = 'iso-8859-1') { diff --git a/package.json b/package.json index 90d8e11..dfc5bba 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "prepublish": "tsc && npm run lint && npm run test" }, "main": "./index.js", + "types": "./index.d.ts", "license": "MIT", "dependencies": { "content-type": "^1.0.5", From 889a7eaf73be86487fd9588369afaf7ede185185 Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Mon, 15 Apr 2024 22:52:41 +0200 Subject: [PATCH 8/9] exporting default types (this is a monkey patching that manually exports the types, because index.js is in the repo root) fix msg_plural that despite the name is a "string" and not a "string[]" --- index.d.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 522d3ee..d47b72b 100644 --- a/index.d.ts +++ b/index.d.ts @@ -22,7 +22,7 @@ export interface GetTextComment { export interface GetTextTranslation { msgctxt?: string; msgid: string; - msgid_plural?: string[]; + msgid_plural?: string; msgstr: string[]; comments?: GetTextComment; } @@ -48,3 +48,7 @@ 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 }; From 822331403fe8481dd189908db59f0e87e2df5992 Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Tue, 30 Apr 2024 13:04:33 +0200 Subject: [PATCH 9/9] fixes eslint warnings --- lib/mocompiler.js | 2 +- lib/moparser.js | 2 +- lib/pocompiler.js | 2 +- lib/poparser.js | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/mocompiler.js b/lib/mocompiler.js index 0563fd6..9e8747d 100644 --- a/lib/mocompiler.js +++ b/lib/mocompiler.js @@ -14,7 +14,7 @@ export default function (table) { const compiler = new Compiler(table); return compiler.compile(); -}; +} /** * Creates a MO compiler 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 7a77e39..70cce36 100644 --- a/lib/poparser.js +++ b/lib/poparser.js @@ -14,7 +14,7 @@ export function parse (input, options = {}) { const parser = new Parser(input, options); return parser.parse(); -}; +} /** * Parses a PO stream, emits translation table in object mode @@ -25,7 +25,7 @@ export function parse (input, options = {}) { */ export function stream (options = {}, transformOptions = {}) { return new PoParserTransform(options, transformOptions); -}; +} /** * Creates a PO parser object. If PO object is a string,