Socket
Socket
Sign inDemoInstall

grunt-banana-checker

Package Overview
Dependencies
Maintainers
2
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

grunt-banana-checker - npm Package Compare versions

Comparing version 0.2.2 to 0.3.0

test/disallowEmptyDocumentation/en.json

24

Gruntfile.js

@@ -37,2 +37,26 @@ /*!

}
},
disallowEmptyDocumentation: {
src: 'test/disallowEmptyDocumentation',
options: {
disallowEmptyDocumentation: false
}
},
disallowUnusedDocumentation: {
src: 'test/disallowUnusedDocumentation',
options: {
disallowUnusedDocumentation: false
}
},
requireCompleteMessageDocumentation: {
src: 'test/requireCompleteMessageDocumentation',
options: {
requireCompleteMessageDocumentation: false
}
},
requireMetadata: {
src: 'test/requireMetadata',
options: {
requireMetadata: false
}
}

@@ -39,0 +63,0 @@ },

# grunt-banana-checker Release History
## v0.3.0 / 2015-09-01
* Fail if the target directory doesn't exist (James D. Forrester)
* Allow individual checks to be disabled in config (James D. Forrester)
* Be able to require complete translations, or specific messages in all translations (James D. Forrester)
* build: Bump grunt-jscs to latest version (James D. Forrester)
* Enforce disallowBlankTranslations, disallowDuplicateTranslations and disallowUnusedTranslations (James D. Forrester)
## v0.2.2 / 2015-06-05

@@ -4,0 +11,0 @@ * Fix off-by-one error in counting the number of messages (Kunal Mehta)

4

package.json
{
"name": "grunt-banana-checker",
"version": "0.2.2",
"version": "0.3.0",
"description": "A grunt checker for the \"banana\" JSON i18n system provided by MediaWiki and jquery.i18n",

@@ -27,4 +27,4 @@ "scripts": {

"grunt-contrib-watch": "0.6.1",
"grunt-jscs": "1.8.0"
"grunt-jscs": "2.1.0"
}
}

@@ -37,3 +37,3 @@ [![NPM version](https://badge.fury.io/js/grunt-banana-checker.svg)](http://badge.fury.io/js/grunt-banana-checker) [![Build Status](https://travis-ci.org/wikimedia/grunt-banana-checker.svg?branch=master)](https://travis-ci.org/wikimedia/grunt-banana-checker)

### sourceFile
#### sourceFile
Type: `string`

@@ -44,3 +44,3 @@ Default value: `"en.json"`

### documentationFile
#### documentationFile
Type: `string`

@@ -51,3 +51,59 @@ Default value: `"qqq.json"`

#### requireMetadata
Type: `boolean`
Default value: `true`
Whether to fail if message files don't have a `@metadata` meta-data key.
#### requireCompleteMessageDocumentation
Type: `boolean`
Default value: `true`
Whether to fail if any message is in the primary file but not documented.
#### disallowEmptyDocumentation
Type: `boolean`
Default value: `true`
Whether to fail if any message is in the primary file but documented as a blank string.
#### disallowUnusedDocumentation
Type: `boolean`
Default value: `true`
Whether to fail if any documented message isn't in the primary file.
#### disallowBlankTranslations
Type: `boolean`
Default value: `true`
Whether to fail if any message is translated as a blank string.
#### disallowDuplicateTranslations
Type: `boolean`
Default value: `true`
Whether to fail if any message is translated as identical to the original string.
#### disallowUnusedTranslations
Type: `boolean`
Default value: `true`
Whether to fail if any translated message isn't in the primary file.
#### requireCompleteTranslationLanguages
Type: `string[]`
Default value: `[]`
Example value: `[ 'fr', 'es' ]`
Languages on which to fail if any message in the primary file is missing.
#### requireCompleteTranslationMessages
Type: `string[]`
Default value: `[]`
Example value: `[ 'first-message-key', 'third-message-key' ]`
Messages on which to fail if missing in any provided language.
Example uses

@@ -54,0 +110,0 @@ --------------------

@@ -8,52 +8,147 @@ /*!

grunt.registerMultiTask( 'banana', function () {
var path = require( 'path' ),
var ok,
path = require( 'path' ),
fs = require( 'fs' ),
options = this.options( {
sourceFile: 'en.json',
documentationFile: 'qqq.json'
documentationFile: 'qqq.json',
requireMetadata: true,
requireCompleteMessageDocumentation: true,
disallowUnusedDocumentation: true,
disallowBlankTranslations: true,
disallowDuplicateTranslations: true,
disallowUnusedTranslations: true,
requireCompleteTranslationLanguages: [],
requireCompleteTranslationMessages: []
} ),
messageCount = 0,
ok = true;
messageCount = 0;
if ( this.filesSrc.length === 0 ) {
grunt.log.error( 'Target directory does not exist.' );
return false;
}
ok = true;
this.filesSrc.forEach( function ( dir ) {
var documentationMessagesMetadataIndex,
sourceMessagesMetadataIndex,
message,
documentationIndex,
documentationMessages = grunt.file.readJSON( path.resolve( dir, options.documentationFile ) ),
documentationMessageKeys = Object.keys( documentationMessages ),
var message, index, offset,
// Source message data
sourceMessages, sourceMessageKeys,
// Documentation message data
documentationMessages, documentationMessageKeys,
// Translated message data
translatedFiles,
translatedData = {},
documentationMessageBlanks = [],
sourceMessageMissing = [],
sourceMessages = grunt.file.readJSON( path.resolve( dir, options.sourceFile ) ),
sourceMessageKeys = Object.keys( sourceMessages ),
count = 0;
sourceMessagesMetadataIndex = sourceMessageKeys.indexOf( '@metadata' );
if ( sourceMessagesMetadataIndex === -1 ) {
grunt.log.error( 'Source file lacks a metadata block.' );
ok = false;
return;
function messages( filename, type ) {
var messageArray;
try {
messageArray = grunt.file.readJSON( path.resolve( dir, filename ) );
} catch ( e ) {
grunt.log.error( 'Loading ' + type + ' messages failed: "' + e + '".' );
ok = false;
throw e;
}
return messageArray;
}
sourceMessageKeys.splice( sourceMessagesMetadataIndex, 1 );
function keysNoMetadata( messageArray, type ) {
var keys, offset;
try {
keys = Object.keys( messageArray );
} catch ( e ) {
grunt.log.error( 'Loading ' + type + ' messages failed: "' + e + '".' );
ok = false;
throw e;
}
offset = keys.indexOf( '@metadata' );
if ( offset === -1 ) {
if ( options.requireMetadata ) {
grunt.log.error( 'No metadata block in the ' + type + ' messages file.' );
ok = false;
}
} else {
keys.splice( offset, 1 );
}
return keys;
}
sourceMessages = messages( options.sourceFile, 'source' );
sourceMessageKeys = keysNoMetadata( sourceMessages, 'source' );
documentationMessages = messages( options.documentationFile, 'documentation' );
documentationMessageKeys = keysNoMetadata( documentationMessages, 'documentation' );
// Count after @metadata is removed
messageCount += sourceMessageKeys.length;
documentationMessagesMetadataIndex = documentationMessageKeys.indexOf( '@metadata' );
if ( documentationMessagesMetadataIndex === -1 ) {
grunt.log.error( 'Documentation file lacks a metadata block.' );
ok = false;
return;
}
documentationMessageKeys.splice( documentationMessagesMetadataIndex, 1 );
translatedFiles = fs.readdirSync( dir ).filter( function ( value ) {
return (
value !== options.sourceFile &&
value !== options.documentationFile &&
value.match( /.*.json/ )
);
} );
translatedFiles.forEach( function ( languageFile ) {
var language = languageFile.match( /(.*)\.json$/ )[ 1 ],
languageMesages = messages( languageFile, language ),
keys = keysNoMetadata( languageMesages, language ),
blanks = [],
duplicates = [],
unuseds = [],
missing = sourceMessageKeys.slice( 0 );
for ( index in keys ) {
message = keys[ index ];
if ( missing.indexOf( message ) !== -1 ) {
if ( languageMesages[ message ] === sourceMessages[ message ] ) {
duplicates.push( message );
}
missing.splice( missing.indexOf( message ), 1 );
} else {
unuseds.push( message );
}
if ( typeof languageMesages[ message ] !== 'string' ) {
continue;
}
if ( languageMesages[ message ].trim() === '' ) {
blanks.push( message );
}
}
translatedData[ language ] = {
messages: languageMesages,
keys: keys,
blank: blanks,
duplicate: duplicates,
unused: unuseds,
missing: missing
};
} );
while ( sourceMessageKeys.length > 0 ) {
message = sourceMessageKeys[0];
documentationIndex = documentationMessageKeys.indexOf( message );
message = sourceMessageKeys[ 0 ];
if ( documentationIndex !== -1 ) {
offset = documentationMessageKeys.indexOf( message );
if ( documentationMessages[message].trim() === '' ) {
if ( offset !== -1 ) {
if ( documentationMessages[ message ].trim() === '' ) {
documentationMessageBlanks.push( message );
}
documentationMessageKeys.splice( documentationIndex, 1 );
documentationMessageKeys.splice( offset, 1 );
} else {

@@ -65,40 +160,152 @@ sourceMessageMissing.push( message );

count = sourceMessageMissing.length;
if ( count > 0 ) {
ok = false;
if ( options.requireCompleteMessageDocumentation ) {
count = sourceMessageMissing.length;
if ( count > 0 ) {
ok = false;
grunt.log.error(
count + ' message' + ( count > 1 ? 's lack' : ' lacks' ) + ' documentation.'
);
grunt.log.error(
count + ' message' + ( count > 1 ? 's lack' : ' lacks' ) + ' documentation.'
);
sourceMessageMissing.forEach( function ( message ) {
grunt.log.error( 'Message "' + message + '" lacks documentation.' );
} );
sourceMessageMissing.forEach( function ( message ) {
grunt.log.error( 'Message "' + message + '" lacks documentation.' );
} );
}
}
count = documentationMessageBlanks.length;
if ( count > 0 ) {
ok = false;
if ( options.disallowEmptyDocumentation ) {
count = documentationMessageBlanks.length;
if ( count > 0 ) {
ok = false;
grunt.log.error(
count + ' documented message' + ( count > 1 ? 's are' : ' is' ) + ' blank.'
);
grunt.log.error(
count + ' documented message' + ( count > 1 ? 's are' : ' is' ) + ' blank.'
);
documentationMessageBlanks.forEach( function ( message ) {
grunt.log.error( 'Message "' + message + '" is documented with a blank string.' );
} );
documentationMessageBlanks.forEach( function ( message ) {
grunt.log.error( 'Message "' + message + '" is documented with a blank string.' );
} );
}
}
count = documentationMessageKeys.length;
if ( count > 0 ) {
ok = false;
if ( options.disallowUnusedDocumentation ) {
count = documentationMessageKeys.length;
if ( count > 0 ) {
ok = false;
grunt.log.error(
count + ' documented message' + ( count > 1 ? 's are' : ' is' ) + ' undefined.'
);
grunt.log.error(
count + ' documented message' + ( count > 1 ? 's are' : ' is' ) + ' undefined.'
);
documentationMessageKeys.forEach( function ( message ) {
grunt.log.error( 'Message "' + message + '" is documented but undefined.' );
} );
documentationMessageKeys.forEach( function ( message ) {
grunt.log.error( 'Message "' + message + '" is documented but undefined.' );
} );
}
}
for ( index in translatedData ) {
if ( !translatedData.hasOwnProperty( index ) ) {
continue;
}
if ( options.disallowBlankTranslations ) {
count = translatedData[ index ].blank.length;
if ( count > 0 ) {
ok = false;
grunt.log.error( 'The "' + index + '" translation has ' + count + ' blank translation' + ( count > 1 ? 's' : '' ) + ':' );
// jshint -W083
translatedData[ index ].blank.forEach( function ( message ) {
grunt.log.error( 'The translation of "' + message + '" is blank.' );
} );
// jshint +W083
}
}
if ( options.disallowDuplicateTranslations ) {
count = translatedData[ index ].duplicate.length;
if ( count > 0 ) {
ok = false;
grunt.log.error( 'The "' + index + '" translation has ' + count + ' duplicate translation' + ( count > 1 ? 's' : '' ) + ':' );
// jshint -W083
translatedData[ index ].duplicate.forEach( function ( message ) {
grunt.log.error( 'The translation of "' + message + '" is a duplicate of the primary message.' );
} );
// jshint +W083
}
}
if ( options.disallowUnusedTranslations ) {
count = translatedData[ index ].unused.length;
if ( count > 0 ) {
ok = false;
grunt.log.error( 'The "' + index + '" translation has ' + count + ' unused translation' + ( count > 1 ? 's' : '' ) + ':' );
// jshint -W083
translatedData[ index ].unused.forEach( function ( message ) {
grunt.log.error( 'The translation of "' + message + '" is unused.' );
} );
// jshint +W083
}
}
}
if ( options.requireCompleteTranslationLanguages.length ) {
for ( index in translatedData ) {
if (
!translatedData.hasOwnProperty( index ) ||
( options.requireCompleteTranslationLanguages.indexOf( index ) === -1 )
) {
continue;
}
count = translatedData[ index ].missing.length;
if ( count > 0 ) {
ok = false;
grunt.log.error( 'The "' + index + '" translation has ' + count + ' missing translation' + ( count > 1 ? 's' : '' ) + ':' );
// jshint -W083
translatedData[ index ].missing.forEach( function ( message ) {
grunt.log.error( 'The translation of "' + message + '" is missing.' );
} );
// jshint +W083
}
}
}
if ( options.requireCompleteTranslationMessages.length ) {
for ( index in translatedData ) {
if ( !translatedData.hasOwnProperty( index ) ) {
continue;
}
for ( message in translatedData[ index ].missing ) {
if ( !translatedData[ index ].missing.hasOwnProperty( sourceMessageKeys[ message ] ) ) {
continue;
}
offset = options.requireCompleteTranslationMessages.indexOf( sourceMessageKeys[ message ] );
if ( offset === -1 ) {
translatedData[ index ].missing.splice( offset, 1 );
}
}
count = translatedData[ index ].missing.length;
if ( count > 0 ) {
ok = false;
grunt.log.error( 'The "' + index + '" translation is missing ' + count + ' required message' + ( count > 1 ? 's' : '' ) + ':' );
// jshint -W083
translatedData[ index ].missing.forEach( function ( message ) {
grunt.log.error( 'The required message "' + message + '" is missing.' );
} );
// jshint +W083
}
}
}
} );

@@ -105,0 +312,0 @@

@@ -9,3 +9,3 @@ {

"third-message-key": "third message definition",
"four-message-key": "four message definition"
}
"fourth-message-key": "fourth message definition"
}

@@ -8,3 +8,3 @@ {

"third-message-key": "third message value",
"four-message-key": "four message value"
}
"fourth-message-key": "fourth message value"
}

@@ -9,3 +9,3 @@ {

"third-message-key": "third message definition",
"four-message-key": "four message definition"
}
"fourth-message-key": "fourth message definition"
}

@@ -8,3 +8,3 @@ {

"third-message-key": "third message value",
"four-message-key": "four message value"
}
"fourth-message-key": "fourth message value"
}

@@ -8,3 +8,3 @@ {

"third-message-key": "third message value",
"four-message-key": "four message value"
}
"fourth-message-key": "fourth message value"
}

@@ -9,3 +9,3 @@ {

"third-message-key": "third message definition",
"four-message-key": "four message definition"
}
"fourth-message-key": "fourth message definition"
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc