Updating ResourceManager to allow multiple languages to be specified (for vs-mda-remote)

Adding tests for ResourceManger (which pass!)

Added more error checking to typescript compilation (When the error is not to do with a file, it would crash in the error reporting code).
Adding in more utility code

Added in cordova config parser to utils, along with the start of some file helpers.
Fixed up compilation of resources.ts. Protip: ///references have to be before any code, such as "use strict"

Added BuildInfo class to util since that will be common across client and server (as well as server components)
This commit is contained in:
Jimmy Thomson 2015-02-04 10:03:05 -08:00
Родитель 51b263407a
Коммит cf44cd6fc3
17 изменённых файлов: 800 добавлений и 42 удалений

Просмотреть файл

@ -36,7 +36,7 @@ gulp.task("rebuild", ["clean"], function (callback: Function): void {
gulp.task("run-stylecop", function (callback: Function): void { gulp.task("run-stylecop", function (callback: Function): void {
if (fs.existsSync(buildConfig.copPath)) { if (fs.existsSync(buildConfig.copPath)) {
var styleCop = new stylecopUtil.StyleCopUtil(); var styleCop = new stylecopUtil.StyleCopUtil();
styleCop.runCop(path.join(buildConfig.src, ".."), buildConfig.copPath, callback); styleCop.runCop(buildConfig.src, buildConfig.copPath, callback);
} else { } else {
callback(); callback();
} }
@ -51,6 +51,7 @@ gulp.task("clean", function (callback: Function): void {
gulp.task("copy", 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, "/**/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, "/**/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*/ /* auto-generate taco-utils.d.ts*/

Просмотреть файл

@ -44,7 +44,6 @@ export class TypeScriptServices {
if (!fs.statSync(currentPath).isDirectory()) { if (!fs.statSync(currentPath).isDirectory()) {
/* push the typescript files */ /* push the typescript files */
if (path.extname(currentPath) === ".ts" && if (path.extname(currentPath) === ".ts" &&
!currentPath.match("d.ts$") &&
!currentPath.match("gulpfile.ts") && !currentPath.match("gulpfile.ts") &&
!currentPath.match("gulpmain.ts")) { !currentPath.match("gulpmain.ts")) {
result.push(currentPath); result.push(currentPath);
@ -79,8 +78,12 @@ export class TypeScriptServices {
*/ */
private logDiagnosticMessage(diagnostic: ts.Diagnostic): void { private logDiagnosticMessage(diagnostic: ts.Diagnostic): void {
var sourceFile = diagnostic.file; var sourceFile = diagnostic.file;
var lineAndCharacter = sourceFile.getLineAndCharacterFromPosition(diagnostic.start); if (sourceFile) {
console.warn(sourceFile.filename + "(" + lineAndCharacter.line + "," + lineAndCharacter.character + "): " + diagnostic.messageText); var lineAndCharacter = sourceFile.getLineAndCharacterFromPosition(diagnostic.start);
console.warn(sourceFile.filename + "(" + lineAndCharacter.line + "," + lineAndCharacter.character + "): " + diagnostic.messageText);
} else {
console.warn(diagnostic.messageText);
}
} }
} }

Просмотреть файл

@ -7,9 +7,13 @@
"version": "0.0.1", "version": "0.0.1",
"main": "taco-utils.js", "main": "taco-utils.js",
"dependencies": { "dependencies": {
"elementtree": "0.1.6",
"unorm": "1.3.3"
}, },
"private": true, "private": true,
"devDependencies": { "devDependencies": {
"typescript": ">=1.4.1" "typescript": ">=1.4.1",
"mocha": "2.0.1",
"should": "4.3.0"
} }
} }

Просмотреть файл

@ -1,39 +1,71 @@
/// <reference path="../typings/node.d.ts" /> /// <reference path="../typings/node.d.ts" />
/// <reference path="../typings/elementtree.d.ts"/>
/// <reference path="../typings/unorm.d.ts"/>
"use strict"; "use strict";
import et = require ("elementtree");
import fs = require ("fs"); import fs = require ("fs");
import path = require ("path"); 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 { module TacoUtility {
// put more classes here, known limitation that classes in external modules CANNOT span multiple files // put more classes here, known limitation that classes in external modules CANNOT span multiple files
export class ResourcesManager { export class ResourcesManager {
private static Resources: any = null; private static Resources: { [key: string]: any; } = null;
private static DefaultLanguage: string = "en"; 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) { if (!resourcesDir) {
resourcesDir = path.join(__dirname, "..", "resources"); resourcesDir = path.join(__dirname, "..", "resources");
} }
var lang = this.bestLanguageMatchOrDefault(language, resourcesDir); ResourcesManager.Resources = {};
this.Resources = this.loadLanguage(lang, resourcesDir); 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 { 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"); 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) { if (!s) {
return 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: /*All args passed to current function:
you can call getString('foo', 'bar', 'baz') or getString('foo',['bar', 'baz']) 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*/ 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) { if (args) {
for (var i: number = 0; i < args.length; i++) { for (var i: number = 0; i < args.length; i++) {
s = s.replace("{" + i + "}", args[i]); s = s.replace("{" + i + "}", args[i]);
@ -43,39 +75,146 @@ module TacoUtility {
return s; return s;
} }
public static bestLanguageMatchOrDefault(language: string, resourcesDir: string): string { private static bestLanguageMatchOrDefault(requestOrAcceptLangs: any): string {
if (!language) { var lang = ResourcesManager.bestLanguageMatch(requestOrAcceptLangs);
return this.DefaultLanguage; if (!ResourcesManager.Resources[lang]) {
lang = ResourcesManager.DefaultLanguage;
} }
var supportedLanguages: string[] = []; return lang.toLowerCase();
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;
} }
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"); var resourcesPath = path.join(resourcesDir, language, "resources.json");
return require(resourcesPath); 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[] { public static getOptionalArgsArrayFromFunctionCall(functionArguments: IArguments, startFrom: number): any[] {
if (functionArguments.length <= startFrom) { if (functionArguments.length <= startFrom) {
return null; return null;
@ -88,6 +227,86 @@ module TacoUtility {
return Array.prototype.slice.apply(functionArguments, [startFrom]); 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; export = TacoUtility;

Просмотреть файл

@ -0,0 +1,35 @@
/**
 * ******************************************************
 * *
 * Copyright (C) Microsoft. All rights reserved. *
 * *
 *******************************************************
 */
"use strict";
/// <reference path="../../typings/should.d.ts"/>
/// <reference path="../../typings/mocha.d.ts"/>
import should = require ("should");
import mocha = require ("mocha");
import fs = require ("fs");
import path = require ("path");
import util = require ("../taco-utils");
/// <disable code="SA1301" justification="CordovaConfig is a class" />
var CordovaConfig = util.CordovaConfig;
/// <enable code="SA1301" />
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.
});
});

Просмотреть файл

@ -0,0 +1,94 @@
/**
 * ******************************************************
 * *
 * Copyright (C) Microsoft. All rights reserved. *
 * *
 *******************************************************
 */
/// <reference path="../../typings/node.d.ts"/>
/// <reference path="../../typings/should.d.ts"/>
/// <reference path="../../typings/mocha.d.ts"/>
"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");
/// <disable code="SA9017" justification="We want to capture any changes in behavior, and currently it returns undefined" />
should(actual).be.equal(undefined);
/// <enable code="SA9017" />
});
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);
});
});

Просмотреть файл

@ -0,0 +1,16 @@
<?xml version='1.0' encoding='utf-8'?>
<widget id="org.foo.bar" version="0.9.2" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0" xmlns:vs="http://schemas.microsoft.com/appx/2014/htmlapps" xmlns:gap="http://phonegap.com/ns/1.0">
<name>FooBar</name>
<description>
A sample Apache Cordova application that responds to the deviceready event.
</description>
<author email="dev@cordova.apache.org" href="http://cordova.io">
Apache Cordova Team
</author>
<content src="index.html" />
<access origin="*" />
<preference name="SplashScreen" value="screen" />
<!--<vs:features>
<vs:feature>org.apache.cordova.splashscreen</vs:feature>
</vs:features>-->
</widget>

Просмотреть файл

@ -0,0 +1,16 @@
<?xml version='1.0' encoding='utf-8'?>
<widget id="org.foo.bar" version="0.9.2" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0" xmlns:vs="http://schemas.microsoft.com/appx/2014/htmlapps" xmlns:gap="http://phonegap.com/ns/1.0">
<name>隣兀﨩</name>
<description>
A sample Apache Cordova application that responds to the deviceready event.
</description>
<author email="dev@cordova.apache.org" href="http://cordova.io">
Apache Cordova Team
</author>
<content src="index.html" />
<access origin="*" />
<preference name="SplashScreen" value="screen" />
<!--<vs:features>
<vs:feature>org.apache.cordova.splashscreen</vs:feature>
</vs:features>-->
</widget>

Просмотреть файл

@ -0,0 +1,4 @@
{
"SimpleMessage": "Hello",
"MessageWithArgs": "Hello {0} {1}"
}

Просмотреть файл

@ -0,0 +1,3 @@
{
"UnicodeMessage": "啊齄丂狛狜隣郎隣兀﨩ˊ▇█〞〡¦℡㈱‐ー﹡﹢﹫、〓ⅰⅹ⒈€㈠㈩ⅠⅫ! ̄ぁんァヶΑ︴АЯаяāɡㄅㄩ─╋︵﹄︻︱︳︴ⅰⅹɑɡ〇〾⿻⺁䜣€龹龻㐀㒣㕴㕵㙉㙊䵯䵰䶴䶵𠀀𠀁𠀂𠀃𪛑𪛒𪛓𪛔𪛕𪛖"
}

Просмотреть файл

@ -0,0 +1,4 @@
{
"SimpleMessage": "Ciao it-CH",
"MessageWithArgs": "Ciao {0} {1} it-CH"
}

Просмотреть файл

@ -0,0 +1,4 @@
{
"SimpleMessage": "Ciao",
"MessageWithArgs": "Ciao {0} {1}"
}

18
src/typings/elementtree.d.ts поставляемый Normal file
Просмотреть файл

@ -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;
}

114
src/typings/mocha.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,114 @@
// Type definitions for mocha 1.17.1
// Project: http://visionmedia.github.io/mocha/
// Definitions by: Kazi Manzur Rashid <https://github.com/kazimanzurrashid/>, otiai10 <https://github.com/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;
}

122
src/typings/should.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,122 @@
// Type definitions for should.js 3.1.2
// Project: https://github.com/visionmedia/should.js
// Definitions by: Alex Varju <https://github.com/varju/>, Maxime LUCE <https://github.com/SomaticIT/>
// 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;
}

93
src/typings/taco-utils.d.ts поставляемый
Просмотреть файл

@ -1,14 +1,103 @@
/// <reference path="../typings/node.d.ts" /> /// <reference path="../typings/node.d.ts" />
/// <reference path="../typings/elementtree.d.ts" />
/// <reference path="../typings/unorm.d.ts" />
declare module TacoUtility { declare module TacoUtility {
class ResourcesManager { class ResourcesManager {
private static Resources; private static Resources;
private static SupportedLanguages;
private static DefaultLanguage; private static DefaultLanguage;
static init(language: string, resourcesDir?: string): void; 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 getString(id: string, ...optionalArgs: any[]): string;
static bestLanguageMatchOrDefault(language: string, resourcesDir: string): string; /** ** ...optionalArgs is only there for typings, function rest params** */
static loadLanguage(language: string, resourcesDir: string): any; 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[]; 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"{ declare module "taco-utils"{
export = TacoUtility; export = TacoUtility;

12
src/typings/unorm.d.ts поставляемый Normal file
Просмотреть файл

@ -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;
}