diff --git a/Changelog.md b/Changelog.md index a43adf8..a0408bc 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,20 @@ + +# [0.4.0](https://github.com/martinroob/ngx-i18nsupport/compare/v0.3.1...v0.4.0) (2017-05-03) + +### Bug Fixes + +* **xliffmerge:** xliffmerge creates empty json files ([#18](https://github.com/martinroob/ngx-i18nsupport/issues/18)) + +### Features + +* **xliffmerge:** create an API to access parsing functionality. ([#11](https://github.com/martinroob/ngx-i18nsupport/issues/11)). +The API is in a separate npm package [ngx-i18nsupport-lib](https://github.com/martinroob/ngx-i18nsupport-lib). + +* **xliffmerge:** use explicitly set IDs for ngx-translate data generation. ([#15](https://github.com/martinroob/ngx-i18nsupport/issues/15)) +For detail have a look at the Wiki page [ngx translate usage](https://github.com/martinroob/ngx-i18nsupport/wiki/ngx-translate-usage). + +* **xliffmerge:** Handle new source element introduced with Angular 4. ([#21](https://github.com/martinroob/ngx-i18nsupport/issues/21)) + # [0.3.1](https://github.com/martinroob/ngx-i18nsupport/compare/v0.3.0...v0.3.1) (2017-04-25) diff --git a/ngx-i18nsupport.d.ts b/ngx-i18nsupport.d.ts deleted file mode 100644 index 4aaf8f9..0000000 --- a/ngx-i18nsupport.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './public_api'; diff --git a/package.json b/package.json index 5aa2ab1..034c78c 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,10 @@ { "name": "ngx-i18nsupport", - "version": "0.3.1", + "version": "0.4.0", "description": "Some tooling to be used with the Angular 2 i18n workflow", "main": "index.js", "module": "./src", "es2015": "./src", - "typings": "./ngx-i18nsupport.d.ts", "bin": { "xliffmerge": "./dist/xliffmerge/xliffmerge" }, @@ -18,7 +17,8 @@ "pretest": "npm run build", "test": "./node_modules/.bin/jasmine-node dist", "precover": "npm run build", - "cover": "./node_modules/.bin/istanbul cover --root dist --include-all-sources ./node_modules/jasmine-node/bin/jasmine-node -- dist" + "cover": "./node_modules/.bin/istanbul cover --root dist --include-all-sources ./node_modules/jasmine-node/bin/jasmine-node -- dist", + "prepublish": "npm run build" }, "repository": { "type": "git", @@ -28,7 +28,8 @@ "i18n", "tooling", "angular", - "xliff" + "xliff", + "xmb" ], "author": "Martin Roob (www.roobsoft.de)", "license": "MIT", @@ -37,7 +38,6 @@ }, "homepage": "https://github.com/martinroob/ngx-i18nsupport#readme", "devDependencies": { - "@types/cheerio": "^0.17.31", "@types/jasmine": "^2.5.43", "@types/node": "^7.0.5", "coveralls": "^2.11.16", @@ -48,7 +48,7 @@ }, "dependencies": { "chalk": "^1.1.3", - "cheerio": "^0.22.0", - "commander": "^2.9.0" + "commander": "^2.9.0", + "ngx-i18nsupport-lib": "^0.0.8" } } diff --git a/public_api.d.ts b/public_api.d.ts deleted file mode 100644 index 7da5242..0000000 --- a/public_api.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @module - * @description - * Entry point for all public APIs of the package. - */ -export * from './src/index'; diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json index a460644..e2a914c 100644 --- a/spec/support/jasmine.json +++ b/spec/support/jasmine.json @@ -1,5 +1,5 @@ { - "spec_dir": "dist/out-tsc", + "spec_dir": "dist", "spec_files": [ "**/*[sS]pec.js" ], diff --git a/src/common/command-output.js b/src/common/command-output.js deleted file mode 100644 index 29c51ad..0000000 --- a/src/common/command-output.js +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Created by martin on 17.02.2017. - * Very simple class to control the output of a command. - * Output can be errors, warnings, infos and debug-Outputs. - * The output can be controlled via 2 flags, quiet and verbose. - * If quit is enabled only error messages are shown. - * If verbose is enabled, everything is shown. - * If both are not enabled (the default) errors, warnings and infos are shown. - * If not are enabled (strange), we assumed the default. - */ -"use strict"; -var chalk = require("chalk"); -var util = require("util"); -var LogLevel; -(function (LogLevel) { - LogLevel[LogLevel["ERROR"] = 0] = "ERROR"; - LogLevel[LogLevel["WARN"] = 1] = "WARN"; - LogLevel[LogLevel["INFO"] = 2] = "INFO"; - LogLevel[LogLevel["DEBUG"] = 3] = "DEBUG"; -})(LogLevel || (LogLevel = {})); -var CommandOutput = (function () { - function CommandOutput(stdout) { - this._quiet = false; - this._verbose = false; - if (stdout) { - this.outputStream = stdout; - } - else { - this.outputStream = process.stdout; - } - } - CommandOutput.prototype.setVerbose = function () { - this._verbose = true; - }; - CommandOutput.prototype.setQuiet = function () { - this._quiet = true; - }; - /** - * Test, wether verbose is enabled. - * @return {boolean} - */ - CommandOutput.prototype.verbose = function () { - return this._verbose; - }; - /** - * Test, wether queit is enabled. - * @return {boolean} - */ - CommandOutput.prototype.quiet = function () { - return this._quiet; - }; - CommandOutput.prototype.error = function (msg) { - var params = []; - for (var _i = 1; _i < arguments.length; _i++) { - params[_i - 1] = arguments[_i]; - } - this.log(LogLevel.ERROR, msg, params); - }; - CommandOutput.prototype.warn = function (msg) { - var params = []; - for (var _i = 1; _i < arguments.length; _i++) { - params[_i - 1] = arguments[_i]; - } - this.log(LogLevel.WARN, msg, params); - }; - CommandOutput.prototype.info = function (msg) { - var params = []; - for (var _i = 1; _i < arguments.length; _i++) { - params[_i - 1] = arguments[_i]; - } - this.log(LogLevel.INFO, msg, params); - }; - CommandOutput.prototype.debug = function (msg) { - var params = []; - for (var _i = 1; _i < arguments.length; _i++) { - params[_i - 1] = arguments[_i]; - } - this.log(LogLevel.DEBUG, msg, params); - }; - CommandOutput.prototype.log = function (level, msg, params) { - if (!this.isOutputEnabled(level)) { - return; - } - var coloredMessage; - switch (level) { - case LogLevel.ERROR: - coloredMessage = chalk.red('ERROR: ' + msg); - break; - case LogLevel.WARN: - coloredMessage = chalk.magenta('WARNING: ' + msg); - break; - default: - coloredMessage = chalk.gray('* ' + msg); - break; - } - var outMsg = util.format.apply(util, [coloredMessage].concat(params)); - this.outputStream.write(outMsg + '\n'); - }; - CommandOutput.prototype.isOutputEnabled = function (level) { - var quietEnabled, verboseEnabled; - if (this._quiet && this._verbose) { - quietEnabled = false; - verboseEnabled = false; - } - else { - quietEnabled = this._quiet; - verboseEnabled = this._verbose; - } - switch (level) { - case LogLevel.ERROR: - return true; // always output errors - case LogLevel.WARN: - return (!quietEnabled); - case LogLevel.INFO: - return (verboseEnabled && !quietEnabled); - case LogLevel.DEBUG: - return verboseEnabled; - default: - return true; - } - }; - return CommandOutput; -}()); -exports.CommandOutput = CommandOutput; diff --git a/src/common/command-output.ts b/src/common/command-output.ts index 3b3c366..a73630a 100644 --- a/src/common/command-output.ts +++ b/src/common/command-output.ts @@ -11,7 +11,7 @@ import * as chalk from "chalk"; import WritableStream = NodeJS.WritableStream; -import util = require('util'); +import * as util from "util"; enum LogLevel { "ERROR", diff --git a/src/common/file-util.js b/src/common/file-util.js deleted file mode 100644 index fe9b06b..0000000 --- a/src/common/file-util.js +++ /dev/null @@ -1,96 +0,0 @@ -"use strict"; -var fs = require("fs"); -/** - * Created by martin on 17.02.2017. - * Some (a few) simple utils for file operations. - * Just for convenience. - */ -var FileUtil = (function () { - function FileUtil() { - } - /** - * Check for existence. - * @param filename - * @return {boolean} - */ - FileUtil.exists = function (filename) { - return fs.existsSync(filename); - }; - /** - * Read a file. - * @param filename - * @param encoding - * @return {string} - */ - FileUtil.read = function (filename, encoding) { - return fs.readFileSync(filename, encoding); - }; - /** - * Write a file with given content. - * @param filename - * @param newContent - * @param encoding - */ - FileUtil.replaceContent = function (filename, newContent, encoding) { - fs.writeFileSync(filename, newContent, { encoding: encoding }); - }; - FileUtil.copy = function (srcFile, destFile) { - var BUF_LENGTH = 64 * 1024; - var buff = new Buffer(BUF_LENGTH); - var fdr = fs.openSync(srcFile, 'r'); - var fdw = fs.openSync(destFile, 'w'); - var bytesRead = 1; - var pos = 0; - while (bytesRead > 0) { - bytesRead = fs.readSync(fdr, buff, 0, BUF_LENGTH, pos); - fs.writeSync(fdw, buff, 0, bytesRead); - pos += bytesRead; - } - fs.closeSync(fdr); - fs.closeSync(fdw); - }; - /** - * Delete the folder and all of its content (rm -rf). - * @param path - */ - FileUtil.deleteFolderRecursive = function (path) { - var files = []; - if (fs.existsSync(path)) { - files = fs.readdirSync(path); - files.forEach(function (file, index) { - var curPath = path + "/" + file; - if (fs.lstatSync(curPath).isDirectory()) { - FileUtil.deleteFolderRecursive(curPath); - } - else { - fs.unlinkSync(curPath); - } - }); - fs.rmdirSync(path); - } - }; - ; - /** - * Delete folders content recursively, but do not delete folder. - * Folder is left empty at the end. - * @param path - */ - FileUtil.deleteFolderContentRecursive = function (path) { - var files = []; - if (fs.existsSync(path)) { - files = fs.readdirSync(path); - files.forEach(function (file, index) { - var curPath = path + "/" + file; - if (fs.lstatSync(curPath).isDirectory()) { - FileUtil.deleteFolderRecursive(curPath); - } - else { - fs.unlinkSync(curPath); - } - }); - } - }; - ; - return FileUtil; -}()); -exports.FileUtil = FileUtil; diff --git a/src/common/file-util.ts b/src/common/file-util.ts index ed811e2..a74dce2 100644 --- a/src/common/file-util.ts +++ b/src/common/file-util.ts @@ -1,4 +1,5 @@ -import fs = require("fs"); +import * as fs from "fs"; + /** * Created by martin on 17.02.2017. * Some (a few) simple utils for file operations. @@ -92,4 +93,11 @@ export class FileUtil { } }; + /** + * Delete a file. + * @param path + */ + public static deleteFile(path: string) { + fs.unlinkSync(path); + } } \ No newline at end of file diff --git a/src/common/writer-to-string.js b/src/common/writer-to-string.js deleted file mode 100644 index 1373cef..0000000 --- a/src/common/writer-to-string.js +++ /dev/null @@ -1,45 +0,0 @@ -"use strict"; -var __extends = (this && this.__extends) || function (d, b) { - for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); -}; -var stream_1 = require("stream"); -var util_1 = require("util"); -/** - * Created by martin on 20.02.2017. - * A helper class for testing. - * Can be used as a WritableStream and writes everything (synchronously) into a string, - * that can easily be read by the tests. - */ -var WriterToString = (function (_super) { - __extends(WriterToString, _super); - function WriterToString() { - var _this = _super.call(this) || this; - _this.resultString = ''; - return _this; - } - WriterToString.prototype._write = function (chunk, encoding, callback) { - var chunkString; - if (util_1.isString(chunk)) { - chunkString = chunk; - } - else if (chunk instanceof Buffer) { - chunkString = chunk.toString(); - } - else { - chunkString = new Buffer(chunk).toString(encoding); - } - this.resultString = this.resultString + chunkString; - callback(); - }; - /** - * Returns a string of everything, that was written to the stream so far. - * @return {string} - */ - WriterToString.prototype.writtenData = function () { - return this.resultString; - }; - return WriterToString; -}(stream_1.Writable)); -exports.WriterToString = WriterToString; diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 235f033..0000000 --- a/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Created by martin on 19.03.2017. - */ -export {TranslationMessagesFileFactory} from './xliffmerge/translation-messages-file-factory'; -export {ITranslationMessagesFile} from './xliffmerge/i-translation-messages-file'; -export {ITransUnit} from './xliffmerge/i-trans-unit'; diff --git a/src/tsconfig.json b/src/tsconfig.json index 18196c5..a0fac10 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -15,7 +15,7 @@ "../node_modules/@types" ] }, - "include": [ + "includes": [ "**/*" ] } diff --git a/src/xliffmerge/i-trans-unit.ts b/src/xliffmerge/i-trans-unit.ts deleted file mode 100644 index 634fd03..0000000 --- a/src/xliffmerge/i-trans-unit.ts +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Created by martin on 19.03.2017. - */ - -/** - * Interface of a translation unit in a translation messages file. - */ -export interface ITransUnit { - - readonly id: string; - - sourceContent(): string; - - /** - * the translated value (containing all markup, depends on the concrete format used). - */ - targetContent(): string; - - /** - * the translated value, but all placeholders are replaced with {{n}} (starting at 0) - * and all embedded html is replaced by direct html markup. - */ - targetContentNormalized(): string; - - /** - * State of the translation. - * (new, final, ...) - */ - targetState(): string; - - /** - * The description set in the template as value of the i18n-attribute. - * e.g. i18n="mydescription". - */ - description(): string; - - /** - * The meaning (intent) set in the template as value of the i18n-attribute. - * This is the part in front of the | symbol. - * e.g. i18n="meaning|mydescription". - */ - meaning(): string; - - /** - * the real xml element used for trans unit. - * @return {CheerioElement} - */ - asXmlElement(): CheerioElement; - - /** - * Copy source to target to use it as dummy translation. - * (better than missing value) - */ - useSourceAsTarget(isDefaultLang: boolean, copyContent: boolean); - - /** - * Translate trans unit. - * (very simple, just for tests) - * @param translation the translated string - */ - translate(translation: string); -} diff --git a/src/xliffmerge/i-translation-messages-file.js b/src/xliffmerge/i-translation-messages-file.js deleted file mode 100644 index de89c30..0000000 --- a/src/xliffmerge/i-translation-messages-file.js +++ /dev/null @@ -1,34 +0,0 @@ -"use strict"; -var xliff_file_1 = require("./xliff-file"); -var xmb_file_1 = require("./xmb-file"); -var util_1 = require("util"); -/** - * The Common interface of XliffFile and XmbFile. - * The merge process only uses this interface. - * Created by martin on 10.03.2017. - */ -/** - * Helper class to read file depending on format. - */ -var TranslationMessagesFileReader = (function () { - function TranslationMessagesFileReader() { - } - /** - * Read file function, result depends on format, either XliffFile or XmbFile. - * @param format - * @param path - * @param encoding - * @return {XliffFile} - */ - TranslationMessagesFileReader.fromFile = function (i18nFormat, path, encoding) { - if (i18nFormat === 'xlf') { - return xliff_file_1.XliffFile.fromFile(path, encoding); - } - if (i18nFormat === 'xmb') { - return xmb_file_1.XmbFile.fromFile(path, encoding); - } - throw new Error(util_1.format('oops, unsupported format "%s"', i18nFormat)); - }; - return TranslationMessagesFileReader; -}()); -exports.TranslationMessagesFileReader = TranslationMessagesFileReader; diff --git a/src/xliffmerge/i-translation-messages-file.ts b/src/xliffmerge/i-translation-messages-file.ts deleted file mode 100644 index 28d225c..0000000 --- a/src/xliffmerge/i-translation-messages-file.ts +++ /dev/null @@ -1,111 +0,0 @@ -import {XliffFile} from './xliff-file'; -import {XmbFile} from './xmb-file'; -import {FileUtil} from '../common/file-util'; -import {format} from 'util'; -import {ITransUnit} from './i-trans-unit'; - -/** - * The Common interface of XliffFile and XmbFile. - * The merge process only uses this interface. - * Created by martin on 10.03.2017. - */ -export interface ITranslationMessagesFile { - - /** - * warnings found in the file - */ - warnings(): string[]; - - /** - * Number of translations found in the file. - */ - numberOfTransUnits(): number; - - /** - * Number of translations without id found in the file. - */ - numberOfTransUnitsWithMissingId(): number; - - /** - * Get source language. - * @return {string} - */ - sourceLanguage(): string; - - /** - * Edit the source language. - * @param language - */ - setSourceLanguage(language: string); - - /** - * Get target language. - * @return {string} - */ - targetLanguage(): string; - - /** - * Edit the target language. - * @param language - */ - setTargetLanguage(language: string); - - /** - * Loop over all Translation Units. - * @param callback - */ - forEachTransUnit(callback: ((transunit: ITransUnit) => void)); - - /** - * Get trans-unit with given id. - * @param id - * @return {Cheerio} - */ - transUnitWithId(id: string): ITransUnit; - - /** - * Edit functions following her - */ - - /** - * Add a new trans-unit. - * @param transUnit - */ - addNewTransUnit(transUnit: ITransUnit); - - /** - * Remove the trans-unit with the given id. - * @param id - */ - removeTransUnitWithId(id: string); - - /** - * Copy source to target to use it as dummy translation. - * (better than missing value) - */ - useSourceAsTarget(transUnit: ITransUnit, isDefaultLang: boolean, copyContent: boolean); - - /** - * Translate a given trans unit. - * (very simple, just for tests) - * @param transUnit - * @param translation the translated string - */ - translate(transUnit: ITransUnit, translation: string); - - /** - * The filename where the data is read from. - */ - filename(): string; - - /** - * The encoding if the xml content (UTF-8, ISO-8859-1, ...) - */ - encoding(): string; - - /** - * The xml content to be saved after changes are made. - */ - editedContent(): string; - -} diff --git a/src/xliffmerge/ngx-translate-extractor.ts b/src/xliffmerge/ngx-translate-extractor.ts index 9863019..a759443 100644 --- a/src/xliffmerge/ngx-translate-extractor.ts +++ b/src/xliffmerge/ngx-translate-extractor.ts @@ -1,7 +1,6 @@ -import {ITranslationMessagesFile} from './i-translation-messages-file'; +import {ITranslationMessagesFile, ITransUnit} from 'ngx-i18nsupport-lib'; import {FileUtil} from '../common/file-util'; import {isNullOrUndefined} from 'util'; -import {ITransUnit} from './i-trans-unit'; /** * Created by roobm on 15.03.2017. * A tool for extracting messages in ngx-translate format. @@ -40,7 +39,13 @@ export class NgxTranslateExtractor { */ public extractTo(outputFile: string) { let translations: NgxTranslations = this.toNgxTranslations(this.extract()); - FileUtil.replaceContent(outputFile, JSON.stringify(translations, null, 4), 'UTF-8') + if (translations && Object.keys(translations).length > 0) { + FileUtil.replaceContent(outputFile, JSON.stringify(translations, null, 4), 'UTF-8') + } else { + if (FileUtil.exists(outputFile)) { + FileUtil.deleteFile(outputFile); + } + } } /** @@ -50,18 +55,46 @@ export class NgxTranslateExtractor { private extract(): NgxMessage[] { let result: NgxMessage[] = []; this.messagesFile.forEachTransUnit((tu: ITransUnit) => { - let description = tu.description(); - let id = tu.meaning(); - if (description && description === 'ngx-translate') { - let messagetext = this.toTranslateString(tu.targetContentNormalized()); - result.push({id: id, message: messagetext}); + let ngxId = this.ngxTranslateIdFromTU(tu); + if (ngxId) { + let messagetext = tu.targetContentNormalized(); + result.push({id: ngxId, message: messagetext}); } }); return result; } - private toTranslateString(contentFromTU: string): string { - return contentFromTU; + /** + * Check, wether this tu should be extracted for ngx-translate usage, and return its id for ngx-translate. + * There are 2 possibilities: + * 1. description is set to "ngx-translate" and meaning contains the id. + * 2. id is explicitly set to a string. + * @param tu + * @return an id or null, if this tu should not be extracted. + */ + private ngxTranslateIdFromTU(tu: ITransUnit): string { + if (this.isExplicitlySetId(tu.id)) { + return tu.id; + } + let description = tu.description(); + if (description && description === 'ngx-translate') { + return tu.meaning(); + } + } + + /** + * Test, wether ID was explicitly set (via i18n="@myid). + * Just heuristic, an ID is explicitly that, if it does not look like a generated one. + * @param id + * @return {boolean} + */ + private isExplicitlySetId(id: string): boolean { + if (isNullOrUndefined(id)) { + return false; + } + // generated IDs are either decimal or sha1 hex + let reForGeneratedId = /^[0-9a-f]{11,}$/; + return !reForGeneratedId.test(id); } /** diff --git a/src/xliffmerge/translation-messages-file-factory.ts b/src/xliffmerge/translation-messages-file-factory.ts deleted file mode 100644 index e49e86d..0000000 --- a/src/xliffmerge/translation-messages-file-factory.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Created by roobm on 21.03.2017. - */ -import {ITranslationMessagesFile} from './i-translation-messages-file'; -import {XmlReader} from './xml-reader'; -import {XliffFile} from './xliff-file'; -import {XmbFile} from './xmb-file'; -import {format} from 'util'; - -/** - * Helper class to read translation files depending on format. - * This is part of the public api - */ -export class TranslationMessagesFileFactory { - - /** - * Read file function, result depends on format, either XliffFile or XmbFile. - * @param format - * @param xmlContent the file content - * @param path the path of the file (only used to remember it) - * @param encoding - * @return {XliffFile} - */ - public static fromFileContent(i18nFormat: string, xmlContent: string, path: string, encoding: string): ITranslationMessagesFile { - if (i18nFormat === 'xlf') { - return new XliffFile(xmlContent, path, encoding); - } - if (i18nFormat === 'xmb') { - return new XmbFile(xmlContent, path, encoding); - } else { - throw new Error(format('oops, unsupported format "%s"', i18nFormat)); - } - } - -} - diff --git a/src/xliffmerge/translation-messages-file-reader.ts b/src/xliffmerge/translation-messages-file-reader.ts index 1ce6d49..672d4a0 100644 --- a/src/xliffmerge/translation-messages-file-reader.ts +++ b/src/xliffmerge/translation-messages-file-reader.ts @@ -1,12 +1,9 @@ /** * Created by roobm on 21.03.2017. */ -import {ITranslationMessagesFile} from './i-translation-messages-file'; -import {XmlReader} from './xml-reader'; -import {XliffFile} from './xliff-file'; -import {XmbFile} from './xmb-file'; -import {format} from 'util'; +import {TranslationMessagesFileFactory, ITranslationMessagesFile, ITransUnit} from 'ngx-i18nsupport-lib'; import {FileUtil} from '../common/file-util'; +import {XmlReader} from './xml-reader'; /** * Helper class to read translation files depending on format. @@ -20,15 +17,46 @@ export class TranslationMessagesFileReader { * @param encoding * @return {XliffFile} */ - public static fromFile(i18nFormat: string, path: string, encoding: string): ITranslationMessagesFile { + public static fromFile(i18nFormat: string, + path: string, + encoding: string, + optionalMasterFilePath?: string): ITranslationMessagesFile { let xmlContent = XmlReader.readXmlFileContent(path, encoding); - if (i18nFormat === 'xlf') { - return new XliffFile(xmlContent.content, path, xmlContent.encoding); - } - if (i18nFormat === 'xmb') { - return new XmbFile(xmlContent.content, path, xmlContent.encoding); + let optionalMaster = TranslationMessagesFileReader.masterFileContent(optionalMasterFilePath, encoding); + return TranslationMessagesFileFactory.fromFileContent(i18nFormat, xmlContent.content, path, xmlContent.encoding, optionalMaster); + } + + /** + * Read file function, result depends on format, either XliffFile or XmbFile. + * @param format + * @param path + * @param encoding + * @return {XliffFile} + */ + public static fromUnknownFormatFile(path: string, + encoding: string, + optionalMasterFilePath?: string): ITranslationMessagesFile { + let xmlContent = XmlReader.readXmlFileContent(path, encoding); + let optionalMaster = TranslationMessagesFileReader.masterFileContent(optionalMasterFilePath, encoding); + return TranslationMessagesFileFactory.fromUnknownFormatFileContent(xmlContent.content, path, xmlContent.encoding, optionalMaster); + } + + /** + * Read master xmb file + * @param optionalMasterFilePath + * @param encoding + * @return {any} content and encoding of file + */ + private static masterFileContent(optionalMasterFilePath: string, encoding: string): {xmlContent: string, path: string, encoding: string} { + if (optionalMasterFilePath) { + let masterXmlContent = XmlReader.readXmlFileContent(optionalMasterFilePath, encoding); + return { + xmlContent: masterXmlContent.content, + path: optionalMasterFilePath, + encoding: masterXmlContent.encoding + }; } else { - throw new Error(format('oops, unsupported format "%s"', i18nFormat)); + return null; } } diff --git a/src/xliffmerge/version.js b/src/xliffmerge/version.js deleted file mode 100644 index fa34032..0000000 --- a/src/xliffmerge/version.js +++ /dev/null @@ -1,7 +0,0 @@ -"use strict"; -/** - * Created by martin on 19.02.2017. - */ -var path = require("path"); -var pkg = require(path.resolve(__dirname, '..', 'package.json')); -exports.VERSION = (pkg ? pkg.version : 'unknown'); diff --git a/src/xliffmerge/xliff-file.js b/src/xliffmerge/xliff-file.js deleted file mode 100644 index 3fc919f..0000000 --- a/src/xliffmerge/xliff-file.js +++ /dev/null @@ -1,218 +0,0 @@ -"use strict"; -var cheerio = require("cheerio"); -var file_util_1 = require("../common/file-util"); -var util_1 = require("util"); -var xml_reader_1 = require("./xml-reader"); -/** - * Created by martin on 23.02.2017. - * Ab xliff file read from a source file. - * Defines some relevant get and set method for reading and modifying such a file. - */ -/** - * Read-Options for cheerio, enable xml mode. - * @type {{xmlMode: boolean}} - */ -var CheerioOptions = { - xmlMode: true, - decodeEntities: false, -}; -var TransUnit = (function () { - function TransUnit(_transUnit, _id) { - this._transUnit = _transUnit; - this._id = _id; - } - Object.defineProperty(TransUnit.prototype, "id", { - get: function () { - return this._id; - }, - enumerable: true, - configurable: true - }); - TransUnit.prototype.sourceContent = function () { - return cheerio('source', this._transUnit).html(); - }; - TransUnit.prototype.targetContent = function () { - return cheerio('target', this._transUnit).html(); - }; - TransUnit.prototype.targetState = function () { - return cheerio('target', this._transUnit).attr('state'); - }; - /** - * the real xml element used for trans unit. - * Here it is a element defined in XLIFF Spec. - * @return {CheerioElement} - */ - TransUnit.prototype.asXmlElement = function () { - return this._transUnit; - }; - /** - * Translate trans unit. - * (very simple, just for tests) - * @param translation the translated string - */ - TransUnit.prototype.translate = function (translation) { - var target = cheerio('target', this._transUnit); - if (!target) { - var source = cheerio('source', this._transUnit); - source.parent().append(''); - target = cheerio('target', source.parent()); - } - target.html(translation); - target.attr('state', 'final'); - }; - /** - * Copy source to target to use it as dummy translation. - * (better than missing value) - */ - TransUnit.prototype.useSourceAsTarget = function (isDefaultLang) { - var source = cheerio('source', this._transUnit); - var target = cheerio('target', this._transUnit); - if (!target) { - source.parent().append(''); - target = cheerio('target', source.parent()); - } - target.html(source.html()); - if (isDefaultLang) { - target.attr('state', 'final'); - } - else { - target.attr('state', 'new'); - } - }; - return TransUnit; -}()); -var XliffFile = (function () { - function XliffFile() { - this._warnings = []; - this._numberOfTransUnitsWithMissingId = 0; - } - /** - * Read an xlf-File. - * @param path Path to file - * @param encoding optional encoding of the xml. - * This is read from the file, but if you know it before, you can avoid reading the file twice. - * @return {XliffFile} - */ - XliffFile.fromFile = function (path, encoding) { - var xlf = new XliffFile(); - var xmlContent = xml_reader_1.XmlReader.readXmlFileContent(path, encoding); - xlf.initializeFromContent(xmlContent.content, path, xmlContent.encoding); - return xlf; - }; - XliffFile.prototype.initializeFromContent = function (xmlString, path, encoding) { - this.filename = path; - this.encoding = encoding; - this.xliffContent = cheerio.load(xmlString, CheerioOptions); - return this; - }; - XliffFile.prototype.forEachTransUnit = function (callback) { - this.initializeTransUnits(); - this.transUnits.forEach(function (tu) { return callback(tu); }); - }; - XliffFile.prototype.warnings = function () { - this.initializeTransUnits(); - return this._warnings; - }; - XliffFile.prototype.numberOfTransUnits = function () { - this.initializeTransUnits(); - return this.transUnits.length; - }; - XliffFile.prototype.numberOfTransUnitsWithMissingId = function () { - this.initializeTransUnits(); - return this._numberOfTransUnitsWithMissingId; - }; - /** - * Get trans-unit with given id. - * @param id - * @return {Cheerio} - */ - XliffFile.prototype.transUnitWithId = function (id) { - this.initializeTransUnits(); - return this.transUnits.find(function (tu) { return tu.id == id; }); - }; - XliffFile.prototype.initializeTransUnits = function () { - var _this = this; - if (util_1.isNullOrUndefined(this.transUnits)) { - this.transUnits = []; - var transUnitsInFile = this.xliffContent('trans-unit'); - transUnitsInFile.each(function (index, transunit) { - var id = cheerio(transunit).attr('id'); - if (!id) { - _this._warnings.push(util_1.format('oops, trans-unit without "id" found in master, please check file %s', _this.filename)); - _this._numberOfTransUnitsWithMissingId++; - } - _this.transUnits.push(new TransUnit(transunit, id)); - }); - } - }; - /** - * Get source language. - * @return {string} - */ - XliffFile.prototype.sourceLanguage = function () { - return this.xliffContent('file').attr('source-language'); - }; - /** - * Edit the source language. - * @param language - */ - XliffFile.prototype.setSourceLanguage = function (language) { - this.xliffContent('file').attr('source-language', language); - }; - /** - * Get target language. - * @return {string} - */ - XliffFile.prototype.targetLanguage = function () { - return this.xliffContent('file').attr('target-language'); - }; - /** - * Edit the target language. - * @param language - */ - XliffFile.prototype.setTargetLanguage = function (language) { - this.xliffContent('file').attr('target-language', language); - }; - /** - * Copy source to target to use it as dummy translation. - * (better than missing value) - */ - XliffFile.prototype.useSourceAsTarget = function (transUnit, isDefaultLang) { - transUnit.useSourceAsTarget(isDefaultLang); - }; - /** - * Translate a given trans unit. - * (very simple, just for tests) - * @param transUnit - * @param translation the translated string - */ - XliffFile.prototype.translate = function (transUnit, translation) { - transUnit.translate(translation); - }; - /** - * Add a new trans-unit. - * @param transUnit - */ - XliffFile.prototype.addNewTransUnit = function (transUnit) { - this.xliffContent('body').append(cheerio(transUnit.asXmlElement())); - this.initializeTransUnits(); - this.transUnits.push(transUnit); - }; - /** - * Remove the trans-unit with the given id. - * @param id - */ - XliffFile.prototype.removeTransUnitWithId = function (id) { - this.xliffContent('#' + id).remove(); - this.initializeTransUnits(); - this.transUnits = this.transUnits.filter(function (tu) { return tu.id != id; }); - }; - /** - * Save edited content to file. - */ - XliffFile.prototype.save = function () { - file_util_1.FileUtil.replaceContent(this.filename, this.xliffContent.xml(), this.encoding); - }; - return XliffFile; -}()); -exports.XliffFile = XliffFile; diff --git a/src/xliffmerge/xliff-file.ts b/src/xliffmerge/xliff-file.ts deleted file mode 100644 index b38afff..0000000 --- a/src/xliffmerge/xliff-file.ts +++ /dev/null @@ -1,326 +0,0 @@ -import * as cheerio from "cheerio"; -import {isNullOrUndefined, format} from 'util'; -import {ITranslationMessagesFile} from './i-translation-messages-file'; -import {ITransUnit} from './i-trans-unit'; -/** - * Created by martin on 23.02.2017. - * Ab xliff file read from a source file. - * Defines some relevant get and set method for reading and modifying such a file. - */ - -/** - * Read-Options for cheerio, enable xml mode. - * @type {{xmlMode: boolean}} - */ -const CheerioOptions: CheerioOptionsInterface = { - xmlMode: true, - decodeEntities: false, - -}; - -class TransUnit implements ITransUnit { - - constructor(private _transUnit: CheerioElement, private _id: string) { - - } - - public get id(): string { - return this._id; - } - - public sourceContent(): string { - return cheerio('source', this._transUnit).html(); - } - - /** - * the translated value (containing all markup, depends on the concrete format used). - */ - public targetContent(): string { - return cheerio('target', this._transUnit).html(); - } - - /** - * the translated value, but all placeholders are replaced with {{n}} (starting at 0) - * and all embedded html is replaced by direct html markup. - */ - targetContentNormalized(): string { - let directHtml = this.targetContent(); - if (!directHtml) { - return directHtml; - } - let normalized = directHtml; - let re0: RegExp = /<\/x>/g; - normalized = normalized.replace(re0, '{{0}}'); - let reN: RegExp = /<\/x>/g; - normalized = normalized.replace(reN, '{{$1}}'); - - let reStartBold: RegExp = /<\/x>/g; - normalized = normalized.replace(reStartBold, ''); - let reCloseBold: RegExp = /<\/x>/g; - normalized = normalized.replace(reCloseBold, ''); - - let reStartAnyTag: RegExp = /<\/x>/g; - normalized = normalized.replace(reStartAnyTag, '<$2>'); - let reCloseAnyTag: RegExp = /<\/x>/g; - normalized = normalized.replace(reCloseAnyTag, ''); - - return normalized; - } - - /** - * State of the translation. - * (new, final, ...) - */ - public targetState(): string { - return cheerio('target', this._transUnit).attr('state'); - } - - /** - * The description set in the template as value of the i18n-attribute. - * e.g. i18n="mydescription". - * In xliff this is stored as a note element with attribute from="description". - */ - public description(): string { - let descriptionElem = cheerio('note', this._transUnit).filter((index, elem) => cheerio(elem).attr('from') == 'description'); - return descriptionElem ? descriptionElem.html() : null; - } - - /** - * The meaning (intent) set in the template as value of the i18n-attribute. - * This is the part in front of the | symbol. - * e.g. i18n="meaning|mydescription". - * In xliff this is stored as a note element with attribute from="meaning". - */ - public meaning(): string { - let meaningElem = cheerio('note', this._transUnit).filter((index, elem) => cheerio(elem).attr('from') == 'meaning'); - return meaningElem ? meaningElem.html() : null; - } - - /** - * the real xml element used for trans unit. - * Here it is a element defined in XLIFF Spec. - * @return {CheerioElement} - */ - public asXmlElement(): CheerioElement { - return this._transUnit; - } - - /** - * Translate trans unit. - * (very simple, just for tests) - * @param translation the translated string - */ - public translate(translation: string) { - let target = cheerio('target', this._transUnit); - if (!target) { - let source = cheerio('source', this._transUnit); - source.parent().append(''); - target = cheerio('target', source.parent()); - } - let translationContainer: CheerioStatic = cheerio.load('' + translation + '', CheerioOptions); - let translationParts: Cheerio = translationContainer('dummy'); - target.contents().remove(); - translationParts.contents().each((index, element) => {target.append(cheerio(element));}); - target.attr('state', 'final'); - } - - /** - * Copy source to target to use it as dummy translation. - * (better than missing value) - */ - public useSourceAsTarget(isDefaultLang: boolean, copyContent: boolean) { - let source = cheerio('source', this._transUnit); - let target = cheerio('target', this._transUnit); - if (!target) { - source.parent().append(''); - target = cheerio('target', source.parent()); - } - if (isDefaultLang || copyContent) { - target.html(source.html()); - } else { - target.html(''); - } - if (isDefaultLang) { - target.attr('state', 'final'); - } else { - target.attr('state', 'new'); - } - } - -} - -export class XliffFile implements ITranslationMessagesFile { - - private _filename: string; - - private _encoding: string; - - private xliffContent: CheerioStatic; - - // trans-unit elements and their id from the file - private transUnits: ITransUnit[]; - - private _warnings: string[]; - private _numberOfTransUnitsWithMissingId: number; - - /** - * Create an xlf-File from source. - * @param xmlString source read from file. - * @param path Path to file - * @param encoding optional encoding of the xml. - * This is read from the file, but if you know it before, you can avoid reading the file twice. - * @return {XliffFile} - */ - constructor(xmlString: string, path: string, encoding: string) { - this._warnings = []; - this._numberOfTransUnitsWithMissingId = 0; - this.initializeFromContent(xmlString, path, encoding); - } - - private initializeFromContent(xmlString: string, path: string, encoding: string): XliffFile { - this._filename = path; - this._encoding = encoding; - this.xliffContent = cheerio.load(xmlString, CheerioOptions); - if (this.xliffContent('xliff').length < 1) { - throw new Error(format('File "%s" seems to be no xliff file (should contain an xliff element)', path)); - } - return this; - } - - public forEachTransUnit(callback: ((transunit: ITransUnit) => void)) { - this.initializeTransUnits(); - this.transUnits.forEach((tu) => callback(tu)); - } - - public warnings(): string[] { - this.initializeTransUnits(); - return this._warnings; - } - - public numberOfTransUnits(): number { - this.initializeTransUnits(); - return this.transUnits.length; - } - - public numberOfTransUnitsWithMissingId(): number { - this.initializeTransUnits(); - return this._numberOfTransUnitsWithMissingId; - } - - /** - * Get trans-unit with given id. - * @param id - * @return {Cheerio} - */ - public transUnitWithId(id: string): ITransUnit { - this.initializeTransUnits(); - return this.transUnits.find((tu) => tu.id == id); - } - - private initializeTransUnits() { - if (isNullOrUndefined(this.transUnits)) { - this.transUnits = []; - let transUnitsInFile = this.xliffContent('trans-unit'); - transUnitsInFile.each((index, transunit: CheerioElement) => { - let id = cheerio(transunit).attr('id'); - if (!id) { - this._warnings.push(format('oops, trans-unit without "id" found in master, please check file %s', this.filename)); - this._numberOfTransUnitsWithMissingId++; - } - this.transUnits.push(new TransUnit(transunit, id)); - }); - } - } - - /** - * Get source language. - * @return {string} - */ - public sourceLanguage(): string { - return this.xliffContent('file').attr('source-language'); - } - - /** - * Edit the source language. - * @param language - */ - public setSourceLanguage(language: string) { - this.xliffContent('file').attr('source-language', language); - } - - /** - * Get target language. - * @return {string} - */ - public targetLanguage(): string { - return this.xliffContent('file').attr('target-language'); - } - - /** - * Edit the target language. - * @param language - */ - public setTargetLanguage(language: string) { - this.xliffContent('file').attr('target-language', language); - } - - /** - * Copy source to target to use it as dummy translation. - * (better than missing value) - */ - public useSourceAsTarget(transUnit: ITransUnit, isDefaultLang: boolean, copyContent: boolean) { - transUnit.useSourceAsTarget(isDefaultLang, copyContent); - } - - /** - * Translate a given trans unit. - * (very simple, just for tests) - * @param transUnit - * @param translation the translated string - */ - public translate(transUnit: ITransUnit, translation: string) { - transUnit.translate(translation); - } - - /** - * Add a new trans-unit. - * @param transUnit - */ - public addNewTransUnit(transUnit: ITransUnit) { - this.xliffContent('body').append(cheerio(transUnit.asXmlElement())); - this.initializeTransUnits(); - this.transUnits.push(transUnit); - } - - /** - * Remove the trans-unit with the given id. - * @param id - */ - public removeTransUnitWithId(id: string) { - this.xliffContent('#' + id).remove(); - this.initializeTransUnits(); - this.transUnits = this.transUnits.filter((tu) => tu.id != id); - } - - /** - * The filename where the data is read from. - */ - public filename(): string { - return this._filename; - } - - /** - * The encoding if the xml content (UTF-8, ISO-8859-1, ...) - */ - public encoding(): string { - return this._encoding; - } - - /** - * The xml to be saved after changes are made. - */ - public editedContent(): string { - return this.xliffContent.xml(); - } - -} diff --git a/src/xliffmerge/xliff-merge-error.js b/src/xliffmerge/xliff-merge-error.js deleted file mode 100644 index ad901be..0000000 --- a/src/xliffmerge/xliff-merge-error.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Created by martin on 17.02.2017. - */ -"use strict"; -var __extends = (this && this.__extends) || function (d, b) { - for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); -}; -var XliffMergeError = (function (_super) { - __extends(XliffMergeError, _super); - function XliffMergeError(msg) { - var _this = _super.call(this, msg) || this; - // Set the prototype explicitly. - Object.setPrototypeOf(_this, XliffMergeError.prototype); - return _this; - } - return XliffMergeError; -}(Error)); -exports.XliffMergeError = XliffMergeError; diff --git a/src/xliffmerge/xliff-merge-parameters.js b/src/xliffmerge/xliff-merge-parameters.js deleted file mode 100644 index 0827fca..0000000 --- a/src/xliffmerge/xliff-merge-parameters.js +++ /dev/null @@ -1,264 +0,0 @@ -/** - * Created by martin on 17.02.2017. - * Collection of all parameters used by the tool. - * The parameters are read form the profile or defaults are used. - */ -"use strict"; -var fs = require("fs"); -var xliff_merge_error_1 = require("./xliff-merge-error"); -var util_1 = require("util"); -var XliffMergeParameters = (function () { - function XliffMergeParameters() { - this.errorsFound = []; - this.warningsFound = []; - } - /** - * Create Parameters. - * @param options command options - * @param profileContent given profile (if not, it is read from the profile path from options). - * @return {XliffMergeParameters} - */ - XliffMergeParameters.createFromOptions = function (options, profileContent) { - var parameters = new XliffMergeParameters(); - parameters.configure(options, profileContent); - return parameters; - }; - /** - * Initialize me from the profile content. - * (public only for test usage). - * @param options - * @param profileContent if null, read it from profile. - */ - XliffMergeParameters.prototype.configure = function (options, profileContent) { - this.errorsFound = []; - this.warningsFound = []; - if (!profileContent) { - profileContent = this.readProfile(options); - } - var validProfile = (!!profileContent); - if (options.quiet) { - this._quiet = options.quiet; - } - if (options.verbose) { - this._verbose = options.verbose; - } - if (validProfile) { - this.initializeFromConfig(profileContent); - // if languages are given as parameters, they ovveride everything said in profile - if (!!options.languages && options.languages.length > 0) { - this._languages = options.languages; - if (!this._defaultLanguage) { - this._defaultLanguage = this._languages[0]; - } - } - this.checkParameters(); - } - }; - /** - * Read profile. - * @param profilePath - * @return the read profile (empty, if none, null if errors) - */ - XliffMergeParameters.prototype.readProfile = function (options) { - var profilePath = options.profilePath; - if (!profilePath) { - return {}; - } - var content; - try { - content = fs.readFileSync(profilePath, 'UTF-8'); - } - catch (err) { - this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('could not read profile "' + profilePath + '"')); - return null; - } - var profileContent = JSON.parse(content); - return profileContent; - }; - XliffMergeParameters.prototype.initializeFromConfig = function (profileContent) { - if (!profileContent) { - return; - } - var profile = profileContent.xliffmergeOptions; - if (profile) { - if (!util_1.isNullOrUndefined(profile.quiet)) { - this._quiet = profile.quiet; - } - if (!util_1.isNullOrUndefined(profile.verbose)) { - this._verbose = profile.verbose; - } - if (profile.defaultLanguage) { - this._defaultLanguage = profile.defaultLanguage; - } - if (profile.languages) { - this._languages = profile.languages; - } - if (profile.srcDir) { - this._srcDir = profile.srcDir; - } - if (profile.angularCompilerOptions) { - if (profile.angularCompilerOptions.genDir) - this._genDir = profile.angularCompilerOptions.genDir; - } - if (profile.genDir) { - // this must be after angularCompilerOptions to be preferred - this._genDir = profile.genDir; - } - if (profile.i18nFile) { - this._i18nFile = profile.i18nFile; - } - if (profile.i18nFormat) { - this._i18nFormat = profile.i18nFormat; - } - if (profile.encoding) { - this._encoding = profile.encoding; - } - if (profile.removeUnusedIds) { - this._removeUnusedIds = profile.removeUnusedIds; - } - } - else { - this.warningsFound.push('did not find "xliffmergeOptions" in profile, using defaults'); - } - }; - /** - * Check all Parameters, wether they are complete and consistent. - * if something is wrong with the parameters, it is collected in errorsFound. - */ - XliffMergeParameters.prototype.checkParameters = function () { - var _this = this; - this.checkLanguageSyntax(this.defaultLanguage()); - if (this.languages().length == 0) { - this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('no languages specified')); - } - this.languages().forEach(function (lang) { - _this.checkLanguageSyntax(lang); - }); - var stats; - var err; - // srcDir should exists - try { - stats = fs.statSync(this.srcDir()); - } - catch (e) { - err = e; - } - if (!!err || !stats.isDirectory()) { - this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('srcDir "' + this.srcDir() + '" is not a directory')); - } - // genDir should exists - try { - stats = fs.statSync(this.genDir()); - } - catch (e) { - err = e; - } - if (!!err || !stats.isDirectory()) { - this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('genDir "' + this.genDir() + '" is not a directory')); - } - // master file MUST exist - try { - fs.accessSync(this.i18nFile(), fs.constants.R_OK); - } - catch (err) { - this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('i18nFile "' + this.i18nFile() + '" is not readable')); - } - // i18nFormat must be xlf or xmb - if (!(this.i18nFormat() === 'xlf' || this.i18nFormat() === 'xmb')) { - this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('i18nFormat "' + this.i18nFormat() + '" invalid, must be "xlf" or "xmb"')); - } - }; - /** - * Check syntax of language. - * Must be compatible with XML Schema type xsd:language. - * Pattern: [a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})* - * @param lang - */ - XliffMergeParameters.prototype.checkLanguageSyntax = function (lang) { - var pattern = /^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/; - if (!pattern.test(lang)) { - this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('language "' + lang + '" is not valid')); - } - }; - XliffMergeParameters.prototype.verbose = function () { - return (util_1.isNullOrUndefined(this._verbose)) ? false : this._verbose; - }; - XliffMergeParameters.prototype.quiet = function () { - return (util_1.isNullOrUndefined(this._quiet)) ? false : this._quiet; - }; - /** - * Debug output all parameters to commandOutput. - */ - XliffMergeParameters.prototype.showAllParameters = function (commandOutput) { - commandOutput.debug('xliffmerge Used Parameters:'); - commandOutput.debug('defaultLanguage:\t"%s"', this.defaultLanguage()); - commandOutput.debug('srcDir:\t"%s"', this.srcDir()); - commandOutput.debug('genDir:\t"%s"', this.genDir()); - commandOutput.debug('i18nFile:\t"%s"', this.i18nFile()); - commandOutput.debug('languages:\t%s', this.languages()); - }; - /** - * Default-Language, default en. - * @return {string} - */ - XliffMergeParameters.prototype.defaultLanguage = function () { - return this._defaultLanguage ? this._defaultLanguage : 'en'; - }; - /** - * Liste der zu bearbeitenden Sprachen. - * @return {string[]} - */ - XliffMergeParameters.prototype.languages = function () { - return this._languages ? this._languages : []; - }; - /** - * src directory, where the master xlif is located. - * @return {string} - */ - XliffMergeParameters.prototype.srcDir = function () { - return this._srcDir ? this._srcDir : '.'; - }; - /** - * The master xlif file (the one generated by ng-xi18n). - * Default is /messages.xlf. - * @return {string} - */ - XliffMergeParameters.prototype.i18nFile = function () { - return this.srcDir() + '/' + (this._i18nFile ? this._i18nFile : 'messages.' + this.i18nFormat()); - }; - /** - * Format of the master xlif file. - * Default is "xlf", possible are "xlf" or "xmb". - * @return {string} - */ - XliffMergeParameters.prototype.i18nFormat = function () { - return (this._i18nFormat ? this._i18nFormat : 'xlf'); - }; - /** - * evtl zu generierendes I18n-File mit den Übersetzungen für eine Sprache. - * @param lang - * @return {string} - */ - XliffMergeParameters.prototype.generatedI18nFile = function (lang) { - return this.genDir() + '/' + 'messages.' + lang + '.' + this.i18nFormat(); - }; - /** - * The encoding used to write new XLIFF-files. - * @return {string} - */ - XliffMergeParameters.prototype.encoding = function () { - return this._encoding ? this._encoding : 'UTF-8'; - }; - /** - * Output-Directory, where the output is written to. - * Default is . - */ - XliffMergeParameters.prototype.genDir = function () { - return this._genDir ? this._genDir : this.srcDir(); - }; - XliffMergeParameters.prototype.removeUnusedIds = function () { - return (util_1.isNullOrUndefined(this._removeUnusedIds)) ? true : this._removeUnusedIds; - }; - return XliffMergeParameters; -}()); -exports.XliffMergeParameters = XliffMergeParameters; diff --git a/src/xliffmerge/xliff-merge-parameters.ts b/src/xliffmerge/xliff-merge-parameters.ts index d4c8c95..aa9d511 100644 --- a/src/xliffmerge/xliff-merge-parameters.ts +++ b/src/xliffmerge/xliff-merge-parameters.ts @@ -4,7 +4,7 @@ * The parameters are read form the profile or defaults are used. */ -import fs = require("fs"); +import * as fs from "fs"; import {XliffMergeError} from './xliff-merge-error'; import {Stats} from 'fs'; import {CommandOutput} from '../common/command-output'; diff --git a/src/xliffmerge/xliff-merge.js b/src/xliffmerge/xliff-merge.js deleted file mode 100644 index bf0c8ae..0000000 --- a/src/xliffmerge/xliff-merge.js +++ /dev/null @@ -1,240 +0,0 @@ -"use strict"; -var program = require("commander"); -var command_output_1 = require("../common/command-output"); -var xliff_merge_parameters_1 = require("./xliff-merge-parameters"); -var xliff_merge_error_1 = require("./xliff-merge-error"); -var file_util_1 = require("../common/file-util"); -var version_1 = require("./version"); -var util_1 = require("util"); -var i_translation_messages_file_1 = require("./i-translation-messages-file"); -var XliffMerge = (function () { - function XliffMerge(commandOutput, options) { - this.commandOutput = commandOutput; - this.options = options; - this.parameters = null; - } - XliffMerge.main = function (argv) { - var options = XliffMerge.parseArgs(argv); - var result = new XliffMerge(new command_output_1.CommandOutput(process.stdout), options).run(); - process.exit(result); - }; - XliffMerge.parseArgs = function (argv) { - var languages = null; - delete program.verbose; - delete program.quiet; - delete program.profilePath; - delete program.languages; - program - .version(version_1.VERSION) - .arguments('') - .option('-p, --profile [configfile]', 'a json configuration file containing all relevant parameters (see details below)') - .option('-v, --verbose', 'show some output for debugging purposes') - .option('-q, --quiet', 'only show errors, nothing else') - .on('--help', function () { - console.log(' has to be a valid language short string, e,g. "en", "de", "de-ch"'); - console.log(''); - console.log(' configfile can contain the following values:'); - console.log('\tquiet verbose defaultLanguage languages srcDir i18nFile i18nFormat encoding genDir removeUnusedIds'); - console.log('\tfor details please consult the home page https://github.com/martinroob/ngx-i18nsupport'); - }) - .action(function (languageArray) { - languages = languageArray; - }) - .parse(argv); - var options = { - languages: languages - }; - if (program.profile) { - options.profilePath = program.profile; - } - if (program.quiet) { - options.quiet = true; - } - if (program.verbose && program.verbose > 0) { - options.verbose = true; - } - return options; - }; - /** - * For Tests, create instance with given profile - * @param commandOutput - * @param options - * @param profileContent - */ - XliffMerge.createFromOptions = function (commandOutput, options, profileContent) { - var instance = new XliffMerge(commandOutput, options); - instance.parameters = xliff_merge_parameters_1.XliffMergeParameters.createFromOptions(options, profileContent); - return instance; - }; - XliffMerge.prototype.run = function () { - try { - this.doRun(); - return 0; - } - catch (err) { - if (err instanceof xliff_merge_error_1.XliffMergeError) { - this.commandOutput.error(err.message); - return -1; - } - else { - // unhandled - this.commandOutput.error('oops ' + err); - throw err; - } - } - }; - /** - * Ausführen merge-Process. - */ - XliffMerge.prototype.doRun = function () { - var _this = this; - if (this.options && this.options.quiet) { - this.commandOutput.setQuiet(); - } - if (this.options && this.options.verbose) { - this.commandOutput.setVerbose(); - } - if (!this.parameters) { - this.parameters = xliff_merge_parameters_1.XliffMergeParameters.createFromOptions(this.options); - } - this.commandOutput.info('xliffmerge version %s', version_1.VERSION); - if (this.parameters.verbose()) { - this.parameters.showAllParameters(this.commandOutput); - } - if (this.parameters.errorsFound.length > 0) { - for (var _i = 0, _a = this.parameters.errorsFound; _i < _a.length; _i++) { - var err = _a[_i]; - this.commandOutput.error(err.message); - } - return; - } - if (this.parameters.warningsFound.length > 0) { - for (var _b = 0, _c = this.parameters.warningsFound; _b < _c.length; _b++) { - var warn = _c[_b]; - this.commandOutput.warn(warn); - } - } - this.readMaster(); - this.parameters.languages().forEach(function (lang) { - _this.processLanguage(lang); - }); - }; - /** - * Return the name of the generated file for given lang. - * @param lang - * @return {string} - */ - XliffMerge.prototype.generatedI18nFile = function (lang) { - return this.parameters.generatedI18nFile(lang); - }; - XliffMerge.prototype.readMaster = function () { - var _this = this; - this.master = i_translation_messages_file_1.TranslationMessagesFileReader.fromFile(this.parameters.i18nFormat(), this.parameters.i18nFile(), this.parameters.encoding()); - this.master.warnings().forEach(function (warning) { - _this.commandOutput.warn(warning); - }); - var count = this.master.numberOfTransUnits(); - var missingIdCount = this.master.numberOfTransUnitsWithMissingId(); - this.commandOutput.info('master contains %s trans-units', count); - if (missingIdCount > 0) { - this.commandOutput.warn('master contains %s trans-units, but there are %s without id', count, missingIdCount); - } - var sourceLang = this.master.sourceLanguage(); - if (sourceLang && sourceLang !== this.parameters.defaultLanguage()) { - this.commandOutput.warn('master says to have source-language="%s", should be "%s" (your defaultLanguage)', sourceLang, this.parameters.defaultLanguage()); - this.master.setSourceLanguage(this.parameters.defaultLanguage()); - this.master.save(); - this.commandOutput.warn('changed master source-language="%s" to "%s"', sourceLang, this.parameters.defaultLanguage()); - } - }; - XliffMerge.prototype.processLanguage = function (lang) { - this.commandOutput.debug('processing language %s', lang); - var languageXliffFile = this.parameters.generatedI18nFile(lang); - if (!file_util_1.FileUtil.exists(languageXliffFile)) { - this.createUntranslatedXliff(lang, languageXliffFile); - } - else { - this.mergeMasterTo(lang, languageXliffFile); - } - }; - /** - * create a new file for the language, which contains no translations, but all keys. - * in principle, this is just a copy of the master with target-language set. - * @param lang - * @param languageXliffFilePath - */ - XliffMerge.prototype.createUntranslatedXliff = function (lang, languageXliffFilePath) { - // copy master ... - file_util_1.FileUtil.copy(this.parameters.i18nFile(), languageXliffFilePath); - // read copy and set target-language - var languageSpecificMessagesFile = i_translation_messages_file_1.TranslationMessagesFileReader.fromFile(this.parameters.i18nFormat(), languageXliffFilePath, this.parameters.encoding()); - languageSpecificMessagesFile.setTargetLanguage(lang); - // copy source to target - var isDefaultLang = (lang == this.parameters.defaultLanguage()); - languageSpecificMessagesFile.forEachTransUnit(function (transUnit) { - languageSpecificMessagesFile.useSourceAsTarget(transUnit, isDefaultLang); - }); - // write it to file - languageSpecificMessagesFile.save(); - this.commandOutput.info('created new file "%s" for target-language="%s"', languageXliffFilePath, lang); - if (!isDefaultLang) { - this.commandOutput.warn('please translate file "%s" to target-language="%s"', languageXliffFilePath, lang); - } - }; - /** - * Merge all - * @param lang - * @param languageXliffFilePath - */ - XliffMerge.prototype.mergeMasterTo = function (lang, languageXliffFilePath) { - var _this = this; - // read lang specific file - var languageSpecificMessagesFile = i_translation_messages_file_1.TranslationMessagesFileReader.fromFile(this.parameters.i18nFormat(), languageXliffFilePath, this.parameters.encoding()); - var isDefaultLang = (lang == this.parameters.defaultLanguage()); - var newCount = 0; - this.master.forEachTransUnit(function (masterTransUnit) { - var transUnit = languageSpecificMessagesFile.transUnitWithId(masterTransUnit.id); - if (!transUnit) { - // oops, no translation, must be a new key, so add it - languageSpecificMessagesFile.useSourceAsTarget(masterTransUnit, isDefaultLang); - languageSpecificMessagesFile.addNewTransUnit(masterTransUnit); - newCount++; - } - }); - if (newCount > 0) { - this.commandOutput.warn('merged %s trans-units from master to "%s"', newCount, lang); - } - // remove all elements that are no longer used - var removeCount = 0; - languageSpecificMessagesFile.forEachTransUnit(function (transUnit) { - var existsInMaster = !util_1.isNullOrUndefined(_this.master.transUnitWithId(transUnit.id)); - if (!existsInMaster) { - if (_this.parameters.removeUnusedIds()) { - languageSpecificMessagesFile.removeTransUnitWithId(transUnit.id); - } - removeCount++; - } - }); - if (removeCount > 0) { - if (this.parameters.removeUnusedIds()) { - this.commandOutput.warn('removed %s unused trans-units in "%s"', removeCount, lang); - } - else { - this.commandOutput.warn('keeping %s unused trans-units in "%s", because removeUnused is disabled', removeCount, lang); - } - } - if (newCount == 0 && removeCount == 0) { - this.commandOutput.info('file for "%s" was up to date', lang); - } - else { - // write it to file - languageSpecificMessagesFile.save(); - this.commandOutput.info('updated file "%s" for target-language="%s"', languageXliffFilePath, lang); - if (newCount > 0 && !isDefaultLang) { - this.commandOutput.warn('please translate file "%s" to target-language="%s"', languageXliffFilePath, lang); - } - } - }; - return XliffMerge; -}()); -exports.XliffMerge = XliffMerge; diff --git a/src/xliffmerge/xliff-merge.spec.js b/src/xliffmerge/xliff-merge.spec.js deleted file mode 100644 index 22f35bc..0000000 --- a/src/xliffmerge/xliff-merge.spec.js +++ /dev/null @@ -1,430 +0,0 @@ -"use strict"; -var fs = require("fs"); -var xliff_merge_1 = require("./xliff-merge"); -var command_output_1 = require("../common/command-output"); -var writer_to_string_1 = require("../common/writer-to-string"); -var file_util_1 = require("../common/file-util"); -var xliff_file_1 = require("./xliff-file"); -var xmb_file_1 = require("./xmb-file"); -/** - * Created by martin on 18.02.2017. - * Testcases for XliffMerge. - */ -describe('XliffMerge test spec', function () { - var MASTER1FILE = 'ngExtractedMaster1.xlf'; - var MASTER2FILE = 'ngExtractedMaster2.xlf'; - var MASTER1XMBFILE = 'ngExtractedMaster1.xmb'; - var MASTER2XMBFILE = 'ngExtractedMaster2.xmb'; - var SRCDIR = 'test/testdata/i18n/'; - var MASTER1SRC = SRCDIR + MASTER1FILE; - var MASTER2SRC = SRCDIR + MASTER2FILE; - var MASTER1XMBSRC = SRCDIR + MASTER1XMBFILE; - var MASTER2XMBSRC = SRCDIR + MASTER2XMBFILE; - /** - * Workdir, not in git. - * Cleaned up for every test. - * Tests, that work on files, copy everything they need into this directory. - * @type {string} - */ - var WORKDIR = 'test/work/'; - var MASTERFILE = 'messages.xlf'; - var MASTER = WORKDIR + MASTERFILE; - var MASTERXMBFILE = 'messages.xmb'; - var MASTERXMB = WORKDIR + MASTERXMBFILE; - describe('test the tooling used in the tests', function () { - it('should write output to string (Test WriterToString)', function () { - var ws = new writer_to_string_1.WriterToString(); - ws.write('test test test\n'); - ws.write('line 2'); - expect(ws.writtenData()).toContain('line 2'); - }); - }); - describe('command line and configuration checks', function () { - it('should parse -v option', function () { - var options = xliff_merge_1.XliffMerge.parseArgs(['node', 'xliffmerge', '-v']); - expect(options.verbose).toBeTruthy(); - expect(options.quiet).toBeFalsy(); - }); - it('should parse -q option', function () { - var options = xliff_merge_1.XliffMerge.parseArgs(['node', 'xliffmerge', '-q']); - expect(options.quiet).toBeTruthy(); - expect(options.verbose).toBeFalsy(); - }); - it('should output an errror (no languages) when called with defaults', function (done) { - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var xliffMergeCmd = new xliff_merge_1.XliffMerge(commandOut, {}); - xliffMergeCmd.run(); - expect(ws.writtenData()).toContain('ERROR'); - expect(ws.writtenData()).toContain('no languages specified'); - done(); - }); - it('should output an errror (i18nfile) when called with defaults', function (done) { - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var xliffMergeCmd = new xliff_merge_1.XliffMerge(commandOut, { languages: ['de', 'en'] }); - xliffMergeCmd.run(); - expect(ws.writtenData()).toContain('ERROR'); - expect(ws.writtenData()).toContain('i18nFile'); - done(); - }); - it('should output an errror (could not read) when called with a non existing profile', function (done) { - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var xliffMergeCmd = new xliff_merge_1.XliffMerge(commandOut, { verbose: true, profilePath: 'lmaa' }); - xliffMergeCmd.run(); - expect(ws.writtenData()).toContain('ERROR'); - expect(ws.writtenData()).toContain('could not read profile'); - done(); - }); - it('should read test config file', function (done) { - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { profilePath: './test/testdata/xliffmergeconfig.json', verbose: true }, null); - xliffMergeCmd.run(); - expect(ws.writtenData()).toContain('languages: de,en'); - done(); - }); - it('should output an errror (srcDir not readable) when called with a non existing srcDir', function (done) { - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - srcDir: 'lmaa', - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { verbose: true }, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).toContain('ERROR'); - expect(ws.writtenData()).toContain('srcDir "lmaa" is not a directory'); - done(); - }); - it('should output an errror (genDir not existing) when called with a non existing genDir', function (done) { - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - genDir: 'lmaa', - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { verbose: true }, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).toContain('ERROR'); - expect(ws.writtenData()).toContain('genDir "lmaa" is not a directory'); - done(); - }); - it('should output an errror (i18nFile is not readable) when called with a non existing master file', function (done) { - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - srcDir: 'test/testdata', - i18nFile: 'nonexistingmaster.xlf' - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, {}, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).toContain('ERROR'); - expect(ws.writtenData()).toContain('i18nFile "test/testdata/nonexistingmaster.xlf" is not readable'); - done(); - }); - it('should output an errror (language not valid) when called with an invalid language code', function (done) { - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - defaultLanguage: 'de/ch', - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, {}, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).toContain('ERROR'); - expect(ws.writtenData()).toContain('language "de/ch" is not valid'); - done(); - }); - it('should output an errror (i18nFormat invalid) when called with an invalid i18n format', function (done) { - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - i18nFormat: 'unknown', - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, {}, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).toContain('ERROR'); - expect(ws.writtenData()).toContain('i18nFormat "unknown" invalid'); - done(); - }); - it('should accept i18n format xlf', function (done) { - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - i18nFormat: 'xlf', - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, {}, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).not.toContain('i18nFormat'); - done(); - }); - it('should accept i18n format xmb', function (done) { - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - i18nFormat: 'xmb', - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, {}, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).not.toContain('i18nFormat'); - done(); - }); - it('should read languages from config file', function (done) { - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - languages: ['de', 'en', 'fr'], - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { verbose: true }, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).toContain('languages: de,en,fr'); - done(); - }); - }); - describe('Merge process checks for format xlf', function () { - var ID_TRANSLATED_SCHLIESSEN = "1ead0ad1063d0c9e005fe56c9529aef4c1ef9d21"; // an ID from ngExtractedMaster1.xlf - var ID_REMOVED_STARTSEITE = "c536247d71822c272f8e9155f831e0efb5aa0d31"; // an ID that will be removed in master2 - var ID_REMOVED_SUCHEN = "d17aee1ddf9fe1c0afe8440e02ef5ab906a69699"; // another removed ID - beforeEach(function () { - if (!fs.existsSync(WORKDIR)) { - fs.mkdirSync(WORKDIR); - } - // cleanup workdir - file_util_1.FileUtil.deleteFolderContentRecursive(WORKDIR); - }); - it('should fix source language, if the masters lang is not the default', function (done) { - file_util_1.FileUtil.copy(MASTER1SRC, MASTER); - var master = xliff_file_1.XliffFile.fromFile(MASTER); - expect(master.sourceLanguage()).toBe('en'); // master is german, but ng-18n extracts it as en - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - defaultLanguage: 'de', - srcDir: WORKDIR, - genDir: WORKDIR, - i18nFile: MASTERFILE, - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de'] }, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).not.toContain('ERROR'); - expect(ws.writtenData()).toContain('master says to have source-language="en"'); - expect(ws.writtenData()).toContain('changed master source-language="en" to "de"'); - var newmaster = xliff_file_1.XliffFile.fromFile(MASTER); - expect(newmaster.sourceLanguage()).toBe('de'); // master is german - done(); - }); - it('should generate translated file for default language de from master', function (done) { - file_util_1.FileUtil.copy(MASTER1SRC, MASTER); - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - defaultLanguage: 'de', - srcDir: WORKDIR, - genDir: WORKDIR, - i18nFile: MASTERFILE - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de'] }, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).not.toContain('ERROR'); - var langFile = xliff_file_1.XliffFile.fromFile(xliffMergeCmd.generatedI18nFile('de')); - expect(langFile.sourceLanguage()).toBe('de'); - expect(langFile.targetLanguage()).toBe('de'); - langFile.forEachTransUnit(function (tu) { - expect(tu.targetContent()).toBe(tu.sourceContent()); - expect(tu.targetState()).toBe('final'); - }); - done(); - }); - it('should generate translated file for all languages', function (done) { - file_util_1.FileUtil.copy(MASTER1SRC, MASTER); - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - defaultLanguage: 'de', - srcDir: WORKDIR, - genDir: WORKDIR, - i18nFile: MASTERFILE - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de', 'en'] }, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).not.toContain('ERROR'); - var langFileGerman = xliff_file_1.XliffFile.fromFile(xliffMergeCmd.generatedI18nFile('de')); - expect(langFileGerman.sourceLanguage()).toBe('de'); - expect(langFileGerman.targetLanguage()).toBe('de'); - langFileGerman.forEachTransUnit(function (tu) { - expect(tu.targetContent()).toBe(tu.sourceContent()); - expect(tu.targetState()).toBe('final'); - }); - var langFileEnglish = xliff_file_1.XliffFile.fromFile(xliffMergeCmd.generatedI18nFile('en')); - expect(langFileEnglish.sourceLanguage()).toBe('de'); - expect(langFileEnglish.targetLanguage()).toBe('en'); - langFileEnglish.forEachTransUnit(function (tu) { - expect(tu.targetContent()).toBe(tu.sourceContent()); - expect(tu.targetState()).toBe('new'); - }); - done(); - }); - it('should merge translated file for all languages', function (done) { - file_util_1.FileUtil.copy(MASTER1SRC, MASTER); - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - defaultLanguage: 'de', - srcDir: WORKDIR, - genDir: WORKDIR, - i18nFile: MASTERFILE - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de', 'en'] }, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).not.toContain('ERROR'); - // now translate some texts in the English version - var langFileEnglish = xliff_file_1.XliffFile.fromFile(xliffMergeCmd.generatedI18nFile('en')); - var tu = langFileEnglish.transUnitWithId(ID_TRANSLATED_SCHLIESSEN); - expect(tu).toBeTruthy(); - langFileEnglish.translate(tu, 'Close'); - langFileEnglish.save(); - // next step, use another master - file_util_1.FileUtil.copy(MASTER2SRC, MASTER); - ws = new writer_to_string_1.WriterToString(); - commandOut = new command_output_1.CommandOutput(ws); - xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de', 'en'] }, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).not.toContain('ERROR'); - expect(ws.writtenData()).toContain('merged 12 trans-units from master to "en"'); - expect(ws.writtenData()).toContain('removed 2 unused trans-units in "en"'); - // look, that the new file contains the old translation - langFileEnglish = xliff_file_1.XliffFile.fromFile(xliffMergeCmd.generatedI18nFile('en')); - expect(langFileEnglish.transUnitWithId(ID_TRANSLATED_SCHLIESSEN).targetContent()).toBe('Close'); - // look, that the removed IDs are really removed. - expect(langFileEnglish.transUnitWithId(ID_REMOVED_STARTSEITE)).toBeFalsy(); - expect(langFileEnglish.transUnitWithId(ID_REMOVED_SUCHEN)).toBeFalsy(); - done(); - }); - }); - describe('Merge process checks for format xmb', function () { - var ID_TRANSLATED_MYFIRST = "2047558209369508311"; // an ID from ngExtractedMaster1.xlf - var ID_REMOVED_DESCRIPTION = "7499557905529977371"; // an ID that will be removed in master2 - var ID_REMOVED_DESCRIPTION2 = "3274258156935474372"; // another removed ID - var ID_ADDED = "3274258156935474372"; // an ID that will be added in master2 - beforeEach(function () { - if (!fs.existsSync(WORKDIR)) { - fs.mkdirSync(WORKDIR); - } - // cleanup workdir - file_util_1.FileUtil.deleteFolderContentRecursive(WORKDIR); - }); - it('should generate translated file for default language de from xmb master', function (done) { - file_util_1.FileUtil.copy(MASTER1XMBSRC, MASTERXMB); - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - defaultLanguage: 'de', - srcDir: WORKDIR, - genDir: WORKDIR, - i18nFile: MASTERXMBFILE, - i18nFormat: 'xmb' - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de'] }, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).not.toContain('ERROR'); - var langFile = xmb_file_1.XmbFile.fromFile(xliffMergeCmd.generatedI18nFile('de')); - expect(langFile.sourceLanguage()).toBeFalsy(); // not supported in xmb - expect(langFile.targetLanguage()).toBeFalsy(); - langFile.forEachTransUnit(function (tu) { - expect(tu.targetContent()).toBe(tu.sourceContent()); - expect(tu.targetState()).toBeFalsy(); - }); - done(); - }); - it('should generate translated file for all languages using format xmb', function (done) { - file_util_1.FileUtil.copy(MASTER1XMBSRC, MASTERXMB); - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - defaultLanguage: 'de', - srcDir: WORKDIR, - genDir: WORKDIR, - i18nFile: MASTERXMBFILE, - i18nFormat: 'xmb' - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de', 'en'] }, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).not.toContain('ERROR'); - var langFileGerman = xmb_file_1.XmbFile.fromFile(xliffMergeCmd.generatedI18nFile('de')); - langFileGerman.forEachTransUnit(function (tu) { - expect(tu.targetContent()).toBe(tu.sourceContent()); - }); - var langFileEnglish = xmb_file_1.XmbFile.fromFile(xliffMergeCmd.generatedI18nFile('en')); - langFileEnglish.forEachTransUnit(function (tu) { - expect(tu.targetContent()).toBe(tu.sourceContent()); - }); - done(); - }); - it('should merge translated file for all languages using format xmb', function (done) { - file_util_1.FileUtil.copy(MASTER1XMBSRC, MASTERXMB); - var ws = new writer_to_string_1.WriterToString(); - var commandOut = new command_output_1.CommandOutput(ws); - var profileContent = { - xliffmergeOptions: { - defaultLanguage: 'de', - srcDir: WORKDIR, - genDir: WORKDIR, - i18nFile: MASTERXMBFILE, - i18nFormat: 'xmb' - } - }; - var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de', 'en'] }, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).not.toContain('ERROR'); - // now translate some texts in the English version - var langFileEnglish = xmb_file_1.XmbFile.fromFile(xliffMergeCmd.generatedI18nFile('en')); - var tu = langFileEnglish.transUnitWithId(ID_TRANSLATED_MYFIRST); - expect(tu).toBeTruthy(); - langFileEnglish.translate(tu, 'My first app'); - langFileEnglish.save(); - // next step, use another master - file_util_1.FileUtil.copy(MASTER2XMBSRC, MASTER); - ws = new writer_to_string_1.WriterToString(); - commandOut = new command_output_1.CommandOutput(ws); - xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de', 'en'] }, profileContent); - xliffMergeCmd.run(); - expect(ws.writtenData()).not.toContain('ERROR'); - expect(ws.writtenData()).toContain('merged 100 trans-units from master to "en"'); - expect(ws.writtenData()).toContain('removed 100 unused trans-units in "en"'); - // look, that the new file contains the old translation - langFileEnglish = xliff_file_1.XliffFile.fromFile(xliffMergeCmd.generatedI18nFile('en')); - expect(langFileEnglish.transUnitWithId(ID_TRANSLATED_MYFIRST).targetContent()).toBe('My first app'); - // look, that the removed IDs are really removed. - expect(langFileEnglish.transUnitWithId(ID_REMOVED_DESCRIPTION)).toBeFalsy(); - expect(langFileEnglish.transUnitWithId(ID_REMOVED_DESCRIPTION2)).toBeFalsy(); - done(); - }); - }); -}); diff --git a/src/xliffmerge/xliff-merge.spec.ts b/src/xliffmerge/xliff-merge.spec.ts index d8165d8..ac6bc87 100644 --- a/src/xliffmerge/xliff-merge.spec.ts +++ b/src/xliffmerge/xliff-merge.spec.ts @@ -1,16 +1,14 @@ -import fs = require("fs"); -import child_process = require("child_process"); +import * as fs from "fs"; +import * as child_process from "child_process"; import {XliffMerge} from './xliff-merge'; import {ProgramOptions, IConfigFile} from './i-xliff-merge-options'; import {CommandOutput} from '../common/command-output'; import WritableStream = NodeJS.WritableStream; import {WriterToString} from '../common/writer-to-string'; import {FileUtil} from '../common/file-util'; -import {ITranslationMessagesFile} from './i-translation-messages-file'; -import {ITransUnit} from './i-trans-unit'; -import {XliffFile} from './xliff-file'; -import {XmbFile} from './xmb-file'; +import {TranslationMessagesFileFactory, ITranslationMessagesFile, ITransUnit} from 'ngx-i18nsupport-lib'; import {TranslationMessagesFileReader} from './translation-messages-file-reader'; + /** * Created by martin on 18.02.2017. * Testcases for XliffMerge. @@ -33,16 +31,24 @@ describe('XliffMerge test spec', () => { * Helper function to read Xliff from File * @type {string} */ - function readXliff(path: string): XliffFile { - return TranslationMessagesFileReader.fromFile('xlf', path, ENCODING); + function readXliff(path: string): ITranslationMessagesFile { + return TranslationMessagesFileReader.fromFile('xlf', path, ENCODING); } /** * Helper function to read Xmb from File * @type {string} */ - function readXmb(path: string): XmbFile { - return TranslationMessagesFileReader.fromFile('xmb', path, ENCODING); + function readXmb(path: string): ITranslationMessagesFile { + return TranslationMessagesFileReader.fromFile('xmb', path, ENCODING); + } + + /** + * Helper function to read Xmb from 2 Files, the xmb and the master + * @type {string} + */ + function readXmbWithMaster(path: string, masterPath: string): ITranslationMessagesFile { + return TranslationMessagesFileReader.fromFile('xmb', path, ENCODING, masterPath); } describe('test the tooling used in the tests', () => { @@ -269,7 +275,7 @@ describe('XliffMerge test spec', () => { it('should fix source language, if the masters lang is not the default', (done) => { FileUtil.copy(MASTER1SRC, MASTER); - let master: XliffFile = readXliff(MASTER); + let master: ITranslationMessagesFile = readXliff(MASTER); expect(master.sourceLanguage()).toBe('en'); // master is german, but ng-18n extracts it as en let ws: WriterToString = new WriterToString(); let commandOut = new CommandOutput(ws); @@ -286,7 +292,7 @@ describe('XliffMerge test spec', () => { expect(ws.writtenData()).not.toContain('ERROR'); expect(ws.writtenData()).toContain('master says to have source-language="en"'); expect(ws.writtenData()).toContain('changed master source-language="en" to "de"'); - let newmaster: XliffFile = readXliff(MASTER); + let newmaster: ITranslationMessagesFile = readXliff(MASTER); expect(newmaster.sourceLanguage()).toBe('de'); // master is german done(); }); @@ -307,7 +313,7 @@ describe('XliffMerge test spec', () => { let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de']}, profileContent); xliffMergeCmd.run(); expect(ws.writtenData()).not.toContain('ERROR'); - let langFile: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('de')); + let langFile: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('de')); expect(langFile.sourceLanguage()).toBe('de'); expect(langFile.targetLanguage()).toBe('de'); langFile.forEachTransUnit((tu: ITransUnit) => { @@ -332,14 +338,14 @@ describe('XliffMerge test spec', () => { let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent); xliffMergeCmd.run(); expect(ws.writtenData()).not.toContain('ERROR'); - let langFileGerman: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('de')); + let langFileGerman: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('de')); expect(langFileGerman.sourceLanguage()).toBe('de'); expect(langFileGerman.targetLanguage()).toBe('de'); langFileGerman.forEachTransUnit((tu: ITransUnit) => { expect(tu.targetContent()).toBe(tu.sourceContent()); expect(tu.targetState()).toBe('final'); }); - let langFileEnglish: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('en')); + let langFileEnglish: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('en')); expect(langFileEnglish.sourceLanguage()).toBe('de'); expect(langFileEnglish.targetLanguage()).toBe('en'); langFileEnglish.forEachTransUnit((tu: ITransUnit) => { @@ -365,14 +371,14 @@ describe('XliffMerge test spec', () => { let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent); xliffMergeCmd.run(); expect(ws.writtenData()).not.toContain('ERROR'); - let langFileGerman: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('de')); + let langFileGerman: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('de')); expect(langFileGerman.sourceLanguage()).toBe('de'); expect(langFileGerman.targetLanguage()).toBe('de'); langFileGerman.forEachTransUnit((tu: ITransUnit) => { expect(tu.targetContent()).toBe(tu.sourceContent()); expect(tu.targetState()).toBe('final'); }); - let langFileEnglish: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('en')); + let langFileEnglish: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('en')); expect(langFileEnglish.sourceLanguage()).toBe('de'); expect(langFileEnglish.targetLanguage()).toBe('en'); langFileEnglish.forEachTransUnit((tu: ITransUnit) => { @@ -399,7 +405,7 @@ describe('XliffMerge test spec', () => { expect(ws.writtenData()).not.toContain('ERROR'); // now translate some texts in the English version - let langFileEnglish: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('en')); + let langFileEnglish: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('en')); let tu: ITransUnit = langFileEnglish.transUnitWithId(ID_TRANSLATED_SCHLIESSEN); expect(tu).toBeTruthy(); langFileEnglish.translate(tu, 'Close'); @@ -450,7 +456,7 @@ describe('XliffMerge test spec', () => { // look, that the new file contains the translation langFileEnglish = readXliff(xliffMergeCmd.generatedI18nFile('en')); - expect(langFileEnglish.transUnitWithId(ID_WITH_PLACEHOLDER).targetContent()).toBe('Item of added.'); + expect(langFileEnglish.transUnitWithId(ID_WITH_PLACEHOLDER).targetContent()).toBe('Item of added.'); done(); }); @@ -461,6 +467,7 @@ describe('XliffMerge test spec', () => { let MASTER1FILE = 'ngxtranslate.xlf'; let MASTER1SRC = SRCDIR + MASTER1FILE; + let MASTER_WITHOUT_NGX_TRANSLATE_STUFF = SRCDIR + 'ngExtractedMaster1.xlf'; let MASTERFILE = 'messages.xlf'; let MASTER = WORKDIR + MASTERFILE; @@ -477,7 +484,7 @@ describe('XliffMerge test spec', () => { it('should return null for unset description and meaning in master xlf file', (done) => { FileUtil.copy(MASTER1SRC, MASTER); - let master: XliffFile = readXliff(MASTER); + let master: ITranslationMessagesFile = readXliff(MASTER); expect(master.transUnitWithId(ID_NODESC_NOMEANING).description()).toBeFalsy(); expect(master.transUnitWithId(ID_NODESC_NOMEANING).meaning()).toBeFalsy(); done(); @@ -485,7 +492,7 @@ describe('XliffMerge test spec', () => { it('should find description and meaning in master xlf file', (done) => { FileUtil.copy(MASTER1SRC, MASTER); - let master: XliffFile = readXliff(MASTER); + let master: ITranslationMessagesFile = readXliff(MASTER); expect(master.transUnitWithId(ID_MONDAY).description()).toBe('ngx-translate'); expect(master.transUnitWithId(ID_MONDAY).meaning()).toBe('dateservice.monday'); done(); @@ -506,7 +513,7 @@ describe('XliffMerge test spec', () => { let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de']}, profileContent); xliffMergeCmd.run(); expect(ws.writtenData()).not.toContain('ERROR'); - let langFile: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('de')); + let langFile: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('de')); expect(langFile.transUnitWithId(ID_MONDAY).description()).toBe('ngx-translate'); expect(langFile.transUnitWithId(ID_MONDAY).meaning()).toBe('dateservice.monday'); done(); @@ -536,6 +543,7 @@ describe('XliffMerge test spec', () => { expect(translation.myapp).toBeTruthy(); expect(translation.dateservice.monday).toBe("Montag"); expect(translation.dateservice.friday).toBe("Freitag"); + expect(translation.explicitlysetids.test1).toBe("Explizit gesetzte ID"); done(); }); @@ -595,6 +603,27 @@ describe('XliffMerge test spec', () => { done(); }); + it('should not write empty translation json file for ngx-translate, if there are no translation (issue #18)', (done) => { + FileUtil.copy(MASTER_WITHOUT_NGX_TRANSLATE_STUFF, MASTER); + let ws: WriterToString = new WriterToString(); + let commandOut = new CommandOutput(ws); + let profileContent: IConfigFile = { + xliffmergeOptions: { + defaultLanguage: 'de', + srcDir: WORKDIR, + genDir: WORKDIR, + i18nFile: MASTERFILE, + supportNgxTranslate: true + } + }; + let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de']}, profileContent); + xliffMergeCmd.run(); + expect(ws.writtenData()).not.toContain('ERROR'); + let translationJsonFilename = xliffMergeCmd.generatedNgxTranslateFile('de'); + expect(FileUtil.exists(translationJsonFilename)).toBeFalsy(); + done(); + }); + }); describe('Merge process checks for format xmb', () => { @@ -637,8 +666,8 @@ describe('XliffMerge test spec', () => { xliffMergeCmd.run(); expect(ws.writtenData()).not.toContain('ERROR'); let langFile: ITranslationMessagesFile = readXmb(xliffMergeCmd.generatedI18nFile('de')); - expect(langFile.sourceLanguage()).toBeFalsy(); // not supported in xmb - expect(langFile.targetLanguage()).toBeFalsy(); + expect(langFile.sourceLanguage()).toBeFalsy(); // not supported in xmb when there is no master + expect(langFile.targetLanguage()).toBe('de'); // guess from filename langFile.forEachTransUnit((tu: ITransUnit) => { expect(tu.targetContent()).toBe(tu.sourceContent()); expect(tu.targetState()).toBeFalsy(); @@ -704,7 +733,7 @@ describe('XliffMerge test spec', () => { xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent); xliffMergeCmd.run(); expect(ws.writtenData()).not.toContain('ERROR'); - expect(ws.writtenData()).toContain('merged 2 trans-units from master to "en"'); + expect(ws.writtenData()).toContain('merged 1 trans-units from master to "en"'); expect(ws.writtenData()).toContain('removed 2 unused trans-units in "en"'); // look, that the new file contains the old translation @@ -751,12 +780,63 @@ describe('XliffMerge test spec', () => { done(); }); + it('should return status new for all trans units using format xmb with master file', (done) => { + FileUtil.copy(MASTER1SRC, MASTER); + let ws: WriterToString = new WriterToString(); + let commandOut = new CommandOutput(ws); + let profileContent: IConfigFile = { + xliffmergeOptions: { + defaultLanguage: 'de', + srcDir: WORKDIR, + genDir: WORKDIR, + i18nFile: MASTERFILE, + i18nFormat: 'xmb' + } + }; + let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent); + xliffMergeCmd.run(); + expect(ws.writtenData()).not.toContain('ERROR'); + let langFileEnglish: ITranslationMessagesFile = readXmbWithMaster(xliffMergeCmd.generatedI18nFile('en'), MASTER); + langFileEnglish.forEachTransUnit((tu: ITransUnit) => { + expect(tu.targetState()).toBe('new'); + }); + done(); + }); + + it('should return status final for a translated trans unit using format xmb with master file', (done) => { + FileUtil.copy(MASTER1SRC, MASTER); + let ws: WriterToString = new WriterToString(); + let commandOut = new CommandOutput(ws); + let profileContent: IConfigFile = { + xliffmergeOptions: { + defaultLanguage: 'de', + srcDir: WORKDIR, + genDir: WORKDIR, + i18nFile: MASTERFILE, + i18nFormat: 'xmb' + } + }; + let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent); + xliffMergeCmd.run(); + expect(ws.writtenData()).not.toContain('ERROR'); + let langFileEnglish: ITranslationMessagesFile = readXmbWithMaster(xliffMergeCmd.generatedI18nFile('en'), MASTER); + // now translate some texts in the English version + let tu: ITransUnit = langFileEnglish.transUnitWithId(ID_TRANSLATED_MYFIRST); + expect(tu).toBeTruthy(); + expect(tu.sourceContent()).toBe('Meine erste I18N-Anwendung'); + expect(tu.targetState()).toBe('new'); + langFileEnglish.translate(tu, 'my first i18n application'); + expect(tu.targetState()).toBe('final'); + done(); + }); + }); describe('ngx-translate processing for format xmb', () => { let MASTER1FILE = 'ngxtranslate.xmb'; let MASTER1SRC = SRCDIR + MASTER1FILE; + let MASTER_WITHOUT_NGX_TRANSLATE_STUFF = SRCDIR + 'ngExtractedMaster1.xmb'; let MASTERFILE = 'messages.xmb'; let MASTER = WORKDIR + MASTERFILE; @@ -773,7 +853,7 @@ describe('XliffMerge test spec', () => { it('should return null for unset description and meaning in master xmb file', (done) => { FileUtil.copy(MASTER1SRC, MASTER); - let master: XmbFile = readXmb(MASTER); + let master: ITranslationMessagesFile = readXmb(MASTER); expect(master.transUnitWithId(ID_NODESC_NOMEANING).description()).toBeFalsy(); expect(master.transUnitWithId(ID_NODESC_NOMEANING).meaning()).toBeFalsy(); done(); @@ -781,7 +861,7 @@ describe('XliffMerge test spec', () => { it('should find description and meaning in master xmb file', (done) => { FileUtil.copy(MASTER1SRC, MASTER); - let master: XmbFile = readXmb(MASTER); + let master: ITranslationMessagesFile = readXmb(MASTER); expect(master.transUnitWithId(ID_MONDAY).description()).toBe('ngx-translate'); expect(master.transUnitWithId(ID_MONDAY).meaning()).toBe('dateservice.monday'); done(); @@ -803,7 +883,7 @@ describe('XliffMerge test spec', () => { let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de']}, profileContent); xliffMergeCmd.run(); expect(ws.writtenData()).not.toContain('ERROR'); - let langFile: XmbFile = readXmb(xliffMergeCmd.generatedI18nFile('de')); + let langFile: ITranslationMessagesFile = readXmb(xliffMergeCmd.generatedI18nFile('de')); expect(langFile.transUnitWithId(ID_MONDAY).description()).toBe('ngx-translate'); expect(langFile.transUnitWithId(ID_MONDAY).meaning()).toBe('dateservice.monday'); done(); @@ -834,6 +914,8 @@ describe('XliffMerge test spec', () => { expect(translation.myapp).toBeTruthy(); expect(translation.dateservice.monday).toBe("Montag"); expect(translation.dateservice.friday).toBe("Freitag"); + expect(translation.explicitlysetids.test1).toBe("Explizit gesetzte ID"); + expect(Object.keys(translation).length).toBe(5); done(); }); @@ -895,5 +977,27 @@ describe('XliffMerge test spec', () => { done(); }); + it('should not write empty translation json file for ngx-translate, if there are no translation (issue #18)', (done) => { + FileUtil.copy(MASTER_WITHOUT_NGX_TRANSLATE_STUFF, MASTER); + let ws: WriterToString = new WriterToString(); + let commandOut = new CommandOutput(ws); + let profileContent: IConfigFile = { + xliffmergeOptions: { + defaultLanguage: 'de', + srcDir: WORKDIR, + genDir: WORKDIR, + i18nFile: MASTERFILE, + i18nFormat: 'xmb', + supportNgxTranslate: true + } + }; + let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de']}, profileContent); + xliffMergeCmd.run(); + expect(ws.writtenData()).not.toContain('ERROR'); + let translationJsonFilename = xliffMergeCmd.generatedNgxTranslateFile('de'); + expect(FileUtil.exists(translationJsonFilename)).toBeFalsy(); + done(); + }); + }); }); diff --git a/src/xliffmerge/xliff-merge.ts b/src/xliffmerge/xliff-merge.ts index 2555b1d..834d2ed 100644 --- a/src/xliffmerge/xliff-merge.ts +++ b/src/xliffmerge/xliff-merge.ts @@ -6,10 +6,9 @@ import {FileUtil} from '../common/file-util'; import {VERSION} from './version'; import WritableStream = NodeJS.WritableStream; import {isNullOrUndefined} from 'util'; -import {ITranslationMessagesFile} from './i-translation-messages-file'; +import {ITranslationMessagesFile, ITransUnit} from 'ngx-i18nsupport-lib'; import {ProgramOptions, IConfigFile} from './i-xliff-merge-options'; import {NgxTranslateExtractor} from './ngx-translate-extractor'; -import {ITransUnit} from './i-trans-unit'; import {TranslationMessagesFileReader} from './translation-messages-file-reader'; /** diff --git a/src/xliffmerge/xmb-file.js b/src/xliffmerge/xmb-file.js deleted file mode 100644 index 653b58f..0000000 --- a/src/xliffmerge/xmb-file.js +++ /dev/null @@ -1,211 +0,0 @@ -"use strict"; -var xml_reader_1 = require("./xml-reader"); -var util_1 = require("util"); -var file_util_1 = require("../common/file-util"); -/** - * Created by martin on 10.03.2017. - * xmb-File access. - */ -/** - * Read-Options for cheerio, enable xml mode. - * @type {{xmlMode: boolean}} - */ -var CheerioOptions = { - xmlMode: true, - decodeEntities: false, -}; -var TransUnit = (function () { - function TransUnit(_msg, _id) { - this._msg = _msg; - this._id = _id; - } - Object.defineProperty(TransUnit.prototype, "_transUnitElement", { - get: function () { - return this._msg; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(TransUnit.prototype, "id", { - get: function () { - return this._id; - }, - enumerable: true, - configurable: true - }); - TransUnit.prototype.sourceContent = function () { - return cheerio(this._msg).html(); - }; - TransUnit.prototype.targetContent = function () { - // in fact, target and source are just the same in xmb - return cheerio(this._msg).html(); - }; - TransUnit.prototype.targetState = function () { - return null; // not supported in xmb - }; - /** - * the real xml element used for trans unit. - * Here it is a element. - * @return {CheerioElement} - */ - TransUnit.prototype.asXmlElement = function () { - return this._msg; - }; - /** - * Copy source to target to use it as dummy translation. - * (better than missing value) - * In xmb there is nothing to do, because there is only a target, no source. - */ - TransUnit.prototype.useSourceAsTarget = function (isDefaultLang) { - }; - /** - * Translate trans unit. - * (very simple, just for tests) - * @param translation the translated string - */ - TransUnit.prototype.translate = function (translation) { - var target = cheerio(this._msg); - target.html(translation); - }; - return TransUnit; -}()); -var XmbFile = (function () { - function XmbFile() { - this._warnings = []; - this._numberOfTransUnitsWithMissingId = 0; - } - /** - * Read an xmb-File. - * @param path Path to file - * @param encoding optional encoding of the xml. - * This is read from the file, but if you know it before, you can avoid reading the file twice. - * @return {XmbFile} - */ - XmbFile.fromFile = function (path, encoding) { - var xmb = new XmbFile(); - var xmlContent = xml_reader_1.XmlReader.readXmlFileContent(path, encoding); - xmb.initializeFromContent(xmlContent.content, path, xmlContent.encoding); - return xmb; - }; - XmbFile.prototype.initializeFromContent = function (xmlString, path, encoding) { - this.filename = path; - this.encoding = encoding; - this.xmbContent = cheerio.load(xmlString, CheerioOptions); - return this; - }; - XmbFile.prototype.initializeTransUnits = function () { - var _this = this; - if (util_1.isNullOrUndefined(this.transUnits)) { - this.transUnits = []; - var transUnitsInFile = this.xmbContent('msg'); - transUnitsInFile.each(function (index, msg) { - var id = cheerio(msg).attr('id'); - if (!id) { - _this._warnings.push(util_1.format('oops, msg without "id" found in master, please check file %s', _this.filename)); - _this._numberOfTransUnitsWithMissingId++; - } - _this.transUnits.push(new TransUnit(msg, id)); - }); - } - }; - XmbFile.prototype.forEachTransUnit = function (callback) { - this.initializeTransUnits(); - this.transUnits.forEach(function (tu) { return callback(tu); }); - }; - /** - * Get trans-unit with given id. - * @param id - * @return {Cheerio} - */ - XmbFile.prototype.transUnitWithId = function (id) { - this.initializeTransUnits(); - return this.transUnits.find(function (tu) { return tu.id == id; }); - }; - XmbFile.prototype.warnings = function () { - this.initializeTransUnits(); - return this._warnings; - }; - XmbFile.prototype.numberOfTransUnits = function () { - this.initializeTransUnits(); - return this.transUnits.length; - }; - XmbFile.prototype.numberOfTransUnitsWithMissingId = function () { - this.initializeTransUnits(); - return this._numberOfTransUnitsWithMissingId; - }; - /** - * Get source language. - * Unsupported in xmb. - * @return {string} - */ - XmbFile.prototype.sourceLanguage = function () { - return null; - }; - /** - * Edit the source language. - * Unsupported in xmb. - * @param language - */ - XmbFile.prototype.setSourceLanguage = function (language) { - // do nothing, xmb has no notation for this. - }; - /** - * Get target language. - * Unsupported in xmb. - * @return {string} - */ - XmbFile.prototype.targetLanguage = function () { - return null; - }; - /** - * Edit the target language. - * Unsupported in xmb. - * @param language - */ - XmbFile.prototype.setTargetLanguage = function (language) { - // do nothing, xmb has no notation for this. - }; - /** - * Copy source to target to use it as dummy translation. - * (better than missing value) - * In xmb there is nothing to do, because there is only a target, no source. - */ - XmbFile.prototype.useSourceAsTarget = function (transUnit, isDefaultLang) { - transUnit.useSourceAsTarget(isDefaultLang); - }; - /** - * Translate a given trans unit. - * (very simple, just for tests) - * @param transUnit - * @param translation the translated string - */ - XmbFile.prototype.translate = function (transUnit, translation) { - transUnit.translate(translation); - }; - /** - * Add a new trans-unit. - * @param transUnit - */ - XmbFile.prototype.addNewTransUnit = function (transUnit) { - this.xmbContent('messagebundle').append(cheerio(transUnit.asXmlElement())); - this.initializeTransUnits(); - this.transUnits.push(transUnit); - }; - /** - * Remove the trans-unit with the given id. - * @param id - */ - XmbFile.prototype.removeTransUnitWithId = function (id) { - this.xmbContent('#' + id).remove(); - this.initializeTransUnits(); - this.transUnits = this.transUnits.filter(function (tu) { return tu.id != id; }); - }; - /** - * Save edited content to file. - */ - XmbFile.prototype.save = function () { - file_util_1.FileUtil.replaceContent(this.filename, this.xmbContent.xml(), this.encoding); - }; - return XmbFile; -}()); -exports.XmbFile = XmbFile; diff --git a/src/xliffmerge/xmb-file.ts b/src/xliffmerge/xmb-file.ts deleted file mode 100644 index ec3099f..0000000 --- a/src/xliffmerge/xmb-file.ts +++ /dev/null @@ -1,299 +0,0 @@ -import * as cheerio from "cheerio"; -import {ITranslationMessagesFile} from './i-translation-messages-file'; -import {isNullOrUndefined, format} from 'util'; -import {ITransUnit} from './i-trans-unit'; -/** - * Created by martin on 10.03.2017. - * xmb-File access. - */ - -/** - * Read-Options for cheerio, enable xml mode. - * @type {{xmlMode: boolean}} - */ -const CheerioOptions: CheerioOptionsInterface = { - xmlMode: true, - decodeEntities: false, -}; - -class TransUnit implements ITransUnit { - - constructor(private _msg: CheerioElement, private _id: string) { - - } - - public get id(): string { - return this._id; - } - - public sourceContent(): string { - return cheerio(this._msg).html(); - } - - /** - * the translated value (containing all markup, depends on the concrete format used). - */ - public targetContent(): string { - // in fact, target and source are just the same in xmb - return cheerio(this._msg).html(); - } - - /** - * the translated value, but all placeholders are replaced with {{n}} (starting at 0) - * and all embedded html is replaced by direct html markup. - */ - targetContentNormalized(): string { - let directHtml = this.targetContent(); - if (!directHtml) { - return directHtml; - } - let normalized = directHtml; - let re0: RegExp = /INTERPOLATION<\/ex><\/ph>/g; - normalized = normalized.replace(re0, '{{0}}'); - let reN: RegExp = /INTERPOLATION_(\d*)<\/ex><\/ph>/g; - normalized = normalized.replace(reN, '{{$1}}'); - - let reStartAnyTag: RegExp = /&lt;(\w*)&gt;<\/ex><\/ph>/g; - normalized = normalized.replace(reStartAnyTag, '<$1>'); - let reCloseAnyTag: RegExp = /&lt;\/(\w*)&gt;<\/ex><\/ph>/g; - normalized = normalized.replace(reCloseAnyTag, ''); - - return normalized; - } - - /** - * State of the translation. - * (not supported in xmb) - */ - public targetState(): string { - return null; // not supported in xmb - } - - /** - * The description set in the template as value of the i18n-attribute. - * e.g. i18n="mydescription". - * In xmb this is stored in the attribute "desc". - */ - public description(): string { - return cheerio(this._msg).attr('desc'); - } - - /** - * The meaning (intent) set in the template as value of the i18n-attribute. - * This is the part in front of the | symbol. - * e.g. i18n="meaning|mydescription". - * In xmb this is stored in the attribute "meaning". - */ - public meaning(): string { - return cheerio(this._msg).attr('meaning'); - } - - /** - * the real xml element used for trans unit. - * Here it is a element. - * @return {CheerioElement} - */ - public asXmlElement(): CheerioElement { - return this._msg; - } - - /** - * Copy source to target to use it as dummy translation. - * (better than missing value) - * In xmb there is nothing to do, because there is only a target, no source. - */ - public useSourceAsTarget(isDefaultLang: boolean, copyContent: boolean) { - } - - /** - * Translate trans unit. - * (very simple, just for tests) - * @param translation the translated string - */ - public translate(translation: string) { - let target = cheerio(this._msg); - target.html(translation); - } - -} - -export class XmbFile implements ITranslationMessagesFile { - - private _filename: string; - - private _encoding: string; - - private xmbContent: CheerioStatic; - - // trans-unit elements and their id from the file - private transUnits: ITransUnit[]; - - private _warnings: string[]; - private _numberOfTransUnitsWithMissingId: number; - - /** - * Create an xmb-File from source. - * @param xmlString file content - * @param path Path to file - * @param encoding optional encoding of the xml. - * This is read from the file, but if you know it before, you can avoid reading the file twice. - * @return {XmbFile} - */ - constructor(xmlString: string, path: string, encoding: string) { - this._warnings = []; - this._numberOfTransUnitsWithMissingId = 0; - this.initializeFromContent(xmlString, path, encoding); - } - - private initializeFromContent(xmlString: string, path: string, encoding: string): XmbFile { - this._filename = path; - this._encoding = encoding; - this.xmbContent = cheerio.load(xmlString, CheerioOptions); - if (this.xmbContent('messagebundle').length != 1) { - throw new Error(format('File "%s" seems to be no xmb file (should contain a messagebundle element)', path)); - } - return this; - } - - private initializeTransUnits() { - if (isNullOrUndefined(this.transUnits)) { - this.transUnits = []; - let transUnitsInFile = this.xmbContent('msg'); - transUnitsInFile.each((index, msg: CheerioElement) => { - let id = cheerio(msg).attr('id'); - if (!id) { - this._warnings.push(format('oops, msg without "id" found in master, please check file %s', this.filename)); - this._numberOfTransUnitsWithMissingId++; - } - this.transUnits.push(new TransUnit(msg, id)); - }); - } - } - - public forEachTransUnit(callback: ((transunit: ITransUnit) => void)) { - this.initializeTransUnits(); - this.transUnits.forEach((tu) => callback(tu)); - } - - /** - * Get trans-unit with given id. - * @param id - * @return {Cheerio} - */ - public transUnitWithId(id: string): ITransUnit { - this.initializeTransUnits(); - return this.transUnits.find((tu) => tu.id == id); - } - - public warnings(): string[] { - this.initializeTransUnits(); - return this._warnings; - } - - public numberOfTransUnits(): number { - this.initializeTransUnits(); - return this.transUnits.length; - } - - public numberOfTransUnitsWithMissingId(): number { - this.initializeTransUnits(); - return this._numberOfTransUnitsWithMissingId; - } - - /** - * Get source language. - * Unsupported in xmb. - * @return {string} - */ - public sourceLanguage(): string { - return null; - } - - /** - * Edit the source language. - * Unsupported in xmb. - * @param language - */ - public setSourceLanguage(language: string) { - // do nothing, xmb has no notation for this. - } - - /** - * Get target language. - * Unsupported in xmb. - * @return {string} - */ - public targetLanguage(): string { - return null; - } - - /** - * Edit the target language. - * Unsupported in xmb. - * @param language - */ - public setTargetLanguage(language: string) { - // do nothing, xmb has no notation for this. - } - - /** - * Copy source to target to use it as dummy translation. - * (better than missing value) - * In xmb there is nothing to do, because there is only a target, no source. - */ - public useSourceAsTarget(transUnit: ITransUnit, isDefaultLang: boolean, copyContent: boolean) { - transUnit.useSourceAsTarget(isDefaultLang, copyContent); - } - - /** - * Translate a given trans unit. - * (very simple, just for tests) - * @param transUnit - * @param translation the translated string - */ - public translate(transUnit: ITransUnit, translation: string) { - transUnit.translate(translation); - } - - /** - * Add a new trans-unit. - * @param transUnit - */ - public addNewTransUnit(transUnit: ITransUnit) { - this.xmbContent('messagebundle').append(cheerio(transUnit.asXmlElement())); - this.initializeTransUnits(); - this.transUnits.push(transUnit); - } - - /** - * Remove the trans-unit with the given id. - * @param id - */ - public removeTransUnitWithId(id: string) { - this.xmbContent('#' + id).remove(); - this.initializeTransUnits(); - this.transUnits = this.transUnits.filter((tu) => tu.id != id); - } - - /** - * The filename where the data is read from. - */ - public filename(): string { - return this._filename; - } - - /** - * The encoding if the xml content (UTF-8, ISO-8859-1, ...) - */ - public encoding(): string { - return this._encoding; - } - - /** - * The xml to be saved after changes are made. - */ - public editedContent(): string { - return this.xmbContent.xml(); - } - -} diff --git a/src/xliffmerge/xml-reader.js b/src/xliffmerge/xml-reader.js deleted file mode 100644 index ff760c4..0000000 --- a/src/xliffmerge/xml-reader.js +++ /dev/null @@ -1,49 +0,0 @@ -"use strict"; -var file_util_1 = require("../common/file-util"); -/** - * Created by martin on 10.03.2017. - * Helper class to read XMl with a correct encoding. - */ -var XmlReader = (function () { - function XmlReader() { - } - /** - * Read an xml-File. - * @param path Path to file - * @param encoding optional encoding of the xml. - * This is read from the file, but if you know it before, you can avoid reading the file twice. - * @return file content and encoding found in the file. - */ - XmlReader.readXmlFileContent = function (path, encoding) { - if (!encoding) { - encoding = XmlReader.DEFAULT_ENCODING; - } - var content = file_util_1.FileUtil.read(path, encoding); - var foundEncoding = XmlReader.encodingFromXml(content); - if (foundEncoding != encoding) { - // read again with the correct encoding - content = file_util_1.FileUtil.read(path, foundEncoding); - } - return { - content: content, - encoding: foundEncoding - }; - }; - /** - * Read the encoding from the xml. - * xml File starts with .. encoding=".." - * @param xmlString - * @return {any} - */ - XmlReader.encodingFromXml = function (xmlString) { - var index = xmlString.indexOf('encoding="'); - if (index < 0) { - return this.DEFAULT_ENCODING; // default in xml if not explicitly set - } - var endIndex = xmlString.indexOf('"', index + 10); // 10 = length of 'encoding="' - return xmlString.substring(index + 10, endIndex); - }; - return XmlReader; -}()); -XmlReader.DEFAULT_ENCODING = 'UTF-8'; -exports.XmlReader = XmlReader; diff --git a/test/testdata/i18n/ngExtractedMaster1.xmb b/test/testdata/i18n/ngExtractedMaster1.xmb index b95add2..67f2a10 100644 --- a/test/testdata/i18n/ngExtractedMaster1.xmb +++ b/test/testdata/i18n/ngExtractedMaster1.xmb @@ -21,10 +21,11 @@ ]> - Meine erste I18N-Anwendung - Diese Anwendung ist eine reine Demonstration und hat keine wirklich nutzbare Funktion. - Diese Anwendung ist eine reine Demonstration und hat keine wirklich nutzbare Funktion. - Eintrag INTERPOLATION von INTERPOLATION_1 hinzugefügt. - Dieser Text + S:/experimente/sampleapp41/src/app/app.component.ts:1Meine erste I18N-Anwendung + S:/experimente/sampleapp41/src/app/app.component.ts:2S:/experimente/sampleapp41/src/app/app.component.ts:3Anwendung läuft! + S:/experimente/sampleapp41/src/app/app.component.ts:4Diese Anwendung ist eine reine Demonstration und hat keine wirklich nutzbare Funktion. + S:/experimente/sampleapp41/src/app/app.component.ts:5Diese Anwendung ist eine reine Demonstration und hat keine wirklich nutzbare Funktion. + S:/experimente/sampleapp41/src/app/app.component.ts:6Eintrag INTERPOLATION von INTERPOLATION_1 hinzugefügt. + S:/experimente/sampleapp41/src/app/app.component.ts:7,8Dieser Text enthält einen Zeilenumbruch. diff --git a/test/testdata/i18n/ngExtractedMaster2.xmb b/test/testdata/i18n/ngExtractedMaster2.xmb index d8c2171..9a94f95 100644 --- a/test/testdata/i18n/ngExtractedMaster2.xmb +++ b/test/testdata/i18n/ngExtractedMaster2.xmb @@ -21,11 +21,10 @@ ]> - Meine erste I18N-Anwendung - Anwendung läuft! - Eintrag INTERPOLATION von INTERPOLATION_1 hinzugefügt. - Dieser Text + S:/experimente/sampleapp41/src/app/app.component.ts:1Meine erste I18N-Anwendung + S:/experimente/sampleapp41/src/app/app.component.ts:2S:/experimente/sampleapp41/src/app/app.component.ts:3Anwendung läuft! + S:/experimente/sampleapp41/src/app/app.component.ts:6Eintrag INTERPOLATION von INTERPOLATION_1 hinzugefügt. + S:/experimente/sampleapp41/src/app/app.component.ts:7,8Dieser Text enthält einen Zeilenumbruch. - Dieser Text enthält <b>eingebettetes html</b> - Dieser Text enthält <b>eingebettetes html</b> + S:/experimente/sampleapp41/src/app/app.component.ts:9Dieser Text enthält <b>eingebettetes html</b> diff --git a/test/testdata/i18n/ngxtranslate.xlf b/test/testdata/i18n/ngxtranslate.xlf index 8935f53..1275a80 100644 --- a/test/testdata/i18n/ngxtranslate.xlf +++ b/test/testdata/i18n/ngxtranslate.xlf @@ -82,6 +82,14 @@ ngx-translate embeddedhtml.strange + + Explizit gesetzte ID + Explizit gesetzte ID + + S:/experimente/sampleapp41/src/app/ngx-translate-test-data/ngx-translate-test-data.component.ts + 18 + + \ No newline at end of file diff --git a/test/testdata/i18n/ngxtranslate.xmb b/test/testdata/i18n/ngxtranslate.xmb index 416e2ce..2787574 100644 --- a/test/testdata/i18n/ngxtranslate.xmb +++ b/test/testdata/i18n/ngxtranslate.xmb @@ -37,4 +37,5 @@ Diese Nachricht ist <b>WICHTIG</b> Diese Nachricht ist <b><strong>SEHR WICHTIG</strong></b> Diese Nachricht ist <strange>INTERPOLATION</strange> + S:/experimente/sampleapp41/src/app/ngx-translate-test-data/ngx-translate-test-data.component.ts:18Explizit gesetzte ID diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..38a7eed --- /dev/null +++ b/yarn.lock @@ -0,0 +1,1502 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/jasmine@^2.5.43": + version "2.5.47" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.5.47.tgz#bbba9bcf0e95e7890c6f4a47394e8bacaa960eb6" + +"@types/node@^7.0.5": + version "7.0.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.12.tgz#ae5f67a19c15f752148004db07cbbb372e69efc9" + +"@types/xmldom@^0.1.29": + version "0.1.29" + resolved "https://registry.yarnpkg.com/@types/xmldom/-/xmldom-0.1.29.tgz#c4428b0ca86d3b881475726fd94980b38a27c381" + +abbrev@1, abbrev@1.0.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +ajv@^4.9.1: + version "4.11.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.6.tgz#947e93049790942b2a2d60a8289b28924d39f987" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + +aproba@^1.0.3: + version "1.1.1" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" + +are-we-there-yet@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.0 || ^1.1.13" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + +array-filter@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" + +array-map@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" + +array-reduce@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async@1.x, async@^1.4.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + +babel-runtime@^6.9.2: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + +balanced-match@^0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + +binary-extensions@^1.0.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +brace-expansion@^1.0.0: + version "1.1.7" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" + dependencies: + balanced-match "^0.4.1" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +buffer-shims@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chokidar@^1.6.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +coffee-script@>=1.0.1: + version "1.12.4" + resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.4.tgz#fe1bced97fe1fb3927b998f2b45616e0658be1ff" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +coveralls@^2.11.16: + version "2.13.0" + resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-2.13.0.tgz#df933876e8c6f478efb04f4d3ab70dc96b7e5a8e" + dependencies: + js-yaml "3.6.1" + lcov-parse "0.0.10" + log-driver "1.2.5" + minimist "1.2.0" + request "2.79.0" + +cpx@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/cpx/-/cpx-1.5.0.tgz#185be018511d87270dedccc293171e37655ab88f" + dependencies: + babel-runtime "^6.9.2" + chokidar "^1.6.0" + duplexer "^0.1.1" + glob "^7.0.5" + glob2base "^0.0.12" + minimatch "^3.0.2" + mkdirp "^0.5.1" + resolve "^1.1.7" + safe-buffer "^5.0.1" + shell-quote "^1.6.1" + subarg "^1.0.0" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +debug@^2.2.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" + dependencies: + ms "0.7.2" + +decamelize@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +deep-extend@~0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +duplexer@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +escape-string-regexp@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escodegen@1.8.x: + version "1.8.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" + dependencies: + esprima "^2.7.1" + estraverse "^1.9.1" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.2.0" + +esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +estraverse@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +extend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +filename-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + +fileset@~0.1.5: + version "0.1.8" + resolved "https://registry.yarnpkg.com/fileset/-/fileset-0.1.8.tgz#506b91a9396eaa7e32fb42a84077c7a0c736b741" + dependencies: + glob "3.x" + minimatch "0.x" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +find-index@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" + +for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.1.tgz#f19fd28f43eeaf761680e519a203c4d0b3d31aff" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.29" + +fstream-ignore@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +gauge@~2.7.1: + version "2.7.3" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gaze@~0.3.2: + version "0.3.4" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-0.3.4.tgz#5f94bdda0afe53bc710969bcd6f282548d60c279" + dependencies: + fileset "~0.1.5" + minimatch "~0.2.9" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +getpass@^0.1.1: + version "0.1.6" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob2base@^0.0.12: + version "0.0.12" + resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56" + dependencies: + find-index "^0.1.1" + +glob@3.x: + version "3.2.11" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" + dependencies: + inherits "2" + minimatch "0.3" + +glob@^5.0.15: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.5: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +graceful-fs@^4.1.2: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +growl@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.7.0.tgz#de2d66136d002e112ba70f3f10c31cf7c350b2da" + +handlebars@^4.0.1: + version "4.0.6" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + +har-schema@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +har-validator@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" + dependencies: + ajv "^4.9.1" + har-schema "^1.0.5" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" + +is-dotfile@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-my-json-valid@^2.12.4: + version "2.16.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +istanbul@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" + dependencies: + abbrev "1.0.x" + async "1.x" + escodegen "1.8.x" + esprima "2.7.x" + glob "^5.0.15" + handlebars "^4.0.1" + js-yaml "3.x" + mkdirp "0.5.x" + nopt "3.x" + once "1.x" + resolve "1.1.x" + supports-color "^3.1.0" + which "^1.1.1" + wordwrap "^1.0.0" + +jasmine-growl-reporter@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/jasmine-growl-reporter/-/jasmine-growl-reporter-0.0.3.tgz#b87ae551e359d28ad5217765eaef6c07b763f6c8" + dependencies: + growl "~1.7.0" + +jasmine-node@^1.14.5: + version "1.14.5" + resolved "https://registry.yarnpkg.com/jasmine-node/-/jasmine-node-1.14.5.tgz#18e8397b856924ee77003666c3731b5aea50c39d" + dependencies: + coffee-script ">=1.0.1" + gaze "~0.3.2" + jasmine-growl-reporter "~0.0.2" + jasmine-reporters "~1.0.0" + mkdirp "~0.3.5" + requirejs ">=0.27.1" + underscore ">= 1.3.1" + walkdir ">= 0.0.1" + +jasmine-reporters@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jasmine-reporters/-/jasmine-reporters-1.0.2.tgz#ab613ed5977dc7487e85b3c12f6a8ea8db2ade31" + dependencies: + mkdirp "~0.3.5" + +jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + +js-yaml@3.6.1, js-yaml@3.x: + version "3.6.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsprim@^1.2.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" + dependencies: + assert-plus "1.0.0" + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + +kind-of@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + dependencies: + is-buffer "^1.0.2" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lcov-parse@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +log-driver@1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.5.tgz#7ae4ec257302fd790d557cb10c97100d857b0056" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +lru-cache@2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +mime-db@~1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" + +mime-types@^2.1.12, mime-types@~2.1.7: + version "2.1.15" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" + dependencies: + mime-db "~1.27.0" + +minimatch@0.3: + version "0.3.0" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" + dependencies: + lru-cache "2" + sigmund "~1.0.0" + +minimatch@0.x, minimatch@~0.2.9: + version "0.2.14" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" + dependencies: + lru-cache "2" + sigmund "~1.0.0" + +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + +minimist@0.0.8, minimist@~0.0.1: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@1.2.0, minimist@^1.1.0, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +mkdirp@~0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" + +ms@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + +nan@^2.3.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.1.tgz#8c84f7b14c96b89f57fbc838012180ec8ca39a01" + +ngx-i18nsupport-lib@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ngx-i18nsupport-lib/-/ngx-i18nsupport-lib-0.0.8.tgz#ce8d527ea166f4e76ad0c2e90cdede78125e8979" + dependencies: + "@types/xmldom" "^0.1.29" + xmldom "^0.1.27" + +node-pre-gyp@^0.6.29: + version "0.6.34" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.34.tgz#94ad1c798a11d7fc67381b50d47f8cc18d9799f7" + dependencies: + mkdirp "^0.5.1" + nopt "^4.0.1" + npmlog "^4.0.2" + rc "^1.1.7" + request "^2.81.0" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^2.2.1" + tar-pack "^3.4.0" + +nopt@3.x: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +npmlog@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.1" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +once@1.x, once@^1.3.0, once@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-tmpdir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@~6.3.0: + version "6.3.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" + +qs@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + +randomatic@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + +rc@^1.1.7: + version "1.2.1" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.1.4: + version "2.2.9" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8" + dependencies: + buffer-shims "~1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~1.0.0" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +regenerator-runtime@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +remove-trailing-separator@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +request@2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + +request@^2.81.0: + version "2.81.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~4.2.1" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "^0.6.0" + uuid "^3.0.0" + +requirejs@>=0.27.1: + version "2.3.3" + resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.3.tgz#aa59fd3a0287eaf407959a138228044b5dd6a6a3" + +resolve@1.1.x: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +resolve@^1.1.7: + version "1.3.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235" + dependencies: + path-parse "^1.0.5" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" + dependencies: + glob "^7.0.5" + +safe-buffer@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" + +semver@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +shell-quote@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" + dependencies: + array-filter "~0.0.0" + array-map "~0.0.0" + array-reduce "~0.0.0" + jsonify "~0.0.0" + +sigmund@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +source-map@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +source-map@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" + dependencies: + amdefine ">=0.0.4" + +source-map@~0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string_decoder@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.0.tgz#f06f41157b664d86069f84bdbdc9b0d8ab281667" + dependencies: + buffer-shims "~1.0.0" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +subarg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" + dependencies: + minimist "^1.1.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.1.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +tar-pack@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" + dependencies: + debug "^2.2.0" + fstream "^1.0.10" + fstream-ignore "^1.0.5" + once "^1.3.3" + readable-stream "^2.1.4" + rimraf "^2.5.1" + tar "^2.2.1" + uid-number "^0.0.6" + +tar@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +tough-cookie@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +typescript@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.2.2.tgz#606022508479b55ffa368b58fee963a03dfd7b0c" + +uglify-js@^2.6: + version "2.8.22" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.22.tgz#d54934778a8da14903fa29a326fb24c0ab51a1a0" + dependencies: + source-map "~0.5.1" + yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uid-number@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +"underscore@>= 1.3.1": + version "1.8.3" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +uuid@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + +verror@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + +"walkdir@>= 0.0.1": + version "0.0.11" + resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.0.11.tgz#a16d025eb931bd03b52f308caed0f40fcebe9532" + +which@^1.1.1: + version "1.2.14" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + dependencies: + string-width "^1.0.1" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wordwrap@^1.0.0, wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +xmldom@^0.1.27: + version "0.1.27" + resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" + +xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0"