diff --git a/src/gulpmain.ts b/src/gulpmain.ts
index 7938f200..6eec35a6 100644
--- a/src/gulpmain.ts
+++ b/src/gulpmain.ts
@@ -36,7 +36,7 @@ gulp.task("rebuild", ["clean"], function (callback: Function): void {
gulp.task("run-stylecop", function (callback: Function): void {
if (fs.existsSync(buildConfig.copPath)) {
var styleCop = new stylecopUtil.StyleCopUtil();
- styleCop.runCop(path.join(buildConfig.src, ".."), buildConfig.copPath, callback);
+ styleCop.runCop(buildConfig.src, buildConfig.copPath, callback);
} else {
callback();
}
@@ -51,6 +51,7 @@ gulp.task("clean", function (callback: Function): void {
gulp.task("copy", function (callback: Function): void {
gulp.src(path.join(buildConfig.src, "/**/package.json")).pipe(gulp.dest(buildConfig.bin));
gulp.src(path.join(buildConfig.src, "/**/resources.json")).pipe(gulp.dest(buildConfig.bin));
+ gulp.src(path.join(buildConfig.src, "/**/test/**")).pipe(gulp.dest(buildConfig.bin));
});
/* auto-generate taco-utils.d.ts*/
diff --git a/src/taco-cli/compile/typescript-util.ts b/src/taco-cli/compile/typescript-util.ts
index 76369a50..49fa0b15 100644
--- a/src/taco-cli/compile/typescript-util.ts
+++ b/src/taco-cli/compile/typescript-util.ts
@@ -44,7 +44,6 @@ export class TypeScriptServices {
if (!fs.statSync(currentPath).isDirectory()) {
/* push the typescript files */
if (path.extname(currentPath) === ".ts" &&
- !currentPath.match("d.ts$") &&
!currentPath.match("gulpfile.ts") &&
!currentPath.match("gulpmain.ts")) {
result.push(currentPath);
@@ -79,8 +78,12 @@ export class TypeScriptServices {
*/
private logDiagnosticMessage(diagnostic: ts.Diagnostic): void {
var sourceFile = diagnostic.file;
- var lineAndCharacter = sourceFile.getLineAndCharacterFromPosition(diagnostic.start);
- console.warn(sourceFile.filename + "(" + lineAndCharacter.line + "," + lineAndCharacter.character + "): " + diagnostic.messageText);
+ if (sourceFile) {
+ var lineAndCharacter = sourceFile.getLineAndCharacterFromPosition(diagnostic.start);
+ console.warn(sourceFile.filename + "(" + lineAndCharacter.line + "," + lineAndCharacter.character + "): " + diagnostic.messageText);
+ } else {
+ console.warn(diagnostic.messageText);
+ }
}
}
diff --git a/src/taco-utils/package.json b/src/taco-utils/package.json
index eb5f6f4f..fd20eb14 100644
--- a/src/taco-utils/package.json
+++ b/src/taco-utils/package.json
@@ -7,9 +7,13 @@
"version": "0.0.1",
"main": "taco-utils.js",
"dependencies": {
+ "elementtree": "0.1.6",
+ "unorm": "1.3.3"
},
"private": true,
"devDependencies": {
- "typescript": ">=1.4.1"
+ "typescript": ">=1.4.1",
+ "mocha": "2.0.1",
+ "should": "4.3.0"
}
-}
\ No newline at end of file
+}
diff --git a/src/taco-utils/taco-utils.ts b/src/taco-utils/taco-utils.ts
index 58f92bac..25da100e 100644
--- a/src/taco-utils/taco-utils.ts
+++ b/src/taco-utils/taco-utils.ts
@@ -1,39 +1,71 @@
///
+///
+///
"use strict";
+import et = require ("elementtree");
import fs = require ("fs");
import path = require ("path");
+var unorm = require("unorm"); // Note no import: the compiler will remove the require since we don't use the unorm object, we just need it to add String.normalize
module TacoUtility {
// put more classes here, known limitation that classes in external modules CANNOT span multiple files
export class ResourcesManager {
- private static Resources: any = null;
- private static DefaultLanguage: string = "en";
+ private static Resources: { [key: string]: any; } = null;
+ private static SupportedLanguages: string[] = null;
+ private static DefaultLanguage: string = "en";
- public static init(language: string, resourcesDir?: string): void {
+ public static init(language: string, resourcesDir?: string): void {
if (!resourcesDir) {
resourcesDir = path.join(__dirname, "..", "resources");
}
- var lang = this.bestLanguageMatchOrDefault(language, resourcesDir);
- this.Resources = this.loadLanguage(lang, resourcesDir);
+ ResourcesManager.Resources = {};
+ ResourcesManager.SupportedLanguages = [];
+ fs.readdirSync(resourcesDir).forEach(function (filename: string): void {
+ try {
+ ResourcesManager.Resources[filename.toLowerCase()] = ResourcesManager.loadLanguage(filename, resourcesDir);
+ ResourcesManager.SupportedLanguages.push(filename.toLowerCase());
+ } catch (e) {
+ // Folder was not a valid resource; ignore it
+ }
+ });
+
+ ResourcesManager.DefaultLanguage = ResourcesManager.bestLanguageMatchOrDefault(language);
}
- /* ...optionalArgs is only there for typings, function rest params */
+ // For unit tests
+ public static teardown(): void {
+ ResourcesManager.Resources = null;
+ ResourcesManager.SupportedLanguages = null;
+ }
+
+ /** ...optionalArgs is only there for typings, function rest params */
public static getString(id: string, ...optionalArgs: any[]): string {
- if (!this.Resources) {
+ var args = ResourcesManager.getOptionalArgsArrayFromFunctionCall(arguments, 1);
+ return ResourcesManager.getStringForLanguage(ResourcesManager.DefaultLanguage, id, args);
+ }
+
+ /** ** ...optionalArgs is only there for typings, function rest params** */
+ public static getStringForLanguage(requestOrAcceptLangs: any, id: string, ...optionalArgs: any[]): string {
+ if (!ResourcesManager.Resources) {
throw new Error("Resources have not been loaded");
}
- var s = this.Resources[id];
+ var lang = ResourcesManager.bestLanguageMatchOrDefault(requestOrAcceptLangs);
+
+ var s = ResourcesManager.Resources[lang][id];
if (!s) {
return s;
+ } else if (Array.isArray(s)) {
+ // Allow longer resources strings to be specified as a list of strings, which represent multiple lines
+ s = s.join("\n");
}
/*All args passed to current function:
you can call getString('foo', 'bar', 'baz') or getString('foo',['bar', 'baz'])
and the utility function will extract ['bar', 'baz'] as args in both cases*/
- var args = this.getOptionalArgsArrayFromFunctionCall(arguments, 1);
+ var args = ResourcesManager.getOptionalArgsArrayFromFunctionCall(arguments, 2);
if (args) {
for (var i: number = 0; i < args.length; i++) {
s = s.replace("{" + i + "}", args[i]);
@@ -43,39 +75,146 @@ module TacoUtility {
return s;
}
- public static bestLanguageMatchOrDefault(language: string, resourcesDir: string): string {
- if (!language) {
- return this.DefaultLanguage;
+ private static bestLanguageMatchOrDefault(requestOrAcceptLangs: any): string {
+ var lang = ResourcesManager.bestLanguageMatch(requestOrAcceptLangs);
+ if (!ResourcesManager.Resources[lang]) {
+ lang = ResourcesManager.DefaultLanguage;
}
- var supportedLanguages: string[] = [];
- fs.readdirSync(resourcesDir).filter(function (c: string): boolean {
- return fs.existsSync(path.join(resourcesDir, c, "resources.json"));
- }).forEach(function (l: string): void {
- supportedLanguages.push(l.toLowerCase());
- });
-
- // TODO: remove assumption of case insensitive file system, so this can work on non-windows systems.
- var lang = language.toLowerCase();
- if (supportedLanguages.indexOf(lang) !== -1) {
- // exact match on language, which could include the region (e.g. it-CH), return the match
- return lang;
- }
-
- var primaryLang = lang.split("-")[0];
- if (supportedLanguages.indexOf(primaryLang) !== -1) {
- // match on primary language (e.g. it from it-CH).
- return primaryLang;
- }
-
- return this.DefaultLanguage;
+ return lang.toLowerCase();
}
- public static loadLanguage(language: string, resourcesDir: string): any {
+ /**
+ * requestOrAcceptLangs can either be:
+ * A string, with format "LangSpec[,LangSpec]*" where LangSpec is "Language[;anything]"
+ * e.g. "pl,fr-FR;q=0.3,en-US;q=0.1" is interpreted as "pl" or "fr-FR" or "en-US". Currently we ignore provided quality (q) values
+ * An array, which we assume is an array of strings representing languages such as "pl" or "fr-FR"
+ * A (express-style) HTTP Request object, with a headers property specifing "accept-language" in a string, as above
+ *
+ * This allows us to handle simple cases of a single string, as well as more complex cases where a client specifies
+ * multiple preferences.
+ */
+ private static bestLanguageMatch(requestOrAcceptLangs: any): string {
+ if (Array.isArray(requestOrAcceptLangs)) {
+ return ResourcesManager.getBestLanguageFromArray(requestOrAcceptLangs);
+ }
+
+ var langString: string;
+ if (!requestOrAcceptLangs) {
+ return ResourcesManager.DefaultLanguage;
+ } else if (typeof requestOrAcceptLangs === "string") {
+ langString = requestOrAcceptLangs;
+ } else if (requestOrAcceptLangs.headers) {
+ langString = requestOrAcceptLangs.headers["accept-language"] || "";
+ } else {
+ throw new Error("Unsupported type of argument for acceptLangs: " + (typeof requestOrAcceptLangs));
+ }
+
+ return ResourcesManager.getBestLanguageFromArray(langString.split(",").map(function (l: string): string { return l.split(";")[0]; }));
+ }
+
+ /**
+ * Given a list of languages, we try to find an exact match if we can, and we fall back to a primary language otherwise.
+ * e.g. "fr-CA" will use "fr-CA" resources if present, but will fall back to "fr" resources if they are available
+ */
+ private static getBestLanguageFromArray(acceptLangs: string[]): string {
+ var primaryLanguageMatch: string = null;
+ for (var i: number = 0; i < acceptLangs.length; ++i) {
+ var lang: string = acceptLangs[i].toLowerCase();
+ var primaryLang = lang.split("-")[0];
+ if (ResourcesManager.SupportedLanguages.indexOf(lang) !== -1) {
+ // Exact match on full language header, which could include the region
+ return lang;
+ }
+
+ if (ResourcesManager.SupportedLanguages.indexOf(primaryLang) !== -1) {
+ // Match on primary language (e.g. it from it-CH). We may find a better match later, so continue looking.
+ primaryLanguageMatch = primaryLang;
+ }
+ }
+
+ return primaryLanguageMatch;
+ }
+
+ private static loadLanguage(language: string, resourcesDir: string): any {
var resourcesPath = path.join(resourcesDir, language, "resources.json");
return require(resourcesPath);
}
+ private static getOptionalArgsArrayFromFunctionCall(functionArguments: IArguments, startFrom: number): any[] {
+ if (functionArguments.length <= startFrom) {
+ return null;
+ }
+
+ if (Array.isArray(functionArguments[startFrom])) {
+ return functionArguments[startFrom];
+ }
+
+ return Array.prototype.slice.apply(functionArguments, [startFrom]);
+ }
+ }
+
+ export class CordovaConfig {
+ /** CordovaConfig is a class for parsing the config.xml file for Cordova projects */
+ private _doc: et.ElementTree;
+
+ constructor(configXmlPath: string) {
+ var contents = UtilHelper.readFileContentsSync(configXmlPath, "utf-8");
+ this._doc = new et.ElementTree(et.XML(contents));
+ }
+
+ public id(): string {
+ return this._doc.getroot().attrib["id"];
+ }
+
+ public name(): string {
+ var el = this._doc.find("name");
+ return el && el.text && el.text.trim().normalize();
+ }
+
+ public version(): string {
+ var el = this._doc.getroot();
+ return el && el.attrib && el.attrib["version"];
+ }
+
+ public preferences(): { [key: string]: string } {
+ var data: { [key: string]: string } = {};
+ var preferences = this._doc.findall("preference");
+ preferences.forEach(function (preference: et.XMLElement): void {
+ data[preference.attrib["name"]] = preference.attrib["value"];
+ });
+
+ return data;
+ }
+ }
+
+ export class UtilHelper {
+ private static InvalidAppNameChars = {
+ 34: "\"",
+ 36: "$",
+ 38: "&",
+ 39: "/",
+ 60: "<",
+ 92: "\\"
+ };
+ /** Converts an untyped argument into a boolean in a "sensible" way, treating only the string "true" as true rather than any non-empty string * */
+ public static argToBool(input: any): boolean {
+ if (typeof input === "string") {
+ return input.toLowerCase() === "true";
+ }
+
+ return !!input;
+ }
+
+ public static readFileContentsSync(filename: string, encoding?: string): string {
+ var contents = fs.readFileSync(filename, (encoding || "utf-8"));
+ if (contents) {
+ contents = contents.replace(/^\uFEFF/, ""); // Windows is the BOM
+ }
+
+ return contents;
+ }
+
public static getOptionalArgsArrayFromFunctionCall(functionArguments: IArguments, startFrom: number): any[] {
if (functionArguments.length <= startFrom) {
return null;
@@ -88,6 +227,86 @@ module TacoUtility {
return Array.prototype.slice.apply(functionArguments, [startFrom]);
}
}
+
+ export class BuildInfo {
+ public status: string;
+ /**
+ * BuildInfo holds relevant information about a particular build, including its identifier, what kind of build was requested, and the status of the build
+ * This information is passed around both within the remote build server, and back to the client
+ */
+ public changeList: {
+ deletedFiles: string[];
+ changedFiles: string[];
+ addedPlugins: string[];
+ deletedPlugins: string[];
+ deletedFilesIos: string[];
+ changedFilesIos: string[];
+ addedPluginsIos: string[];
+ deletedPluginsIos: string[];
+ };
+ public statusTime: Date;
+ public cordovaVersion: string;
+ public buildCommand: string;
+ public configuration: string;
+ public options: any;
+ public buildDir: string;
+ public buildLang: string;
+ public buildPlatform: string;
+ public submissionTime: Date;
+ public buildNumber: number;
+
+ public messageId: string;
+ public messageArgs: any[];
+ public message: string;
+
+ public tgzFilePath: string;
+ public appDir: string;
+ public appName: string;
+
+ public webDebugProxyPort: number;
+
+ constructor(params: { buildNumber?: number; status?: string; cordovaVersion?: string; buildCommand?: string; configuration?: string; options?: any; buildDir?: string; buildLang?: string; buildPlatform?: string }) {
+ this.buildNumber = params.buildNumber;
+ this.status = params.status;
+ this.cordovaVersion = params.cordovaVersion;
+ this.buildCommand = params.buildCommand;
+ this.configuration = params.configuration;
+ this.options = params.options;
+ this.buildDir = params.buildDir;
+ this.buildLang = params.buildLang;
+ this.buildPlatform = params.buildPlatform;
+ this.submissionTime = new Date();
+ this.changeList = null;
+ }
+
+ public static createNewBuildInfoFromDataObject(buildInfoData: any): BuildInfo {
+ var bi: any = new BuildInfo(buildInfoData);
+ Object.keys(buildInfoData).forEach(function (k: string): void {
+ bi[k] = buildInfoData[k];
+ });
+ return bi;
+ }
+
+ public updateStatus(status: string, messageId?: string, ...messageArgs: any[]): void {
+ this.status = status;
+ this.messageId = messageId;
+ if (arguments.length > 2) {
+ this.messageArgs = UtilHelper.getOptionalArgsArrayFromFunctionCall(arguments, 2);
+ }
+
+ this.statusTime = new Date();
+ }
+
+ public localize(req: any): BuildInfo {
+ if (this.messageId) {
+ this.message = ResourcesManager.getStringForLanguage(req, this.messageId, this.messageArgs);
+ } else {
+ this.message = ResourcesManager.getStringForLanguage(req, "Build-" + this.status);
+ }
+
+ return this;
+ }
+ }
}
export = TacoUtility;
\ No newline at end of file
diff --git a/src/taco-utils/test/cordova-config.ts b/src/taco-utils/test/cordova-config.ts
new file mode 100644
index 00000000..9d22c4d6
--- /dev/null
+++ b/src/taco-utils/test/cordova-config.ts
@@ -0,0 +1,35 @@
+/**
+ * ******************************************************
+ * *
+ * Copyright (C) Microsoft. All rights reserved. *
+ * *
+ *******************************************************
+ */
+"use strict";
+///
+///
+import should = require ("should");
+import mocha = require ("mocha");
+
+import fs = require ("fs");
+import path = require ("path");
+
+import util = require ("../taco-utils");
+
+///
+var CordovaConfig = util.CordovaConfig;
+///
+
+describe("CordovaConfig", function (): void {
+ it("should correctly parse config files", function (): void {
+ var cfg = new CordovaConfig(path.join(__dirname, "resources", "config.xml"));
+ cfg.id().should.equal("org.foo.bar");
+ cfg.name().should.equal("FooBar");
+ cfg.version().should.equal("0.9.2");
+ });
+
+ it("should correctly normalize unicode display names", function (): void {
+ var cfg = new CordovaConfig(path.join(__dirname, "resources", "config_unicode.xml"));
+ cfg.name().should.equal("隣兀﨩"); // Note that this is NOT identical to the name in config_unicode, it is the normalized form.
+ });
+});
\ No newline at end of file
diff --git a/src/taco-utils/test/resources.ts b/src/taco-utils/test/resources.ts
new file mode 100644
index 00000000..ca2d4709
--- /dev/null
+++ b/src/taco-utils/test/resources.ts
@@ -0,0 +1,94 @@
+/**
+ * ******************************************************
+ * *
+ * Copyright (C) Microsoft. All rights reserved. *
+ * *
+ *******************************************************
+ */
+///
+///
+///
+"use strict";
+import path = require ("path");
+import should = require ("should");
+import mocha = require ("mocha");
+
+import util = require ("../taco-utils");
+
+var resources = util.ResourcesManager;
+
+describe("resources", function (): void {
+ before(function (): void {
+ resources.init("en", path.join(__dirname, "resources"));
+ });
+ after(function (): void {
+ resources.teardown();
+ });
+
+ it("should use the default language by default", function (): void {
+ var expectedResources = require(path.join(__dirname, "/resources/en/resources.json"));
+ var actual = resources.getString("SimpleMessage");
+ var expected = expectedResources["SimpleMessage"];
+ actual.should.equal(expected);
+ });
+
+ it("should correctly return strings for a primary language", function (): void {
+ var expectedResources = require(path.join(__dirname, "/resources/en/resources.json"));
+ var actual = resources.getStringForLanguage("en", "SimpleMessage");
+ var expected = expectedResources["SimpleMessage"];
+ actual.should.equal(expected);
+ });
+
+ it("should correctly return strings for a non-english primary language", function (): void {
+ var expectedResources = require(path.join(__dirname, "/resources/it/resources.json"));
+ var actual = resources.getStringForLanguage("it", "SimpleMessage");
+ var expected = expectedResources["SimpleMessage"];
+ actual.should.equal(expected);
+ });
+
+ it("should correctly substitute arguments in resource strings", function (): void {
+ var expectedResources = require(path.join(__dirname, "/resources/en/resources.json"));
+ var actual = resources.getStringForLanguage("en", "MessageWithArgs", "Billy", "Fish");
+ var expected = expectedResources["MessageWithArgs"];
+ var actualBackToExpected = actual.replace("Billy", "{0}").replace("Fish", "{1}");
+ actualBackToExpected.should.equal(expected);
+
+ var actualWithArrayArgs = resources.getStringForLanguage("en", "MessageWithArgs", ["Billy", "Fish"]);
+ actualWithArrayArgs.should.equal(actual);
+ });
+
+ it("should find the most specific region for a language", function (): void {
+ var expectedResources = require(path.join(__dirname, "/resources/it-ch/resources.json"));
+ var actual = resources.getStringForLanguage("it-ch", "SimpleMessage");
+ var expected = expectedResources["SimpleMessage"];
+ actual.should.equal(expected);
+ });
+
+ it("should fall back to more general languages if a more specific one is not available", function (): void {
+ var expectedResources = require(path.join(__dirname, "/resources/it/resources.json"));
+ var actual = resources.getStringForLanguage("it-DE", "SimpleMessage");
+ var expected = expectedResources["SimpleMessage"];
+ actual.should.equal(expected);
+ });
+
+ it("should fall back to english as a default if the language is unknown", function (): void {
+ var expectedResources = require(path.join(__dirname, "/resources/en/resources.json"));
+ var actual = resources.getStringForLanguage("hy-Latn-IT-arevela", "SimpleMessage");
+ var expected = expectedResources["SimpleMessage"];
+ actual.should.equal(expected);
+ });
+
+ it("should return undefined for bad resource identifiers", function (): void {
+ var actual = resources.getStringForLanguage("en", "NoResourceDefinedForThis");
+ ///
+ should(actual).be.equal(undefined);
+ ///
+ });
+
+ it("should handle unicode in resource strings", function (): void {
+ var expectedResources = require(path.join(__dirname, "/resources/gb18030/resources.json"));
+ var actual = resources.getStringForLanguage("gb18030", "UnicodeMessage");
+ var expected = expectedResources["UnicodeMessage"];
+ actual.should.equal(expected);
+ });
+});
\ No newline at end of file
diff --git a/src/taco-utils/test/resources/config.xml b/src/taco-utils/test/resources/config.xml
new file mode 100644
index 00000000..a320aff3
--- /dev/null
+++ b/src/taco-utils/test/resources/config.xml
@@ -0,0 +1,16 @@
+
+
+ FooBar
+
+ A sample Apache Cordova application that responds to the deviceready event.
+
+
+ Apache Cordova Team
+
+
+
+
+
+
diff --git a/src/taco-utils/test/resources/config_unicode.xml b/src/taco-utils/test/resources/config_unicode.xml
new file mode 100644
index 00000000..d8d15061
--- /dev/null
+++ b/src/taco-utils/test/resources/config_unicode.xml
@@ -0,0 +1,16 @@
+
+
+ 隣兀﨩
+
+ A sample Apache Cordova application that responds to the deviceready event.
+
+
+ Apache Cordova Team
+
+
+
+
+
+
diff --git a/src/taco-utils/test/resources/en/resources.json b/src/taco-utils/test/resources/en/resources.json
new file mode 100644
index 00000000..e9829718
--- /dev/null
+++ b/src/taco-utils/test/resources/en/resources.json
@@ -0,0 +1,4 @@
+{
+ "SimpleMessage": "Hello",
+ "MessageWithArgs": "Hello {0} {1}"
+}
\ No newline at end of file
diff --git a/src/taco-utils/test/resources/gb18030/resources.json b/src/taco-utils/test/resources/gb18030/resources.json
new file mode 100644
index 00000000..fb2782e3
--- /dev/null
+++ b/src/taco-utils/test/resources/gb18030/resources.json
@@ -0,0 +1,3 @@
+{
+ "UnicodeMessage": "啊齄丂狛狜隣郎隣兀﨩ˊ▇█〞〡¦℡㈱‐ー﹡﹢﹫、〓ⅰⅹ⒈€㈠㈩ⅠⅫ! ̄ぁんァヶΑ︴АЯаяāɡㄅㄩ─╋︵﹄︻︱︳︴ⅰⅹɑɡ〇〾⿻⺁䜣€龹龻㐀㒣㕴㕵㙉㙊䵯䵰䶴䶵𠀀𠀁𠀂𠀃𪛑𪛒𪛓𪛔𪛕𪛖"
+}
\ No newline at end of file
diff --git a/src/taco-utils/test/resources/it-ch/resources.json b/src/taco-utils/test/resources/it-ch/resources.json
new file mode 100644
index 00000000..a5d1c3f8
--- /dev/null
+++ b/src/taco-utils/test/resources/it-ch/resources.json
@@ -0,0 +1,4 @@
+{
+ "SimpleMessage": "Ciao it-CH",
+ "MessageWithArgs": "Ciao {0} {1} it-CH"
+}
\ No newline at end of file
diff --git a/src/taco-utils/test/resources/it/resources.json b/src/taco-utils/test/resources/it/resources.json
new file mode 100644
index 00000000..9b696776
--- /dev/null
+++ b/src/taco-utils/test/resources/it/resources.json
@@ -0,0 +1,4 @@
+{
+ "SimpleMessage": "Ciao",
+ "MessageWithArgs": "Ciao {0} {1}"
+}
\ No newline at end of file
diff --git a/src/typings/elementtree.d.ts b/src/typings/elementtree.d.ts
new file mode 100644
index 00000000..79cf52b2
--- /dev/null
+++ b/src/typings/elementtree.d.ts
@@ -0,0 +1,18 @@
+// Barebones typing for elementtree, added as-needed
+
+declare module "elementtree" {
+ export class ElementTree {
+ constructor(xml: XMLElement);
+
+ getroot(): XMLElement
+ find(name: string): XMLElement;
+ findall(name: string): XMLElement[];
+ }
+
+ export class XMLElement {
+ attrib: { [key: string]: string };
+ text: string;
+ }
+
+ export function XML(data: string): XMLElement;
+}
\ No newline at end of file
diff --git a/src/typings/mocha.d.ts b/src/typings/mocha.d.ts
new file mode 100644
index 00000000..30f02f6d
--- /dev/null
+++ b/src/typings/mocha.d.ts
@@ -0,0 +1,114 @@
+// Type definitions for mocha 1.17.1
+// Project: http://visionmedia.github.io/mocha/
+// Definitions by: Kazi Manzur Rashid , otiai10
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+interface Mocha {
+ // Setup mocha with the given setting options.
+ setup(options: MochaSetupOptions): Mocha;
+
+ //Run tests and invoke `fn()` when complete.
+ run(callback?: () => void): void;
+
+ // Set reporter as function
+ reporter(reporter: () => void): Mocha;
+
+ // Set reporter, defaults to "dot"
+ reporter(reporter: string): Mocha;
+
+ // Enable growl support.
+ growl(): Mocha
+}
+
+interface MochaSetupOptions {
+ //milliseconds to wait before considering a test slow
+ slow?: number;
+
+ // timeout in milliseconds
+ timeout?: number;
+
+ // ui name "bdd", "tdd", "exports" etc
+ ui?: string;
+
+ //array of accepted globals
+ globals?: any[];
+
+ // reporter instance (function or string), defaults to `mocha.reporters.Dot`
+ reporter?: any;
+
+ // bail on the first test failure
+ bail?: Boolean;
+
+ // ignore global leaks
+ ignoreLeaks?: Boolean;
+
+ // grep string or regexp to filter tests with
+ grep?: any;
+}
+
+interface MochaDone {
+ (error?: Error): void;
+}
+
+declare var mocha: Mocha;
+
+declare var describe: {
+ (description: string, spec: () => void): void;
+ only(description: string, spec: () => void): void;
+ skip(description: string, spec: () => void): void;
+ timeout(ms: number): void;
+}
+
+// alias for `describe`
+declare var context: {
+ (contextTitle: string, spec: () => void): void;
+ only(contextTitle: string, spec: () => void): void;
+ skip(contextTitle: string, spec: () => void): void;
+ timeout(ms: number): void;
+}
+
+declare var it: {
+ (expectation: string, assertion?: () => void): void;
+ (expectation: string, assertion?: (done: MochaDone) => void): void;
+ only(expectation: string, assertion?: () => void): void;
+ only(expectation: string, assertion?: (done: MochaDone) => void): void;
+ skip(expectation: string, assertion?: () => void): void;
+ skip(expectation: string, assertion?: (done: MochaDone) => void): void;
+ timeout(ms: number): void;
+};
+
+declare function before(action: () => void): void;
+
+declare function before(action: (done: MochaDone) => void): void;
+
+declare function setup(action: () => void): void;
+
+declare function setup(action: (done: MochaDone) => void): void;
+
+declare function after(action: () => void): void;
+
+declare function after(action: (done: MochaDone) => void): void;
+
+declare function teardown(action: () => void): void;
+
+declare function teardown(action: (done: MochaDone) => void): void;
+
+declare function beforeEach(action: () => void): void;
+
+declare function beforeEach(action: (done: MochaDone) => void): void;
+
+declare function suiteSetup(action: () => void): void;
+
+declare function suiteSetup(action: (done: MochaDone) => void): void;
+
+declare function afterEach(action: () => void): void;
+
+declare function afterEach(action: (done: MochaDone) => void): void;
+
+declare function suiteTeardown(action: () => void): void;
+
+declare function suiteTeardown(action: (done: MochaDone) => void): void;
+
+declare module "mocha" {
+ export = undefined;
+}
\ No newline at end of file
diff --git a/src/typings/should.d.ts b/src/typings/should.d.ts
new file mode 100644
index 00000000..e9af28df
--- /dev/null
+++ b/src/typings/should.d.ts
@@ -0,0 +1,122 @@
+// Type definitions for should.js 3.1.2
+// Project: https://github.com/visionmedia/should.js
+// Definitions by: Alex Varju , Maxime LUCE
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+interface Object {
+ should: ShouldAssertion;
+}
+
+interface ShouldAssertion {
+ // basic grammar
+ a: ShouldAssertion;
+ an: ShouldAssertion;
+ and: ShouldAssertion;
+ be: ShouldAssertion;
+ have: ShouldAssertion;
+ with: ShouldAssertion;
+ of: ShouldAssertion;
+ not: ShouldAssertion;
+
+ // validators
+ arguments: ShouldAssertion;
+ empty: ShouldAssertion;
+ ok: ShouldAssertion;
+ true: ShouldAssertion;
+ false: ShouldAssertion;
+ NaN: ShouldAssertion;
+ Infinity: ShouldAssertion;
+ Array: ShouldAssertion;
+ Object: ShouldAssertion;
+ String: ShouldAssertion;
+ Boolean: ShouldAssertion;
+ Number: ShouldAssertion;
+ Error: ShouldAssertion;
+ Function: ShouldAssertion;
+ eql(expected: any, description?: string): ShouldAssertion;
+ equal(expected: any, description?: string): ShouldAssertion;
+ within(start: number, finish: number, description?: string): ShouldAssertion;
+ approximately(value: number, delta: number, description?: string): ShouldAssertion;
+ type(expected: any, description?: string): ShouldAssertion;
+ instanceof(constructor: Function, description?: string): ShouldAssertion;
+ above(n: number, description?: string): ShouldAssertion;
+ below(n: number, description?: string): ShouldAssertion;
+ match(other: {}, description?: string): ShouldAssertion;
+ match(other: (val: any) => any, description?: string): ShouldAssertion;
+ match(regexp: RegExp, description?: string): ShouldAssertion;
+ match(other: any, description?: string): ShouldAssertion;
+ matchEach(other: {}, description?: string): ShouldAssertion;
+ matchEach(other: (val: any) => any, description?: string): ShouldAssertion;
+ matchEach(regexp: RegExp, description?: string): ShouldAssertion;
+ matchEach(other: any, description?: string): ShouldAssertion;
+ length(n: number, description?: string): ShouldAssertion;
+ property(name: string, description?: string): ShouldAssertion;
+ property(name: string, val: any, description?: string): ShouldAssertion;
+ properties(names: string[]): ShouldAssertion;
+ properties(name: string): ShouldAssertion;
+ properties(descriptor: any): ShouldAssertion;
+ properties(...properties: string[]): ShouldAssertion;
+ ownProperty(name: string, description?: string): ShouldAssertion;
+ contain(obj: any): ShouldAssertion;
+ containEql(obj: any): ShouldAssertion;
+ containDeep(obj: any): ShouldAssertion;
+ keys(...allKeys: string[]): ShouldAssertion;
+ keys(allKeys: string[]): ShouldAssertion;
+ header(field: string, val?: string): ShouldAssertion;
+ status(code: number): ShouldAssertion;
+ json: ShouldAssertion;
+ html: ShouldAssertion;
+ startWith(expected: string, message?: any): ShouldAssertion;
+ endWith(expected: string, message?: any): ShouldAssertion;
+ throw(message?: any): ShouldAssertion;
+
+ // deprecated
+ include(obj: any, description?: string): ShouldAssertion;
+ includeEql(obj: any[], description?: string): ShouldAssertion;
+
+ // aliases
+ exactly(expected: any, description?: string): ShouldAssertion;
+ instanceOf(constructor: Function, description?: string): ShouldAssertion;
+ throwError(message?: any): ShouldAssertion;
+ lengthOf(n: number, description?: string): ShouldAssertion;
+ key(key: string): ShouldAssertion;
+ haveOwnProperty(name: string, description?: string): ShouldAssertion;
+ greaterThan(n: number, description?: string): ShouldAssertion;
+ lessThan(n: number, description?: string): ShouldAssertion;
+}
+
+interface ShouldInternal {
+ // should.js's extras
+ exist(actual: any, msg?: string): void;
+ exists(actual: any, msg?: string): void;
+ not: ShouldInternal;
+}
+
+interface Internal extends ShouldInternal {
+ (obj: any): ShouldAssertion;
+
+ // node.js's assert functions
+ fail(actual: any, expected: any, message: string, operator: string): void;
+ assert(value: any, message: string): void;
+ ok(value: any, message?: string): void;
+ equal(actual: any, expected: any, message?: string): void;
+ notEqual(actual: any, expected: any, message?: string): void;
+ deepEqual(actual: any, expected: any, message?: string): void;
+ notDeepEqual(actual: any, expected: any, message?: string): void;
+ strictEqual(actual: any, expected: any, message?: string): void;
+ notStrictEqual(actual: any, expected: any, message?: string): void;
+ throws(block: any, error?: any, message?: string): void;
+ doesNotThrow(block: any, message?: string): void;
+ ifError(value: any): void;
+ inspect(value: any, obj: any): any;
+}
+
+declare var should: Internal;
+declare var Should: Internal;
+interface Window {
+ Should: Internal;
+}
+
+declare module "should" {
+ export = should;
+}
diff --git a/src/typings/taco-utils.d.ts b/src/typings/taco-utils.d.ts
index 58890253..35ff932c 100644
--- a/src/typings/taco-utils.d.ts
+++ b/src/typings/taco-utils.d.ts
@@ -1,14 +1,103 @@
///
+///
+///
declare module TacoUtility {
class ResourcesManager {
private static Resources;
+ private static SupportedLanguages;
private static DefaultLanguage;
static init(language: string, resourcesDir?: string): void;
+ static teardown(): void;
+ /** ...optionalArgs is only there for typings, function rest params */
static getString(id: string, ...optionalArgs: any[]): string;
- static bestLanguageMatchOrDefault(language: string, resourcesDir: string): string;
- static loadLanguage(language: string, resourcesDir: string): any;
+ /** ** ...optionalArgs is only there for typings, function rest params** */
+ static getStringForLanguage(requestOrAcceptLangs: any, id: string, ...optionalArgs: any[]): string;
+ private static bestLanguageMatchOrDefault(requestOrAcceptLangs);
+ /**
+ * requestOrAcceptLangs can either be:
+ * A string, with format "LangSpec[,LangSpec]*" where LangSpec is "Language[;anything]"
+ * e.g. "pl,fr-FR;q=0.3,en-US;q=0.1" is interpreted as "pl" or "fr-FR" or "en-US". Currently we ignore provided quality (q) values
+ * An array, which we assume is an array of strings representing languages such as "pl" or "fr-FR"
+ * A (express-style) HTTP Request object, with a headers property specifing "accept-language" in a string, as above
+ *
+ * This allows us to handle simple cases of a single string, as well as more complex cases where a client specifies
+ * multiple preferences.
+ */
+ private static bestLanguageMatch(requestOrAcceptLangs);
+ /**
+ * Given a list of languages, we try to find an exact match if we can, and we fall back to a primary language otherwise.
+ * e.g. "fr-CA" will use "fr-CA" resources if present, but will fall back to "fr" resources if they are available
+ */
+ private static getBestLanguageFromArray(acceptLangs);
+ private static loadLanguage(language, resourcesDir);
+ private static getOptionalArgsArrayFromFunctionCall(functionArguments, startFrom);
+ }
+ class CordovaConfig {
+ /** CordovaConfig is a class for parsing the config.xml file for Cordova projects */
+ private _doc;
+ constructor(configXmlPath: string);
+ id(): string;
+ name(): string;
+ version(): string;
+ preferences(): {
+ [key: string]: string;
+ };
+ }
+ class UtilHelper {
+ private static InvalidAppNameChars;
+ /** Converts an untyped argument into a boolean in a "sensible" way, treating only the string "true" as true rather than any non-empty string * */
+ static argToBool(input: any): boolean;
+ static readFileContentsSync(filename: string, encoding?: string): string;
static getOptionalArgsArrayFromFunctionCall(functionArguments: IArguments, startFrom: number): any[];
}
+ class BuildInfo {
+ status: string;
+ /**
+ * BuildInfo holds relevant information about a particular build, including its identifier, what kind of build was requested, and the status of the build
+ * This information is passed around both within the remote build server, and back to the client
+ */
+ changeList: {
+ deletedFiles: string[];
+ changedFiles: string[];
+ addedPlugins: string[];
+ deletedPlugins: string[];
+ deletedFilesIos: string[];
+ changedFilesIos: string[];
+ addedPluginsIos: string[];
+ deletedPluginsIos: string[];
+ };
+ statusTime: Date;
+ cordovaVersion: string;
+ buildCommand: string;
+ configuration: string;
+ options: any;
+ buildDir: string;
+ buildLang: string;
+ buildPlatform: string;
+ submissionTime: Date;
+ buildNumber: number;
+ messageId: string;
+ messageArgs: any[];
+ message: string;
+ tgzFilePath: string;
+ appDir: string;
+ appName: string;
+ webDebugProxyPort: number;
+ constructor(params: {
+ buildNumber?: number;
+ status?: string;
+ cordovaVersion?: string;
+ buildCommand?: string;
+ configuration?: string;
+ options?: any;
+ buildDir?: string;
+ buildLang?: string;
+ buildPlatform?: string;
+ });
+ static createNewBuildInfoFromDataObject(buildInfoData: any): BuildInfo;
+ updateStatus(status: string, messageId?: string, ...messageArgs: any[]): void;
+ localize(req: any): BuildInfo;
+ }
}
declare module "taco-utils"{
export = TacoUtility;
diff --git a/src/typings/unorm.d.ts b/src/typings/unorm.d.ts
new file mode 100644
index 00000000..153d1ea7
--- /dev/null
+++ b/src/typings/unorm.d.ts
@@ -0,0 +1,12 @@
+// Barebones typing for unorm, added as-needed
+
+interface Object {
+ normalize: (form?: string) => string;
+}
+
+declare module "unorm" {
+ export function nfc(str: string): string;
+ export function nfd(str: string): string;
+ export function nfkc(str: string): string;
+ export function nfkd(str: string): string;
+}
\ No newline at end of file