grunt-banana-checker
Advanced tools
Comparing version 0.9.0 to 0.10.0
{ | ||
"name": "grunt-banana-checker", | ||
"version": "0.9.0", | ||
"description": "Checker for the 'Banana' JSON-file format for interface messages, as used by MediaWiki and jQuery.i18n.", | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/wikimedia/grunt-banana-checker.git" | ||
}, | ||
"homepage": "https://github.com/wikimedia/grunt-banana-checker", | ||
"keywords": [ | ||
"gruntplugin", | ||
"checker", | ||
"banana" | ||
], | ||
"bin": { | ||
"banana-checker": "src/cli.js" | ||
}, | ||
"files": [ | ||
"src/", | ||
"tasks/" | ||
], | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/wikimedia/grunt-banana-checker/issues" | ||
}, | ||
"main": "src/banana.js", | ||
"engines": { | ||
"node": ">=8" | ||
}, | ||
"devDependencies": { | ||
"eslint-config-wikimedia": "0.15.1", | ||
"nyc": "15.0.1", | ||
"grunt": "1.1.0" | ||
}, | ||
"scripts": { | ||
"test": "nyc node test/test.js && eslint . && grunt banana && ./src/cli.js --requireLowerCase=0 test/simple/ test/requireLowerCase/full/" | ||
}, | ||
"nyc": { | ||
"exclude": [ | ||
"test" | ||
], | ||
"reporter": [ | ||
"text", | ||
"html" | ||
] | ||
} | ||
"name": "grunt-banana-checker", | ||
"version": "0.10.0", | ||
"description": "Checker for the 'Banana' JSON-file format for interface messages, as used by MediaWiki and jQuery.i18n.", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/wikimedia/banana-checker.git" | ||
}, | ||
"homepage": "https://github.com/wikimedia/banana-checker", | ||
"keywords": [ | ||
"gruntplugin", | ||
"checker", | ||
"banana" | ||
], | ||
"bin": { | ||
"banana-checker": "src/cli.js" | ||
}, | ||
"files": [ | ||
"src/", | ||
"tasks/" | ||
], | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/wikimedia/banana-checker/issues" | ||
}, | ||
"main": "src/banana.js", | ||
"engines": { | ||
"node": ">=8" | ||
}, | ||
"devDependencies": { | ||
"eslint-config-wikimedia": "0.22.1", | ||
"nyc": "15.1.0", | ||
"grunt": "1.5.3" | ||
}, | ||
"scripts": { | ||
"test": "nyc node test/test.js && eslint --cache . && grunt banana && ./src/cli.js --requireLowerCase=0 test/simple/ test/requireLowerCase/full/" | ||
}, | ||
"nyc": { | ||
"exclude": [ | ||
"test" | ||
], | ||
"reporter": [ | ||
"text", | ||
"html" | ||
] | ||
} | ||
} |
@@ -213,1 +213,13 @@ [![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/banana-checker.svg?branch=master)](https://travis-ci.org/wikimedia/banana-checker) | ||
Whether to ignore missing translations whose original string is blank. | ||
### allowLeadingWhitespace | ||
Type: `boolean` | ||
Default value: `true` | ||
Whether to ignore leading whitespace in original or translated messages. | ||
### allowTrailingWhitespace | ||
Type: `boolean` | ||
Default value: `true` | ||
Whether to ignore trailing whitespace in original or translated messages. |
'use strict'; | ||
var path = require( 'path' ); | ||
var fs = require( 'fs' ); | ||
const path = require( 'path' ); | ||
const fs = require( 'fs' ); | ||
@@ -16,4 +16,7 @@ /** | ||
module.exports = function bananaChecker( dir, options, logErr ) { | ||
var ok = true; | ||
// Step 1: Read config and get set up. | ||
let ok = true; | ||
options = Object.assign( { | ||
@@ -36,22 +39,16 @@ sourceFile: 'en.json', | ||
allowLeadingWhitespace: true, | ||
allowTrailingWhitespace: true, | ||
skipIncompleteMessageDocumentation: [] | ||
}, options ); | ||
var message, index, offset, | ||
// Source message data | ||
sourceMessages, sourceMessageKeys, | ||
// Documentation message data | ||
documentationMessages, documentationMessageKeys, | ||
// Translated message data | ||
translatedFiles, | ||
jsonFilenameRegex = /(.*)\.json$/, | ||
translatedData = {}, | ||
documentationMessageBlanks = [], | ||
sourceMessageMissing = [], | ||
sourceMessageWrongCase = [], | ||
sourceMessageWrongPrefix = [], | ||
count = 0; | ||
const jsonFilenameRegex = /(.*)\.json$/; | ||
const leadingWhitespaceRegex = /^\s/; | ||
const trailingWhitespaceRegex = /\s$/; | ||
const translatedData = {}; | ||
function messages( filename, type ) { | ||
var messageArray; | ||
let messageArray; | ||
@@ -70,8 +67,7 @@ try { | ||
function keysNoMetadata( messageArray, type ) { | ||
var keys, offset; | ||
const keys = Object.keys( messageArray ); | ||
keys = Object.keys( messageArray ); | ||
const keyOffset = keys.indexOf( '@metadata' ); | ||
offset = keys.indexOf( '@metadata' ); | ||
if ( offset === -1 ) { | ||
if ( keyOffset === -1 ) { | ||
if ( options.requireMetadata ) { | ||
@@ -82,3 +78,3 @@ logErr( `No metadata block in the ${type} messages file.` ); | ||
} else { | ||
keys.splice( offset, 1 ); | ||
keys.splice( keyOffset, 1 ); | ||
} | ||
@@ -89,29 +85,36 @@ | ||
sourceMessages = messages( options.sourceFile, 'source' ); | ||
sourceMessageKeys = keysNoMetadata( sourceMessages, 'source' ); | ||
// Source message data | ||
const sourceMessages = messages( options.sourceFile, 'source' ); | ||
const sourceMessageKeys = keysNoMetadata( sourceMessages, 'source' ); | ||
documentationMessages = messages( options.documentationFile, 'documentation' ); | ||
documentationMessageKeys = keysNoMetadata( documentationMessages, 'documentation' ); | ||
// Documentation message data | ||
const documentationMessages = messages( options.documentationFile, 'documentation' ); | ||
const documentationMessageKeys = keysNoMetadata( documentationMessages, 'documentation' ); | ||
translatedFiles = fs.readdirSync( dir ).filter( function ( value ) { | ||
return ( | ||
value !== options.sourceFile && | ||
value !== options.documentationFile && | ||
value.match( jsonFilenameRegex ) | ||
); | ||
} ); | ||
// Translated message data | ||
const translatedFiles = fs.readdirSync( dir ).filter( ( value ) => | ||
value !== options.sourceFile && | ||
value !== options.documentationFile && | ||
jsonFilenameRegex.test( value ) | ||
); | ||
translatedFiles.forEach( function ( languageFile ) { | ||
var language = languageFile.match( jsonFilenameRegex )[ 1 ], | ||
languageMessages = messages( languageFile, language ), | ||
keys = keysNoMetadata( languageMessages, language ), | ||
blanks = [], | ||
duplicates = [], | ||
unuseds = [], | ||
missing = sourceMessageKeys.slice( 0 ), | ||
unusedParameters = [], | ||
stack, originalParameters; | ||
// Step 2: Walk through files and check for failures. | ||
for ( index in keys ) { | ||
message = keys[ index ]; | ||
translatedFiles.forEach( ( languageFile ) => { | ||
const language = languageFile.match( jsonFilenameRegex )[ 1 ]; | ||
const languageMessages = messages( languageFile, language ); | ||
const keys = keysNoMetadata( languageMessages, language ); | ||
const blanks = []; | ||
const duplicates = []; | ||
const unuseds = []; | ||
const unusedParameters = []; | ||
let leadingWhitespace = []; | ||
let trailingWhitespace = []; | ||
let missing = sourceMessageKeys.slice( 0 ); | ||
let stack, originalParameters; | ||
for ( const index in keys ) { | ||
const message = keys[ index ]; | ||
if ( sourceMessages[ message ] === undefined ) { | ||
@@ -126,3 +129,3 @@ // An unused translation. This happens on commits that remove messages, | ||
if ( missing.indexOf( message ) !== -1 ) { | ||
if ( missing.includes( message ) ) { | ||
if ( languageMessages[ message ] === sourceMessages[ message ] ) { | ||
@@ -137,6 +140,5 @@ duplicates.push( message ); | ||
if ( originalParameters ) { | ||
// eslint-disable-next-line no-loop-func | ||
stack = originalParameters.filter( function ( originalParameter ) { | ||
return languageMessages[ message ].indexOf( originalParameter ) === -1; | ||
} ); | ||
stack = originalParameters.filter( ( originalParameter ) => | ||
!languageMessages[ message ].includes( originalParameter ) | ||
); | ||
@@ -156,6 +158,18 @@ if ( stack.length ) { | ||
if ( !options.allowLeadingWhitespace ) { | ||
leadingWhitespace = keys.filter( ( message ) => | ||
leadingWhitespaceRegex.test( sourceMessages[ message ] ) | ||
); | ||
} | ||
if ( !options.allowTrailingWhitespace ) { | ||
trailingWhitespace = keys.filter( ( message ) => | ||
trailingWhitespaceRegex.test( sourceMessages[ message ] ) | ||
); | ||
} | ||
if ( options.ignoreMissingBlankTranslations ) { | ||
missing = missing.filter( function ( message ) { | ||
return sourceMessages[ message ] !== ''; | ||
} ); | ||
missing = missing.filter( ( messageName ) => | ||
sourceMessages[ messageName ] !== '' | ||
); | ||
} | ||
@@ -170,16 +184,20 @@ | ||
missing: missing, | ||
unusedParameters: unusedParameters | ||
unusedParameters: unusedParameters, | ||
leadingWhitespace: leadingWhitespace, | ||
trailingWhitespace: trailingWhitespace | ||
}; | ||
} ); | ||
let sourceMessageWrongCase = []; | ||
if ( options.requireLowerCase === 'initial' ) { | ||
sourceMessageWrongCase = sourceMessageKeys.filter( function ( value ) { | ||
return ( value !== '' && value[ 0 ] !== value[ 0 ].toLowerCase() ); | ||
} ); | ||
sourceMessageWrongCase = sourceMessageKeys.filter( ( value ) => | ||
( value !== '' && value[ 0 ] !== value[ 0 ].toLowerCase() ) | ||
); | ||
} else if ( options.requireLowerCase ) { | ||
sourceMessageWrongCase = sourceMessageKeys.filter( function ( value ) { | ||
return value !== value.toLowerCase(); | ||
} ); | ||
sourceMessageWrongCase = sourceMessageKeys.filter( ( value ) => | ||
value !== value.toLowerCase() | ||
); | ||
} | ||
let sourceMessageWrongPrefix = []; | ||
if ( options.requireKeyPrefix.length ) { | ||
@@ -189,13 +207,39 @@ if ( typeof options.requireKeyPrefix === 'string' ) { | ||
} | ||
sourceMessageWrongPrefix = sourceMessageKeys.filter( function ( key ) { | ||
return !options.requireKeyPrefix.some( function ( prefix ) { | ||
return key.startsWith( prefix ); | ||
} ); | ||
} ); | ||
sourceMessageWrongPrefix = sourceMessageKeys.filter( ( key ) => | ||
!options.requireKeyPrefix.some( ( prefix ) => | ||
key.startsWith( prefix ) | ||
) | ||
); | ||
} | ||
let sourceMessageLeadingWhitespace = []; | ||
let documentationMessageLeadingWhitespace = []; | ||
if ( !options.allowLeadingWhitespace ) { | ||
sourceMessageLeadingWhitespace = sourceMessageKeys.filter( | ||
( message ) => leadingWhitespaceRegex.test( sourceMessages[ message ] ) | ||
); | ||
documentationMessageLeadingWhitespace = documentationMessageKeys.filter( | ||
( message ) => leadingWhitespaceRegex.test( documentationMessages[ message ] ) | ||
); | ||
} | ||
let sourceMessageTrailingWhitespace = []; | ||
let documentationMessageTrailingWhitespace = []; | ||
if ( !options.allowTrailingWhitespace ) { | ||
sourceMessageTrailingWhitespace = sourceMessageKeys.filter( | ||
( message ) => trailingWhitespaceRegex.test( sourceMessages[ message ] ) | ||
); | ||
documentationMessageTrailingWhitespace = documentationMessageKeys.filter( | ||
( message ) => trailingWhitespaceRegex.test( documentationMessages[ message ] ) | ||
); | ||
} | ||
let sourceMessageMissing = []; | ||
const documentationMessageBlanks = []; | ||
while ( sourceMessageKeys.length > 0 ) { | ||
message = sourceMessageKeys[ 0 ]; | ||
const message = sourceMessageKeys[ 0 ]; | ||
offset = documentationMessageKeys.indexOf( message ); | ||
const offset = documentationMessageKeys.indexOf( message ); | ||
@@ -215,7 +259,10 @@ if ( offset !== -1 ) { | ||
// Step 3: Go through failures and report them, based on config. | ||
let count = 0; | ||
if ( options.requireCompleteMessageDocumentation ) { | ||
// Filter out any missing message that is OK to be skipped | ||
sourceMessageMissing = sourceMessageMissing.filter( function ( value ) { | ||
return options.skipIncompleteMessageDocumentation.indexOf( value ) === -1; | ||
} ); | ||
sourceMessageMissing = sourceMessageMissing.filter( ( value ) => | ||
!options.skipIncompleteMessageDocumentation.includes( value ) | ||
); | ||
count = sourceMessageMissing.length; | ||
@@ -227,4 +274,4 @@ if ( count > 0 ) { | ||
sourceMessageMissing.forEach( function ( message ) { | ||
logErr( `Message "${message}" lacks documentation in qqq.json.` ); | ||
sourceMessageMissing.forEach( ( messageName ) => { | ||
logErr( `Message "${messageName}" lacks documentation in qqq.json.` ); | ||
} ); | ||
@@ -241,4 +288,4 @@ } | ||
documentationMessageBlanks.forEach( function ( message ) { | ||
logErr( `Message "${message}" is documented with a blank string.` ); | ||
documentationMessageBlanks.forEach( ( messageName ) => { | ||
logErr( `Message "${messageName}" is documented with a blank string.` ); | ||
} ); | ||
@@ -248,37 +295,41 @@ } | ||
count = sourceMessageWrongCase.length; | ||
if ( count > 0 ) { | ||
ok = false; | ||
if ( options.requireLowerCase ) { | ||
count = sourceMessageWrongCase.length; | ||
if ( count > 0 ) { | ||
ok = false; | ||
if ( options.requireLowerCase === 'initial' ) { | ||
logErr( `${count} message${( count > 1 ? 's do' : ' does' )} not start with a lowercase character.` ); | ||
if ( options.requireLowerCase === 'initial' ) { | ||
logErr( `${count} message${( count > 1 ? 's do' : ' does' )} not start with a lowercase character.` ); | ||
sourceMessageWrongCase.forEach( function ( message ) { | ||
logErr( `Message "${message}" should start with a lowercase character.` ); | ||
} ); | ||
} else { | ||
logErr( `${count} message${( count > 1 ? 's are' : ' is' )} not wholly lowercase.` ); | ||
sourceMessageWrongCase.forEach( ( messageName ) => { | ||
logErr( `Message "${messageName}" should start with a lowercase character.` ); | ||
} ); | ||
} else { | ||
logErr( `${count} message${( count > 1 ? 's are' : ' is' )} not wholly lowercase.` ); | ||
sourceMessageWrongCase.forEach( function ( message ) { | ||
logErr( `Message "${message}" should be in lowercase.` ); | ||
} ); | ||
sourceMessageWrongCase.forEach( ( messageName ) => { | ||
logErr( `Message "${messageName}" should be in lowercase.` ); | ||
} ); | ||
} | ||
} | ||
} | ||
count = sourceMessageWrongPrefix.length; | ||
if ( count > 0 ) { | ||
ok = false; | ||
if ( options.requireKeyPrefix.length ) { | ||
count = sourceMessageWrongPrefix.length; | ||
if ( count > 0 ) { | ||
ok = false; | ||
if ( options.requireKeyPrefix.length === 1 ) { | ||
logErr( `${count} message${( count > 1 ? 's do' : ' does' )} not start with the required prefix "${options.requireKeyPrefix[ 0 ]}".` ); | ||
if ( options.requireKeyPrefix.length === 1 ) { | ||
logErr( `${count} message${( count > 1 ? 's do' : ' does' )} not start with the required prefix "${options.requireKeyPrefix[ 0 ]}".` ); | ||
sourceMessageWrongPrefix.forEach( function ( message ) { | ||
logErr( `Message "${message}" should start with the required prefix "${options.requireKeyPrefix[ 0 ]}".` ); | ||
} ); | ||
} else { | ||
logErr( `${count} message${( count > 1 ? 's do' : ' does' )} not start with any of the required prefices.'` ); | ||
sourceMessageWrongPrefix.forEach( ( messageName ) => { | ||
logErr( `Message "${messageName}" should start with the required prefix "${options.requireKeyPrefix[ 0 ]}".` ); | ||
} ); | ||
} else { | ||
logErr( `${count} message${( count > 1 ? 's do' : ' does' )} not start with any of the required prefices.'` ); | ||
sourceMessageWrongPrefix.forEach( function ( message ) { | ||
logErr( `Message "${message}" should start with one of the required prefices.` ); | ||
} ); | ||
sourceMessageWrongPrefix.forEach( ( messageName ) => { | ||
logErr( `Message "${messageName}" should start with one of the required prefices.` ); | ||
} ); | ||
} | ||
} | ||
@@ -294,4 +345,4 @@ } | ||
documentationMessageKeys.forEach( function ( message ) { | ||
logErr( `Message "${message}" is documented but undefined.` ); | ||
documentationMessageKeys.forEach( ( messageName ) => { | ||
logErr( `Message "${messageName}" is documented but undefined.` ); | ||
} ); | ||
@@ -301,3 +352,43 @@ } | ||
for ( index in translatedData ) { | ||
if ( !options.allowLeadingWhitespace ) { | ||
count = sourceMessageLeadingWhitespace.length; | ||
if ( count > 0 ) { | ||
ok = false; | ||
logErr( `${count} message${( count > 1 ? 's have' : ' has' )} leading whitespace:` ); | ||
sourceMessageLeadingWhitespace.forEach( ( message ) => { | ||
logErr( `Message "${message}" has leading whitespace` ); | ||
} ); | ||
} | ||
count = documentationMessageLeadingWhitespace.length; | ||
if ( count > 0 ) { | ||
ok = false; | ||
logErr( `${count} message documentation${( count > 1 ? 's have' : ' has' )} leading whitespace:` ); | ||
documentationMessageLeadingWhitespace.forEach( ( message ) => { | ||
logErr( `Message documentation "${message}" has leading whitespace` ); | ||
} ); | ||
} | ||
} | ||
if ( !options.allowTrailingWhitespace ) { | ||
count = sourceMessageTrailingWhitespace.length; | ||
if ( count > 0 ) { | ||
ok = false; | ||
logErr( `${count} message${( count > 1 ? 's have' : ' has' )} trailing whitespace:` ); | ||
sourceMessageTrailingWhitespace.forEach( ( message ) => { | ||
logErr( `Message "${message}" has trailing whitespace` ); | ||
} ); | ||
} | ||
count = documentationMessageTrailingWhitespace.length; | ||
if ( count > 0 ) { | ||
ok = false; | ||
logErr( `${count} message documentation${( count > 1 ? 's have' : ' has' )} trailing whitespace:` ); | ||
documentationMessageTrailingWhitespace.forEach( ( message ) => { | ||
logErr( `Message documentation "${message}" has trailing whitespace` ); | ||
} ); | ||
} | ||
} | ||
for ( const index in translatedData ) { | ||
// eslint-disable-next-line no-prototype-builtins | ||
@@ -313,4 +404,4 @@ if ( !translatedData.hasOwnProperty( index ) ) { | ||
logErr( `The "${index}" translation has ${count} blank translation${( count > 1 ? 's' : '' )}:` ); | ||
translatedData[ index ].blank.forEach( function ( message ) { | ||
logErr( `The translation of "${message}" is blank.` ); | ||
translatedData[ index ].blank.forEach( ( messageName ) => { | ||
logErr( `The translation of "${messageName}" is blank.` ); | ||
} ); | ||
@@ -325,4 +416,4 @@ } | ||
logErr( `The "${index}" translation has ${count} duplicate translation${( count > 1 ? 's' : '' )}:` ); | ||
translatedData[ index ].duplicate.forEach( function ( message ) { | ||
logErr( `The translation of "${message}" duplicates the primary message.` ); | ||
translatedData[ index ].duplicate.forEach( ( messageName ) => { | ||
logErr( `The translation of "${messageName}" duplicates the primary message.` ); | ||
} ); | ||
@@ -337,4 +428,4 @@ } | ||
logErr( `The "${index}" translation has ${count} unused translation${( count > 1 ? 's' : '' )}:` ); | ||
translatedData[ index ].unused.forEach( function ( message ) { | ||
logErr( `The translation of "${message}" is unused.` ); | ||
translatedData[ index ].unused.forEach( ( messageName ) => { | ||
logErr( `The translation of "${messageName}" is unused.` ); | ||
} ); | ||
@@ -349,4 +440,4 @@ } | ||
logErr( `The "${index}" translation has ${count} message${( count > 1 ? 's' : '' )} which fail${( count > 1 ? 's' : '' )} to use all parameters:` ); | ||
// eslint-disable-next-line no-loop-func | ||
translatedData[ index ].unusedParameters.forEach( function ( report ) { | ||
translatedData[ index ].unusedParameters.forEach( ( report ) => { | ||
switch ( report.stack.length ) { | ||
@@ -365,10 +456,32 @@ case 1: | ||
} | ||
if ( !options.allowLeadingWhitespace ) { | ||
count = translatedData[ index ].leadingWhitespace.length; | ||
if ( count > 0 ) { | ||
ok = false; | ||
logErr( `The "${index}" translation has ${count} translation${( count > 1 ? 's' : '' )} with leading whitespace:` ); | ||
translatedData[ index ].leadingWhitespace.forEach( ( message ) => { | ||
logErr( `The translation of "${message}" has leading whitespace.` ); | ||
} ); | ||
} | ||
} | ||
if ( !options.allowTrailingWhitespace ) { | ||
count = translatedData[ index ].trailingWhitespace.length; | ||
if ( count > 0 ) { | ||
ok = false; | ||
logErr( `The "${index}" translation has ${count} translation${( count > 1 ? 's' : '' )} with trailing whitespace:` ); | ||
translatedData[ index ].trailingWhitespace.forEach( ( message ) => { | ||
logErr( `The translation of "${message}" has trailing whitespace.` ); | ||
} ); | ||
} | ||
} | ||
} | ||
if ( options.requireCompleteTranslationLanguages.length ) { | ||
for ( index in translatedData ) { | ||
for ( const index in translatedData ) { | ||
if ( | ||
// eslint-disable-next-line no-prototype-builtins | ||
!translatedData.hasOwnProperty( index ) || | ||
( options.requireCompleteTranslationLanguages.indexOf( index ) === -1 ) | ||
( !options.requireCompleteTranslationLanguages.includes( index ) ) | ||
) { | ||
@@ -383,4 +496,4 @@ continue; | ||
translatedData[ index ].missing.forEach( function ( message ) { | ||
logErr( `The translation of "${message}" is missing.` ); | ||
translatedData[ index ].missing.forEach( ( messageName ) => { | ||
logErr( `The translation of "${messageName}" is missing.` ); | ||
} ); | ||
@@ -392,3 +505,3 @@ } | ||
if ( options.requireCompleteTranslationMessages.length ) { | ||
for ( index in translatedData ) { | ||
for ( const index in translatedData ) { | ||
// eslint-disable-next-line no-prototype-builtins | ||
@@ -399,3 +512,3 @@ if ( !translatedData.hasOwnProperty( index ) ) { | ||
for ( message in translatedData[ index ].missing ) { | ||
for ( const message in translatedData[ index ].missing ) { | ||
if ( | ||
@@ -408,3 +521,3 @@ // eslint-disable-next-line no-prototype-builtins | ||
offset = options.requireCompleteTranslationMessages.indexOf( | ||
const offset = options.requireCompleteTranslationMessages.indexOf( | ||
sourceMessageKeys[ message ] | ||
@@ -423,4 +536,4 @@ ); | ||
translatedData[ index ].missing.forEach( function ( message ) { | ||
logErr( `The required message "${message}" is missing.` ); | ||
translatedData[ index ].missing.forEach( ( messageName ) => { | ||
logErr( `The required message "${messageName}" is missing.` ); | ||
} ); | ||
@@ -427,0 +540,0 @@ } |
@@ -26,2 +26,4 @@ #!/usr/bin/env node | ||
case 'disallowUnusedTranslations': | ||
case 'allowLeadingWhitespace': | ||
case 'allowTrailingWhitespace': | ||
case 'ignoreMissingBlankTranslations': | ||
@@ -53,2 +55,3 @@ case 'requireCompleteMessageDocumentation': | ||
console.error( 'banana-check: Specify one or more directories.' ); | ||
// eslint-disable-next-line no-process-exit | ||
process.exit( 1 ); | ||
@@ -66,2 +69,3 @@ } | ||
if ( !result ) { | ||
// eslint-disable-next-line no-process-exit | ||
process.exit( 1 ); | ||
@@ -68,0 +72,0 @@ } |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
const bananaChecker = require( '../src/banana.js' ); | ||
@@ -2,0 +4,0 @@ |
26680
522
225
6