From e61e535a7969d0f676f6bad0e28295ebd3627c1b Mon Sep 17 00:00:00 2001 From: Ruben Vermeersch Date: Mon, 16 Dec 2013 16:36:32 +0100 Subject: [PATCH] Add JSHint. Fix style and some potential bugs. --- .gitignore | 1 + .jshintrc | 14 ++ Gruntfile.coffee | 18 +++ lib/po.js | 363 ++++++++++++++++++++++++----------------------- package.json | 31 ++-- 5 files changed, 240 insertions(+), 187 deletions(-) create mode 100644 .gitignore create mode 100644 .jshintrc create mode 100644 Gruntfile.coffee diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..07e6e47 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/node_modules diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..9021e97 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,14 @@ +{ + "curly": true, + "eqeqeq": true, + "immed": true, + "latedef": true, + "newcap": true, + "noarg": true, + "sub": true, + "undef": true, + "boss": true, + "eqnull": true, + "node": true, + "white": true +} diff --git a/Gruntfile.coffee b/Gruntfile.coffee new file mode 100644 index 0000000..731a845 --- /dev/null +++ b/Gruntfile.coffee @@ -0,0 +1,18 @@ +module.exports = (grunt) -> + @loadNpmTasks('grunt-contrib-jshint') + @loadNpmTasks('grunt-contrib-watch') + + @initConfig + jshint: + all: [ 'lib/*.js' ] + options: + jshintrc: '.jshintrc' + + watch: + all: + files: ['lib/**.js', 'test/*/*'] + tasks: ['test'] + + @registerTask 'default', ['test'] + @registerTask 'build', ['jshint'] + @registerTask 'test', ['build'] diff --git a/lib/po.js b/lib/po.js index 87133b5..4a7d733 100644 --- a/lib/po.js +++ b/lib/po.js @@ -1,207 +1,214 @@ -var fs = require('fs') - , util = require('util'); +var fs = require('fs'), + util = require('util'); function trim(string) { - return string.replace(/^\s+|\s+$/g, ''); + return string.replace(/^\s+|\s+$/g, ''); +} + +var PO = function () { + this.comments = []; + this.headers = {}; + this.items = []; }; -var PO = function() { - this.comments = []; - this.headers = {}; - this.items = []; -}; +PO.prototype.save = function (filename, callback) { + fs.writeFile(filename, this.toString(), function (err) { + if (err) { + throw err; + } -PO.prototype.save = function(filename, callback) { - fs.writeFile(filename, this.toString(), function(err) { - if (err) throw err; - callback && callback(); - }); -}; - -PO.prototype.toString = function() { - var lines = [] - , that = this; - - if (this.comments) { - this.comments.forEach(function(comment) { - lines.push('# ' + comment); + if (callback) { + callback(); + } }); - } +}; - lines.push('msgid ""'); - lines.push('msgstr ""'); +PO.prototype.toString = function () { + var lines = [], + that = this; - var keys = Object.keys(this.headers); - keys.forEach(function(key) { - lines.push(util.format('"%s: %s\\n"', key, that.headers[key])); - }); + if (this.comments) { + this.comments.forEach(function (comment) { + lines.push('# ' + comment); + }); + } - lines.push(''); + lines.push('msgid ""'); + lines.push('msgstr ""'); + + var keys = Object.keys(this.headers); + keys.forEach(function (key) { + lines.push(util.format('"%s: %s\\n"', key, that.headers[key])); + }); - this.items.forEach(function(item) { - lines.push(item.toString()); lines.push(''); - }); - return lines.join("\n"); + this.items.forEach(function (item) { + lines.push(item.toString()); + lines.push(''); + }); + + return lines.join("\n"); }; -PO.load = function(filename, callback) { - fs.readFile(filename, 'utf-8', function(err, data) { - if (err) throw err; - var po = PO.parse(data); - callback && callback(po); - }); +PO.load = function (filename, callback) { + fs.readFile(filename, 'utf-8', function (err, data) { + if (err) { + throw err; + } + var po = PO.parse(data); + callback(po); + }); }; -PO.parse = function(data) { +PO.parse = function (data) { //support both unix and windows newline formats. data = data.replace(/\r\n/g, '\n'); - var po = new PO - , sections = data.split(/\n\n/) - , headers = sections.shift() - , lines = sections.join("\n").split(/\n/); + var po = new PO(), + sections = data.split(/\n\n/), + headers = sections.shift(), + lines = sections.join("\n").split(/\n/); - po.headers = { - 'Project-Id-Version': '', - 'Report-Msgid-Bugs-To': '', - 'POT-Creation-Date': '', - 'PO-Revision-Date': '', - 'Last-Translator': '', - 'Language': '', - 'Language-Team': '', - 'Content-Type': '', - 'Content-Transfer-Encoding': '', - 'Plural-Forms': '', - }; + po.headers = { + 'Project-Id-Version': '', + 'Report-Msgid-Bugs-To': '', + 'POT-Creation-Date': '', + 'PO-Revision-Date': '', + 'Last-Translator': '', + 'Language': '', + 'Language-Team': '', + 'Content-Type': '', + 'Content-Transfer-Encoding': '', + 'Plural-Forms': '', + }; - headers.split(/\n/).forEach(function(header) { - if (header.match(/^#/)) { - po.comments.push(header.replace(/^#\s*/, '')); - } - if (header.match(/^"/)) { - header = header.trim().replace(/^"/, '').replace(/\\n"$/, ''); - var p = header.split(/:/) - , name = p.shift().trim() - , value = p.join(':').trim(); - po.headers[name] = value; - } - }); - - var item = new PO.Item() - , context = null - , plural = 0; - - function finish() { - if (item.msgid.length > 0) { - po.items.push(item); - item = new PO.Item(); - } - }; - - function extract(string) { - string = trim(string); - string = string.replace(/^[^"]*"|"$/g, ''); - string = string.replace(/\\"/g, '"'); - string = string.replace(/\\\\/g, '\\'); - return string; - }; - - while (lines.length > 0) { - var line = trim(lines.shift()) - , add = false; - if (line.match(/^#:/)) { // Reference - finish(); - item.references.push(trim(line.replace(/^#:/, ''))); - } - else if (line.match(/^#/)) { // Comment - finish(); - item.comments.push(trim(line.replace(/^#/, ''))); - } - else if (line.match(/^msgid_plural/)) { // Plural form - item.msgid_plural = extract(line); - context = 'msgid_plural'; - } - else if (line.match(/^msgid/)) { // Original - finish(); - item.msgid = extract(line); - context = 'msgid'; - } - else if (line.match(/^msgstr/)) { // Translation - var m = line.match(/^msgstr\[(\d+)\]/); - plural = m && m[1] ? parseInt(m[1]) : 0; - item.msgstr[plural] = extract(line); - context = 'msgstr' - } - else { // Probably multiline string or blank - if (line.length > 0) { - if (context == 'msgstr') { - item.msgstr[plural] += extract(line); + headers.split(/\n/).forEach(function (header) { + if (header.match(/^#/)) { + po.comments.push(header.replace(/^#\s*/, '')); } - else if (context == 'msgid') { - item.msgid += extract(line); + if (header.match(/^"/)) { + header = header.trim().replace(/^"/, '').replace(/\\n"$/, ''); + var p = header.split(/:/), + name = p.shift().trim(), + value = p.join(':').trim(); + po.headers[name] = value; } - else if (context == 'msgid_plural') { - item.msgid_plural += extract(line); - } - } - } - }; - finish(); - - return po; -}; - -PO.Item = function() { - this.msgid = ''; - this.references = []; - this.msgid_plural = null; - this.msgstr = []; - this.comments = []; -}; - -PO.Item.prototype.toString = function() { - var lines = [] - , that = this; - - var _process = function(keyword, text, i) { - var lines = [] - , parts = text.split(/\n/) - , index = typeof i != 'undefined' ? util.format('[%d]', i) : ''; - if (parts.length > 1) { - lines.push(util.format('%s%s ""', keyword, index)); - parts.forEach(function(part) { - lines.push(util.format('"%s"', part)) - }); - } - else { - lines.push(util.format('%s%s "%s"', keyword, index, text)); - } - return lines; - } - - if (this.references.length > 0) { - this.references.forEach(function(ref) { - lines.push(util.format('#: %s', ref)); }); - }; - ['msgid', 'msgid_plural', 'msgstr'].forEach(function(keyword) { - var text = that[keyword]; - if (text != null) { - if (util.isArray(text) && text.length > 1) { - text.forEach(function(t, i) { - lines = lines.concat(_process(keyword, t, i)); - }); - } - else { - text = util.isArray(text) ? text.join() : text; - lines = lines.concat(_process(keyword, text)); - } + var item = new PO.Item(), + context = null, + plural = 0; + + function finish() { + if (item.msgid.length > 0) { + po.items.push(item); + item = new PO.Item(); + } } - }); - return lines.join("\n"); + function extract(string) { + string = trim(string); + string = string.replace(/^[^"]*"|"$/g, ''); + string = string.replace(/\\"/g, '"'); + string = string.replace(/\\\\/g, '\\'); + return string; + } + + while (lines.length > 0) { + var line = trim(lines.shift()), + add = false; + if (line.match(/^#:/)) { // Reference + finish(); + item.references.push(trim(line.replace(/^#:/, ''))); + } + else if (line.match(/^#/)) { // Comment + finish(); + item.comments.push(trim(line.replace(/^#/, ''))); + } + else if (line.match(/^msgid_plural/)) { // Plural form + item.msgid_plural = extract(line); + context = 'msgid_plural'; + } + else if (line.match(/^msgid/)) { // Original + finish(); + item.msgid = extract(line); + context = 'msgid'; + } + else if (line.match(/^msgstr/)) { // Translation + var m = line.match(/^msgstr\[(\d+)\]/); + plural = m && m[1] ? parseInt(m[1]) : 0; + item.msgstr[plural] = extract(line); + context = 'msgstr'; + } + else { // Probably multiline string or blank + if (line.length > 0) { + if (context === 'msgstr') { + item.msgstr[plural] += extract(line); + } + else if (context === 'msgid') { + item.msgid += extract(line); + } + else if (context === 'msgid_plural') { + item.msgid_plural += extract(line); + } + } + } + } + finish(); + + return po; +}; + +PO.Item = function () { + this.msgid = ''; + this.references = []; + this.msgid_plural = null; + this.msgstr = []; + this.comments = []; +}; + +PO.Item.prototype.toString = function () { + var lines = [], + that = this; + + var _process = function (keyword, text, i) { + var lines = [], + parts = text.split(/\n/), + index = typeof i !== 'undefined' ? util.format('[%d]', i) : ''; + if (parts.length > 1) { + lines.push(util.format('%s%s ""', keyword, index)); + parts.forEach(function (part) { + lines.push(util.format('"%s"', part)); + }); + } + else { + lines.push(util.format('%s%s "%s"', keyword, index, text)); + } + return lines; + }; + + if (this.references.length > 0) { + this.references.forEach(function (ref) { + lines.push(util.format('#: %s', ref)); + }); + } + + ['msgid', 'msgid_plural', 'msgstr'].forEach(function (keyword) { + var text = that[keyword]; + if (text != null) { + if (util.isArray(text) && text.length > 1) { + text.forEach(function (t, i) { + lines = lines.concat(_process(keyword, t, i)); + }); + } + else { + text = util.isArray(text) ? text.join() : text; + lines = lines.concat(_process(keyword, text)); + } + } + }); + + return lines.join("\n"); }; module.exports = PO; diff --git a/package.json b/package.json index 27282b6..e4b0be9 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,24 @@ { - "name" : "node-po", - "description" : "Simple library for loading and saving Gettext PO files.", - "version" : "0.1.1", - "author" : "Mike Holly", - "homepage" : "http://github.com/mikejholly/node-po", - "repository" : {"type" : "git", "url" : "http://github.com/mikejholly/node-po.git"}, - "dependencies" : [], - "main" : "./lib/po", - "keywords" : ["i18n", "l10n", "gettext", "mo", "po"] + "name": "node-po", + "description": "Simple library for loading and saving Gettext PO files.", + "version": "0.1.1", + "author": "Mike Holly", + "homepage": "http://github.com/mikejholly/node-po", + "repository": { + "type": "git", + "url": "http://github.com/mikejholly/node-po.git" + }, + "main": "./lib/po", + "keywords": [ + "i18n", + "l10n", + "gettext", + "mo", + "po" + ], + "devDependencies": { + "grunt": "~0.4.2", + "grunt-contrib-watch": "~0.5.3", + "grunt-contrib-jshint": "~0.7.2" + } }