diff --git a/.gitignore b/.gitignore
index de42debdd..99b4fcc42 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,6 @@
.sublime-grunt.cache
tscommand*.tmp.txt
.tscache
-*.js
node_modules/
dist/
@@ -20,3 +19,7 @@ CrossPlatformModules.csproj.user
bin/
obj/
.vs/
+
+.baseDir.ts
+.ctags-exclude
+tags
diff --git a/gruntfile.js b/gruntfile.js
index 853c205bb..0311ffad2 100644
--- a/gruntfile.js
+++ b/gruntfile.js
@@ -142,6 +142,12 @@ module.exports = function(grunt) {
]
};
+ var nodeTestEnv = JSON.parse(JSON.stringify(process.env));
+ nodeTestEnv['NODE_PATH'] = localCfg.outModulesDir;
+
+ localCfg.nodeTestsDir = pathModule.join(localCfg.outModulesDir, 'node-tests');
+
+
localCfg.mainPackageContent = grunt.file.readJSON(localCfg.packageJsonFilePath);
localCfg.packageVersion = getPackageVersion(localCfg.packageJsonFilePath);
localCfg.commitSHA = getCommitSha();
@@ -180,6 +186,9 @@ module.exports = function(grunt) {
],
cwd: localCfg.outModulesDir
},
+ nodeTests: {
+ src: localCfg.nodeTestsDir,
+ },
readyAppFiles: {
src: [localCfg.outModulesDir + "/apps/**"]
}
@@ -293,6 +302,25 @@ module.exports = function(grunt) {
src: localCfg.typeScriptSrc,
outDir: localCfg.outModulesDir,
options: {
+ fast: 'never',
+ module: "commonjs",
+ target: "es5",
+ sourceMap: false,
+ declaration: false,
+ removeComments: "<%= !grunt.option('leavecomments') || '' %>",
+ compiler: "node_modules/typescript/bin/tsc",
+ noEmitOnError: true
+ }
+ },
+ buildNodeTests: {
+ src: [
+ 'js-libs/easysax/**/*.ts',
+ 'xml/**/*.ts',
+ 'node-tests/**/*.ts',
+ ],
+ outDir: localCfg.outModulesDir,
+ options: {
+ fast: 'never',
module: "commonjs",
target: "es5",
sourceMap: false,
@@ -325,6 +353,9 @@ module.exports = function(grunt) {
packApp: {
cmd: "npm pack",
cwd: "__dummy__"
+ },
+ mochaNode: {
+ cmd: "grunt simplemocha:node"
}
},
multidest: {
@@ -347,6 +378,16 @@ module.exports = function(grunt) {
options: {
callback: assignGitSHA
}
+ },
+ },
+ simplemocha: {
+ node: {
+ src: localCfg.nodeTestsDir + '/**/*.js'
+ }
+ },
+ env: {
+ nodeTests: {
+ NODE_PATH: localCfg.outModulesDir,
}
}
});
@@ -358,6 +399,8 @@ module.exports = function(grunt) {
grunt.loadNpmTasks("grunt-tslint");
grunt.loadNpmTasks("grunt-multi-dest");
grunt.loadNpmTasks("grunt-shell");
+ grunt.loadNpmTasks("grunt-env");
+ grunt.loadNpmTasks("grunt-simple-mocha");
var cloneTasks = function(originalTasks, taskNameSuffix)
{
@@ -486,4 +529,19 @@ module.exports = function(grunt) {
"pack-definitions",
"get-ready-packages"
]));
+
+ grunt.registerTask("testEnv", function() {
+ console.log('fafla', process.env.NODE_PATH);
+ //var x = require('xml')
+ //console.log(x);
+ });
+
+ grunt.registerTask("node-tests", [
+ "clean:nodeTests",
+ "ts:buildNodeTests",
+ "copy:childPackageFiles",
+ "copy:jsLibs",
+ "env:nodeTests",
+ "exec:mochaNode", //spawn a new process to use the new NODE_PATH
+ ]);
};
diff --git a/js-libs/easysax/easysax.d.ts b/js-libs/easysax/easysax.d.ts
index e70c1d1e2..3f2d82226 100644
--- a/js-libs/easysax/easysax.d.ts
+++ b/js-libs/easysax/easysax.d.ts
@@ -5,6 +5,7 @@ declare module "js-libs/easysax" {
parse(xml: string): void;
on(name: string, cb: Function): void;
ns(root: string, ns: any): void;
+ public angularSyntax: boolean;
}
}
diff --git a/js-libs/easysax/easysax.js b/js-libs/easysax/easysax.js
index 9828d8333..321eabc0a 100644
--- a/js-libs/easysax/easysax.js
+++ b/js-libs/easysax/easysax.js
@@ -54,17 +54,11 @@
};
-
-
*/
// << ------------------------------------------------------------------------ >> //
-
-
-
-
if (typeof exports === 'object' /*&& this == exports*/) {
module.exports.EasySAXParser = EasySAXParser;
};
@@ -74,133 +68,162 @@ function EasySAXParser() {
if (!this) return null;
+ this.angularSyntax = false;
+
function nullFunc() {};
- var onTextNode = nullFunc, onStartNode = nullFunc, onEndNode = nullFunc, onCDATA = nullFunc, onError = nullFunc, onComment, onQuestion, onAttention;
- var is_onComment, is_onQuestion, is_onAttention;
+ this.onTextNode = nullFunc;
+ this.onStartNode = nullFunc;
+ this.onEndNode = nullFunc;
+ this.onCDATA = nullFunc;
+ this.onError = nullFunc;
+ this.onComment = null;
+ this.onQuestion = null;
+ this.onAttention = null;
+ this.is_onComment = this.is_onQuestion = this.is_onAttention = false;
- var isNamespace = false, useNS , default_xmlns, xmlns
- , nsmatrix = {xmlns: xmlns}
- , hasSurmiseNS = false
+ this.isNamespace = false;
+ this.useNS = null;
+ this.default_xmlns = null;
+ this.xmlns = null;
+ this.nsmatrix = {xmlns: this.xmlns};
+ this.hasSurmiseNS = false;
;
- this.on = function(name, cb) {
- if (typeof cb !== 'function') {
- if (cb !== null) return;
- };
+ this.attr_string = ''; // строка атрибутов
+ this.attr_posstart = 0; //
+ this.attr_res; // закешированный результат разбора атрибутов , null - разбор не проводился, object - хеш атрибутов, true - нет атрибутов, false - невалидный xml
+}
- switch(name) {
- case 'error': onError = cb || nullFunc; break;
- case 'startNode': onStartNode = cb || nullFunc; break;
- case 'endNode': onEndNode = cb || nullFunc; break;
- case 'textNode': onTextNode = cb || nullFunc; break;
- case 'cdata': onCDATA = cb || nullFunc; break;
+EasySAXParser.prototype.on = function(name, cb) {
+ if (typeof cb !== 'function') {
+ if (cb !== null) return;
+ };
- case 'comment': onComment = cb; is_onComment = !!cb; break;
- case 'question': onQuestion = cb; is_onQuestion = !!cb; break; // .... ?>
- case 'attention': onAttention = cb; is_onAttention = !!cb; break; //
-
- };
- };
+ switch(name) {
+ case 'error': this.onError = cb || nullFunc; break;
+ case 'startNode': this.onStartNode = cb || nullFunc; break;
+ case 'endNode': this.onEndNode = cb || nullFunc; break;
+ case 'textNode': this.onTextNode = cb || nullFunc; break;
+ case 'cdata': this.onCDATA = cb || nullFunc; break;
- this.ns = function(root, ns) {
- if (!root || typeof root !== 'string' || !ns) {
- return;
- };
+ case 'comment': this.onComment = cb; this.is_onComment = !!cb; break;
+ case 'question': this.onQuestion = cb; this.is_onQuestion = !!cb; break; // .... ?>
+ case 'attention': this.onAttention = cb; this.is_onAttention = !!cb; break; //
+ };
+};
- var u, x = {}, ok, v, i;
+EasySAXParser.prototype.ns = function(root, ns) {
+ if (!root || typeof root !== 'string' || !ns) {
+ return;
+ };
- for(i in ns) {
- v = ns[i];
- if (typeof v === 'string') {
- if (root === v) ok = true;
- x[i] = v;
- };
- };
-
- if (ok) {
- isNamespace = true;
- default_xmlns = root;
- useNS = x;
- };
- };
+ var u, x = {}, ok, v, i;
- this.parse = function(xml) {
- if (typeof xml !== 'string') {
- return;
- };
+ for(i in ns) {
+ v = ns[i];
+ if (typeof v === 'string') {
+ if (root === v) ok = true;
+ x[i] = v;
+ };
+ };
- if (isNamespace) {
- nsmatrix = {xmlns: default_xmlns};
-
- parse(xml);
-
- nsmatrix = false;
-
- } else {
- parse(xml);
- };
-
- attr_res = true;
- };
-
- // -----------------------------------------------------
-
- var xharsQuot={constructor: false, hasOwnProperty: false, isPrototypeOf: false, propertyIsEnumerable: false, toLocaleString: false, toString: false, valueOf: false
- , quot: '"'
- , QUOT: '"'
- , amp: '&'
- , AMP: '&'
- , nbsp: '\u00A0'
- , apos: '\''
- , lt: '<'
- , LT: '<'
- , gt: '>'
- , GT: '>'
- , copy: '\u00A9'
- , laquo: '\u00AB'
- , raquo: '\u00BB'
- , reg: '\u00AE'
- , deg: '\u00B0'
- , plusmn: '\u00B1'
- , sup2: '\u00B2'
- , sup3: '\u00B3'
- , micro: '\u00B5'
- , para: '\u00B6'
- };
+ if (ok) {
+ this.isNamespace = true;
+ this.default_xmlns = root;
+ this.useNS = x;
+ };
+};
- function rpEntities(s, d, x, z) {
- if (z) {
- return xharsQuot[z] || '\x01';
- };
+EasySAXParser.prototype.parse = function(xml) {
+ if (typeof xml !== 'string') {
+ return;
+ };
- if (d) {
- return String.fromCharCode(d);
- };
+ if (this.isNamespace) {
+ this.nsmatrix = {xmlns: this.default_xmlns};
- return String.fromCharCode(parseInt(x, 16));
- };
+ parse(xml);
- function unEntities(s, i) {
- s = String(s);
- if (s.length > 3 && s.indexOf('&') !== -1) {
- if (s.indexOf('>') !== -1) s = s.replace(/>/g, '>');
- if (s.indexOf('<') !== -1) s = s.replace(/</g, '<');
- if (s.indexOf('"') !== -1) s = s.replace(/"/g, '"');
+ this.nsmatrix = false;
- if (s.indexOf('&') !== -1) {
- s = s.replace(/(\d+);|([0123456789abcdef]+);|&(\w+);/ig, rpEntities);
- };
- };
+ } else {
+ parse(xml);
+ };
- return s;
- };
+ this.attr_res = true;
+};
- var attr_string = ''; // строка атрибутов
- var attr_posstart = 0; //
- var attr_res; // закешированный результат разбора атрибутов , null - разбор не проводился, object - хеш атрибутов, true - нет атрибутов, false - невалидный xml
+// -----------------------------------------------------
+
+var xharsQuot={constructor: false, hasOwnProperty: false, isPrototypeOf: false, propertyIsEnumerable: false, toLocaleString: false, toString: false, valueOf: false
+ , quot: '"'
+ , QUOT: '"'
+ , amp: '&'
+ , AMP: '&'
+ , nbsp: '\u00A0'
+ , apos: '\''
+ , lt: '<'
+ , LT: '<'
+ , gt: '>'
+ , GT: '>'
+ , copy: '\u00A9'
+ , laquo: '\u00AB'
+ , raquo: '\u00BB'
+ , reg: '\u00AE'
+ , deg: '\u00B0'
+ , plusmn: '\u00B1'
+ , sup2: '\u00B2'
+ , sup3: '\u00B3'
+ , micro: '\u00B5'
+ , para: '\u00B6'
+};
+
+
+function rpEntities(s, d, x, z) {
+ if (z) {
+ return xharsQuot[z] || '\x01';
+ };
+
+ if (d) {
+ return String.fromCharCode(d);
+ };
+
+ return String.fromCharCode(parseInt(x, 16));
+};
+
+function unEntities(s, i) {
+ s = String(s);
+ if (s.length > 3 && s.indexOf('&') !== -1) {
+ if (s.indexOf('>') !== -1) s = s.replace(/>/g, '>');
+ if (s.indexOf('<') !== -1) s = s.replace(/</g, '<');
+ if (s.indexOf('"') !== -1) s = s.replace(/"/g, '"');
+
+ if (s.indexOf('&') !== -1) {
+ s = s.replace(/(\d+);|([0123456789abcdef]+);|&(\w+);/ig, rpEntities);
+ };
+ };
+
+ return s;
+};
+
+
+EasySAXParser.prototype.allowedAngularAttributeChars = function(w) {
+ if (!this.angularSyntax) {
+ return false;
+ } else {
+ return (
+ w === 40 || // (
+ w === 41 || // )
+ w === 91 || // [
+ w === 93 || // ]
+ w === 94 || // ^
+ w === 35 // #
+ );
+ }
+};
/*
парсит атрибуты по требованию. Важно! - функция не генерирует исключения.
@@ -210,499 +233,519 @@ function EasySAXParser() {
если есть атрибуты то возврашается обьект(хеш)
*/
- var RGX_ATTR_NAME = /[^\w:-]+/g;
-
- function getAttrs() {
- if (attr_res !== null) {
- return attr_res;
- };
-
- /*
- if (xxtest !== u && attr_string.indexOf(xxtest) === -1) {
- / *
- // для ускорения
- if (getAttrs('html').type == 'html') {
- ...
- };
- * /
- return true;
- };
- */
-
- var u
- , res = {}
- , s = attr_string
- , i = attr_posstart
- , l = s.length
- , attr_list = hasSurmiseNS ? [] : false
- , name, value = ''
- , ok = false
- , j, w, nn, n
- , hasNewMatrix
- , alias, newalias
- ;
-
-
- aa:
- for(; i < l; i++) {
- w = s.charCodeAt(i);
-
- if (w===32 || (w<14 && w > 8) ) { // \f\n\r\t\v
- continue
- };
-
- if (w < 65 || w >122 || (w>90 && w<97) ) { // ожидаем символ
- //console.log('error attr 1')
- return attr_res = false; // error. invalid char
- };
-
- for(j = i + 1; j < l; j++) { // проверяем все символы имени атрибута
- w = s.charCodeAt(j);
-
- if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w === 46 /* https://github.com/telerik/xPlatCore/issues/179 */) {
- continue;
- };
-
-
- if (w !== 61) { // "=" == 61
- //console.log('error 2');
- return attr_res = false; // error. invalid char
- };
-
- break;
- };
-
- name = s.substring(i, j);
- ok = true;
-
- if (name === 'xmlns:xmlns') {
- //console.log('error 6')
- return attr_res = false; // error. invalid name
- };
-
- w = s.charCodeAt(j+1);
-
- if (w === 34) { // '"'
- j = s.indexOf('"', i = j+2 );
-
- } else {
- if (w === 39) {
- j = s.indexOf('\'', i = j+2 );
-
- } else { // "'"
- //console.log('error 3')
- return attr_res = false; // error. invalid char
- };
- };
-
- if (j === -1) {
- //console.log('error 4')
- return attr_res = false; // error. invalid char
- };
-
-
- if (j+1 < l) {
- w = s.charCodeAt(j+1);
-
- if (w > 32 || w < 9 || (w<32 && w>13)) {
- // error. invalid char
- //console.log('error 5')
- return attr_res = false;
- };
- };
-
-
- value = s.substring(i, j);
- i = j + 1; // след. семвол уже проверен потому проверять нужно следуюший
-
- if (isNamespace) { //
- if (hasSurmiseNS) {
- // есть подозрение что в атрибутах присутствует xmlns
-
- if (newalias = name === 'xmlns' ? 'xmlns' : name.charCodeAt(0) === 120 && name.substr(0, 6) === 'xmlns:' && name.substr(6) ) {
- alias = useNS[unEntities(value)];
-
- if (alias) {
- if (nsmatrix[newalias] !== alias) {
- if (!hasNewMatrix) {
- hasNewMatrix = true;
- nn = {}; for (n in nsmatrix) nn[n] = nsmatrix[n];
- nsmatrix = nn;
- };
-
- nsmatrix[newalias] = alias;
- };
- } else {
- if (nsmatrix[newalias]) {
- if (!hasNewMatrix) {
- hasNewMatrix = true;
- nn = {}; for (n in nsmatrix) nn[n] = nsmatrix[n];
- nsmatrix = nn;
- };
-
- nsmatrix[newalias] = false;
- };
- };
-
- res[name] = value;
- continue;
- };
-
- attr_list.push(name, value);
- continue;
- };
-
- w = name.length;
- while(--w) {
- if (name.charCodeAt(w) === 58) { // ':'
- if (w = nsmatrix[name.substring(0, w)] ) {
- res[w + name.substr(w)] = value;
- };
- continue aa;
-
- // 'xml:base' ???
- };
- };
- };
-
- res[name] = value;
- };
-
-
- if (!ok) {
- return attr_res = true; // атрибутов нет, ошибок тоже нет
- };
-
-
- if (hasSurmiseNS) {
- bb:
-
- for (i = 0, l = attr_list.length; i < l; i++) {
- name = attr_list[i++];
-
- w = name.length;
- while(--w) { // name.indexOf(':')
- if (name.charCodeAt(w) === 58) { // ':'
- if (w = nsmatrix[name.substring(0, w)]) {
- res[w + name.substr(w)] = attr_list[i];
- };
- continue bb;
- break;
- };
- };
-
- res[name] = attr_list[i];
- };
- };
-
- return attr_res = res;
- };
-
-
- // xml - string
- function parse(xml) {
- var u
- , xml = String(xml)
- , nodestack = []
- , stacknsmatrix = []
- //, string_node
- , elem
- , tagend = false
- , tagstart = false
- , j = 0, i = 0
- , x, y, q, w
- , xmlns
- , stopIndex = 0
- , stop // используется при разборе "namespace" . если встретился неизвестное пространство то события не генерируются
- , _nsmatrix
- , ok
- ;
-
- function getStringNode() {
- return xml.substring(i, j+1)
- };
-
- while(j !== -1) {
- stop = stopIndex > 0;
-
- if (xml.charCodeAt(j) === 60) { // "<"
- i = j;
- } else {
- i = xml.indexOf('<', j);
- };
-
- if (i === -1) { // конец разбора
-
- if (nodestack.length) {
- onError('end file');
- return;
- };
-
- return;
- };
-
- if (j !== i && !stop) {
- ok = onTextNode(xml.substring(j, i), unEntities);
- if (ok === false) return;
- };
-
- w = xml.charCodeAt(i+1);
-
- if (w === 33) { // "!"
- w = xml.charCodeAt(i+2);
- if (w === 91 && xml.substr(i+3, 6) === 'CDATA[') { // 91 == "["
- j = xml.indexOf(']]>', i);
- if (j === -1) {
- onError('cdata');
- return;
- };
-
- //x = xml.substring(i+9, j);
- if (!stop) {
- ok = onCDATA(xml.substring(i+9, j), false);
- if (ok === false) return;
- };
-
-
- j += 3;
- continue;
- };
-
-
- if (w === 45 && xml.charCodeAt(i+3) === 45) { // 45 == "-"
- j = xml.indexOf('-->', i);
- if (j === -1) {
- onError('expected -->');
- return;
- };
-
-
- if (is_onComment && !stop) {
- ok = onComment(xml.substring(i+4, j), unEntities);
- if (ok === false) return;
- };
-
- j += 3;
- continue;
- };
-
- j = xml.indexOf('>', i+1);
- if (j === -1) {
- onError('expected ">"');
- return;
- };
-
- if (is_onAttention && !stop) {
- ok = onAttention(xml.substring(i, j+1), unEntities);
- if (ok === false) return;
- };
-
- j += 1;
- continue;
-
- } else {
- if (w === 63) { // "?"
- j = xml.indexOf('?>', i);
- if (j === -1) { // error
- onError('...?>');
- return;
- };
-
- if (is_onQuestion) {
- ok = onQuestion(xml.substring(i, j+2));
- if (ok === false) return;
- };
-
- j += 2;
- continue;
- };
- };
-
- j = xml.indexOf('>', i+1);
-
- if (j == -1) { // error
- onError('...>');
- return;
- };
-
- attr_res = true; // атрибутов нет
-
- //if (xml.charCodeAt(i+1) === 47) { // 8 && w<14) ) { // \f\n\r\t\v пробел
- continue;
- };
-
- onError('close tag');
- return;
- };
-
- } else {
- if (xml.charCodeAt(j-1) === 47) { // .../>
- x = elem = xml.substring(i+1, j-1);
-
- tagstart = true;
- tagend = true;
- } else {
- x = elem = xml.substring(i+1, j);
-
- tagstart = true;
- tagend = false;
- };
-
- if ( !(w > 96 && w < 123 || w > 64 && w <91) ) {
- onError('first char nodeName');
- return;
- };
-
- for(q = 1, y = x.length; q < y; q++) {
- w = x.charCodeAt(q);
-
- if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w === 46 /* https://github.com/telerik/xPlatCore/issues/179 */) {
- continue;
- };
-
- if (w===32 || (w<14 && w > 8)) { // \f\n\r\t\v пробел
- elem = x.substring(0, q)
- attr_res = null; // возможно есть атирибуты
- break;
- };
-
- onError('invalid nodeName');
- return;
- };
-
- if (!tagend) {
- nodestack.push(elem);
- };
- };
-
-
- if (isNamespace) {
- if (stop) {
- if (tagend) {
- if (!tagstart) {
- if (--stopIndex === 0) {
- nsmatrix = stacknsmatrix.pop();
- };
- };
-
- } else {
- stopIndex += 1;
- };
-
-
- j += 1;
- continue;
- };
-
- _nsmatrix = nsmatrix;
-
- if (!tagend) {
- stacknsmatrix.push(nsmatrix);
-
- if (attr_res !== true) {
- if (hasSurmiseNS = x.indexOf('xmlns', q) !== -1) {
- attr_string = x;
- attr_posstart = q;
-
- getAttrs();
-
- hasSurmiseNS = false;
- };
- };
- };
-
-
- w = elem.indexOf(':');
- if (w !== -1) {
- xmlns = nsmatrix[elem.substring(0, w)];
- elem = elem.substr(w+1);
-
-
- } else {
- xmlns = nsmatrix.xmlns;
- };
-
-
- if (!xmlns) {
- if (tagend) {
- if (tagstart) {
- nsmatrix = _nsmatrix;
- } else {
- nsmatrix = stacknsmatrix.pop();
- };
- } else {
- stopIndex = 1; // первый элемент для которого не определено пространство имен
- attr_res = true;
- };
-
- j += 1;
- continue;
- };
-
- elem = xmlns + ':' + elem;
- };
-
- //string_node = xml.substring(i, j+1); // текст ноды как есть
-
-
- if (tagstart) { // is_onStartNode
- attr_string = x;
- attr_posstart = q;
-
- ok = onStartNode(elem, getAttrs, unEntities, tagend
- , getStringNode
- );
-
- if (ok === false) {
- return;
- };
-
- attr_res = true;
- };
-
- if (tagend) {
- ok = onEndNode(elem, unEntities, tagstart
- , getStringNode
- );
-
- if (ok === false) {
- return;
- };
-
- if (isNamespace) {
- if (tagstart) {
- nsmatrix = _nsmatrix;
- } else {
- nsmatrix = stacknsmatrix.pop();
- };
- };
- };
-
- j += 1;
- };
- };
+EasySAXParser.prototype.getAttrs = function() {
+ if (this.attr_res !== null) {
+ return this.attr_res;
+ };
+
+ /*
+ if (xxtest !== u && attr_string.indexOf(xxtest) === -1) {
+ / *
+ // для ускорения
+ if (getAttrs('html').type == 'html') {
+ ...
+ };
+ * /
+ return true;
+ };
+ */
+
+ var u
+ , res = {}
+ , s = this.attr_string
+ , i = this.attr_posstart
+ , l = s.length
+ , attr_list = this.hasSurmiseNS ? [] : false
+ , name, value = ''
+ , ok = false
+ , noValueAttribute = false
+ , j, w, nn, n
+ , hasNewMatrix
+ , alias, newalias
+ ;
+
+ aa:
+ for(; i < l; i++) {
+ w = s.charCodeAt(i);
+
+ if (w===32 || (w<14 && w > 8) ) { // \f\n\r\t\v
+ continue
+ };
+
+ // Check for valid attribute start char
+ if ((w < 65 && !this.allowedAngularAttributeChars(w)) ||
+ w > 122 || (w > 90 && w < 97 && !this.allowedAngularAttributeChars(w)) ) { // ожидаем символ
+ return this.attr_res = false; // error. invalid char
+ };
+
+ for(j = i + 1; j < l; j++) { // проверяем все символы имени атрибута
+ w = s.charCodeAt(j);
+
+ if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w === 46 /* https://github.com/telerik/xPlatCore/issues/179 */) {
+ if (noValueAttribute) {
+ j--; //Started next attribute. Get back and break out of the loop.
+ break;
+ } else {
+ continue;
+ }
+ };
+
+ if (this.allowedAngularAttributeChars(w)) {
+ continue;
+ }
+
+ if (w === 32 || (w > 8 && w < 14) ) { // \f\n\r\t\v пробел
+ noValueAttribute = true;
+ continue;
+ } else if (w === 61) { // "=" == 61
+ noValueAttribute = false;
+ break;
+ } else {
+ //console.log('error 2');
+ if (!noValueAttribute)
+ return this.attr_res = false; // error. invalid char
+ };
+
+ break;
+ };
+
+ name = s.substring(i, j).trim();
+ ok = true;
+
+ if (name === 'xmlns:xmlns') {
+ //console.log('error 6')
+ return this.attr_res = false; // error. invalid name
+ };
+
+ w = s.charCodeAt(j+1);
+
+ while (w = s.charCodeAt(j+1)) {
+ if (w===32 || (w > 8 && w<14) ) { // \f\n\r\t\v пробел
+ j++;
+ } else {
+ break;
+ }
+ }
+
+ if (!noValueAttribute) {
+ if (w === 34) { // '"'
+ j = s.indexOf('"', i = j+2 );
+
+ } else {
+ if (w === 39) {
+ j = s.indexOf('\'', i = j+2 );
+
+ } else { // "'"
+ return this.attr_res = false; // error. invalid char
+ };
+ };
+ }
+
+ if (j === -1) {
+ //console.log('error 4')
+ return this.attr_res = false; // error. invalid char
+ };
+
+
+ if (j+1 < l && !noValueAttribute) {
+ w = s.charCodeAt(j+1);
+
+ if (w > 32 || w < 9 || (w < 32 && w > 13)) {
+ // error. invalid char
+ //console.log('error 5')
+ return this.attr_res = false;
+ };
+ };
+
+
+ if (noValueAttribute) {
+ value = '';
+ } else {
+ value = s.substring(i, j);
+ }
+
+ //i = j + 1; // след. семвол уже проверен потому проверять нужно следуюший
+ i = j; // след. семвол уже проверен потому проверять нужно следуюший
+
+ if (this.isNamespace) { //
+ if (this.hasSurmiseNS) {
+ // есть подозрение что в атрибутах присутствует xmlns
+
+ if (newalias = name === 'xmlns' ? 'xmlns' : name.charCodeAt(0) === 120 && name.substr(0, 6) === 'xmlns:' && name.substr(6) ) {
+ alias = this.useNS[unEntities(value)];
+
+ if (alias) {
+ if (this.nsmatrix[newalias] !== alias) {
+ if (!hasNewMatrix) {
+ hasNewMatrix = true;
+ nn = {}; for (n in this.nsmatrix) nn[n] = this.nsmatrix[n];
+ this.nsmatrix = nn;
+ };
+
+ this.nsmatrix[newalias] = alias;
+ };
+ } else {
+ if (this.nsmatrix[newalias]) {
+ if (!hasNewMatrix) {
+ hasNewMatrix = true;
+ nn = {}; for (n in this.nsmatrix) nn[n] = this.nsmatrix[n];
+ this.nsmatrix = nn;
+ };
+
+ this.nsmatrix[newalias] = false;
+ };
+ };
+
+ res[name] = value;
+ continue;
+ };
+
+ attr_list.push(name, value);
+ continue;
+ };
+
+ w = name.length;
+ while(--w) {
+ if (name.charCodeAt(w) === 58) { // ':'
+ if (w = this.nsmatrix[name.substring(0, w)] ) {
+ res[w + name.substr(w)] = value;
+ };
+ continue aa;
+
+ // 'xml:base' ???
+ };
+ };
+ };
+
+ res[name] = value;
+ noValueAttribute = false;
+ };
+
+
+ if (!ok) {
+ return this.attr_res = true; // атрибутов нет, ошибок тоже нет
+ };
+
+
+ if (this.hasSurmiseNS) {
+ bb:
+
+ for (i = 0, l = attr_list.length; i < l; i++) {
+ name = attr_list[i++];
+
+ w = name.length;
+ while(--w) { // name.indexOf(':')
+ if (name.charCodeAt(w) === 58) { // ':'
+ if (w = this.nsmatrix[name.substring(0, w)]) {
+ res[w + name.substr(w)] = attr_list[i];
+ };
+ continue bb;
+ break;
+ };
+ };
+
+ res[name] = attr_list[i];
+ };
+ };
+
+ return this.attr_res = res;
};
+// xml - string
+EasySAXParser.prototype.parse = function(xml) {
+ var u
+ , xml = String(xml)
+ , nodestack = []
+ , stacknsmatrix = []
+ //, string_node
+ , elem
+ , tagend = false
+ , tagstart = false
+ , j = 0, i = 0
+ , x, y, q, w
+ , xmlns
+ , stopIndex = 0
+ , stop // используется при разборе "namespace" . если встретился неизвестное пространство то события не генерируются
+ , _nsmatrix
+ , ok
+ ;
+
+ function getStringNode() {
+ return xml.substring(i, j+1)
+ };
+
+ while(j !== -1) {
+ stop = stopIndex > 0;
+
+ if (xml.charCodeAt(j) === 60) { // "<"
+ i = j;
+ } else {
+ i = xml.indexOf('<', j);
+ };
+
+ if (i === -1) { // конец разбора
+
+ if (nodestack.length) {
+ this.onError('end file');
+ return;
+ };
+
+ return;
+ };
+
+ if (j !== i && !stop) {
+ ok = this.onTextNode(xml.substring(j, i), unEntities);
+ if (ok === false) return;
+ };
+
+ w = xml.charCodeAt(i+1);
+
+ if (w === 33) { // "!"
+ w = xml.charCodeAt(i+2);
+ if (w === 91 && xml.substr(i+3, 6) === 'CDATA[') { // 91 == "["
+ j = xml.indexOf(']]>', i);
+ if (j === -1) {
+ this.onError('cdata');
+ return;
+ };
+
+ //x = xml.substring(i+9, j);
+ if (!stop) {
+ ok = this.onCDATA(xml.substring(i+9, j), false);
+ if (ok === false) return;
+ };
+
+ j += 3;
+ continue;
+ };
+
+ if (w === 45 && xml.charCodeAt(i+3) === 45) { // 45 == "-"
+ j = xml.indexOf('-->', i);
+ if (j === -1) {
+ this.onError('expected -->');
+ return;
+ };
+ if (this.is_onComment && !stop) {
+ ok = this.onComment(xml.substring(i+4, j), unEntities);
+ if (ok === false) return;
+ };
+ j += 3;
+ continue;
+ };
+
+ j = xml.indexOf('>', i+1);
+ if (j === -1) {
+ this.onError('expected ">"');
+ return;
+ };
+
+ if (this.is_onAttention && !stop) {
+ ok = this.onAttention(xml.substring(i, j+1), unEntities);
+ if (ok === false) return;
+ };
+
+ j += 1;
+ continue;
+
+ } else {
+ if (w === 63) { // "?"
+ j = xml.indexOf('?>', i);
+ if (j === -1) { // error
+ this.onError('...?>');
+ return;
+ };
+
+ if (this.is_onQuestion) {
+ ok = this.onQuestion(xml.substring(i, j+2));
+ if (ok === false) return;
+ };
+
+ j += 2;
+ continue;
+ };
+ };
+
+ j = xml.indexOf('>', i+1);
+
+ if (j == -1) { // error
+ this.onError('...>');
+ return;
+ };
+
+ this.attr_res = true; // атрибутов нет
+
+ //if (xml.charCodeAt(i+1) === 47) { // 8 && w<14) ) { // \f\n\r\t\v пробел
+ continue;
+ };
+
+ this.onError('close tag');
+ return;
+ };
+
+ } else {
+ if (xml.charCodeAt(j-1) === 47) { // .../>
+ x = elem = xml.substring(i+1, j-1);
+
+ tagstart = true;
+ tagend = true;
+ } else {
+ x = elem = xml.substring(i+1, j);
+
+ tagstart = true;
+ tagend = false;
+ };
+
+ if ( !(w > 96 && w < 123 || w > 64 && w <91) ) {
+ this.onError('first char nodeName');
+ return;
+ };
+
+ for(q = 1, y = x.length; q < y; q++) {
+ w = x.charCodeAt(q);
+
+ if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w === 46 /* https://github.com/telerik/xPlatCore/issues/179 */) {
+ continue;
+ };
+
+ if (w===32 || (w<14 && w > 8)) { // \f\n\r\t\v пробел
+ elem = x.substring(0, q)
+ this.attr_res = null; // возможно есть атирибуты
+ break;
+ };
+
+ this.onError('invalid nodeName');
+ return;
+ };
+
+ if (!tagend) {
+ nodestack.push(elem);
+ };
+ };
+
+
+ if (this.isNamespace) {
+ if (stop) {
+ if (tagend) {
+ if (!tagstart) {
+ if (--stopIndex === 0) {
+ this.nsmatrix = stacknsmatrix.pop();
+ };
+ };
+
+ } else {
+ stopIndex += 1;
+ };
+
+
+ j += 1;
+ continue;
+ };
+
+ _nsmatrix = this.nsmatrix;
+
+ if (!tagend) {
+ stacknsmatrix.push(this.nsmatrix);
+
+ if (this.attr_res !== true) {
+ if (this.hasSurmiseNS = x.indexOf('xmlns', q) !== -1) {
+ this.attr_string = x;
+ this.attr_posstart = q;
+
+ this.getAttrs();
+
+ this.hasSurmiseNS = false;
+ };
+ };
+ };
+
+
+ w = elem.indexOf(':');
+ if (w !== -1) {
+ xmlns = this.nsmatrix[elem.substring(0, w)];
+ elem = elem.substr(w+1);
+
+ } else {
+ xmlns = this.nsmatrix.xmlns;
+ };
+
+ if (!xmlns) {
+ if (tagend) {
+ if (tagstart) {
+ this.nsmatrix = _nsmatrix;
+ } else {
+ this.nsmatrix = stacknsmatrix.pop();
+ };
+ } else {
+ stopIndex = 1; // первый элемент для которого не определено пространство имен
+ this.attr_res = true;
+ };
+
+ j += 1;
+ continue;
+ };
+
+ elem = xmlns + ':' + elem;
+ };
+
+ //string_node = xml.substring(i, j+1); // текст ноды как есть
+
+ if (tagstart) { // is_onStartNode
+ this.attr_string = x;
+ this.attr_posstart = q;
+
+ var that = this;
+ ok = this.onStartNode(elem, function() { return that.getAttrs() }, unEntities, tagend
+ , getStringNode
+ );
+
+ if (ok === false) {
+ return;
+ };
+
+ this.attr_res = true;
+ };
+
+ if (tagend) {
+ ok = this.onEndNode(elem, unEntities, tagstart
+ , getStringNode
+ );
+
+ if (ok === false) {
+ return;
+ };
+
+ if (this.isNamespace) {
+ if (tagstart) {
+ this.nsmatrix = _nsmatrix;
+ } else {
+ this.nsmatrix = stacknsmatrix.pop();
+ };
+ };
+ };
+
+ j += 1;
+ };
+};
diff --git a/node-tests/definitions/chai.d.ts b/node-tests/definitions/chai.d.ts
new file mode 100644
index 000000000..fae15cd05
--- /dev/null
+++ b/node-tests/definitions/chai.d.ts
@@ -0,0 +1,285 @@
+/* tslint:disable */
+
+// Type definitions for chai 1.7.2
+// Project: http://chaijs.com/
+// Definitions by: Jed Hunsaker , Bart van der Schoor
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+declare module chai {
+ export class AssertionError {
+ constructor(message: string, _props?: any, ssf?: Function);
+ name: string;
+ message: string;
+ showDiff: boolean;
+ stack: string;
+ }
+
+ function expect(target: any, message?: string): Expect;
+
+ export var assert: Assert;
+ export var config: Config;
+
+ export interface Config {
+ includeStack: boolean;
+ }
+
+ // Provides a way to extend the internals of Chai
+ function use(fn: (chai: any, utils: any) => void): any;
+
+ interface ExpectStatic {
+ (target: any): Expect;
+ }
+
+ interface Assertions {
+ attr(name: string, value?: string): any;
+ css(name: string, value?: string): any;
+ data(name: string, value?: string): any;
+ class(className: string): any;
+ id(id: string): any;
+ html(html: string): any;
+ text(text: string): any;
+ value(value: string): any;
+ visible: any;
+ hidden: any;
+ selected: any;
+ checked: any;
+ disabled: any;
+ empty: any;
+ exist: any;
+ }
+
+ interface Expect extends LanguageChains, NumericComparison, TypeComparison, Assertions {
+ not: Expect;
+ deep: Deep;
+ a: TypeComparison;
+ an: TypeComparison;
+ include: Include;
+ contain: Include;
+ ok: Expect;
+ true: Expect;
+ false: Expect;
+ null: Expect;
+ undefined: Expect;
+ exist: Expect;
+ empty: Expect;
+ arguments: Expect;
+ Arguments: Expect;
+ equal: Equal;
+ equals: Equal;
+ eq: Equal;
+ eql: Equal;
+ eqls: Equal;
+ property: Property;
+ ownProperty: OwnProperty;
+ haveOwnProperty: OwnProperty;
+ length: Length;
+ lengthOf: Length;
+ match(RegularExpression: RegExp, message?: string): Expect;
+ string(string: string, message?: string): Expect;
+ keys: Keys;
+ key(string: string): Expect;
+ throw: Throw;
+ throws: Throw;
+ Throw: Throw;
+ respondTo(method: string, message?: string): Expect;
+ itself: Expect;
+ satisfy(matcher: Function, message?: string): Expect;
+ closeTo(expected: number, delta: number, message?: string): Expect;
+ members: Members;
+ }
+
+ interface LanguageChains {
+ to: Expect;
+ be: Expect;
+ been: Expect;
+ is: Expect;
+ that: Expect;
+ and: Expect;
+ have: Expect;
+ with: Expect;
+ at: Expect;
+ of: Expect;
+ same: Expect;
+ }
+
+ interface NumericComparison {
+ above: NumberComparer;
+ gt: NumberComparer;
+ greaterThan: NumberComparer;
+ least: NumberComparer;
+ gte: NumberComparer;
+ below: NumberComparer;
+ lt: NumberComparer;
+ lessThan: NumberComparer;
+ most: NumberComparer;
+ lte: NumberComparer;
+ within(start: number, finish: number, message?: string): Expect;
+ }
+
+ interface NumberComparer {
+ (value: number, message?: string): Expect;
+ }
+
+ interface TypeComparison {
+ (type: string, message?: string): Expect;
+ instanceof: InstanceOf;
+ instanceOf: InstanceOf;
+ }
+
+ interface InstanceOf {
+ (constructor: Object, message?: string): Expect;
+ }
+
+ interface Deep {
+ equal: Equal;
+ property: Property;
+ }
+
+ interface Equal {
+ (value: any, message?: string): Expect;
+ }
+
+ interface Property {
+ (name: string, value?: any, message?: string): Expect;
+ }
+
+ interface OwnProperty {
+ (name: string, message?: string): Expect;
+ }
+
+ interface Length extends LanguageChains, NumericComparison {
+ (length: number, message?: string): Expect;
+ }
+
+ interface Include {
+ (value: Object, message?: string): Expect;
+ (value: string, message?: string): Expect;
+ (value: number, message?: string): Expect;
+ keys: Keys;
+ members: Members;
+ }
+
+ interface Keys {
+ (...keys: string[]): Expect;
+ (keys: any[]): Expect;
+ }
+
+ interface Members {
+ (set: any[], message?: string): Expect;
+ }
+
+ interface Throw {
+ (): Expect;
+ (expected: string, message?: string): Expect;
+ (expected: RegExp, message?: string): Expect;
+ (constructor: Error, expected?: string, message?: string): Expect;
+ (constructor: Error, expected?: RegExp, message?: string): Expect;
+ (constructor: Function, expected?: string, message?: string): Expect;
+ (constructor: Function, expected?: RegExp, message?: string): Expect;
+ }
+
+ export interface Assert {
+ (express: any, msg?: string):void;
+
+ fail(actual?: any, expected?: any, msg?: string, operator?: string):void;
+
+ ok(val: any, msg?: string):void;
+ notOk(val: any, msg?: string):void;
+
+ equal(act: any, exp: any, msg?: string):void;
+ notEqual(act: any, exp: any, msg?: string):void;
+
+ strictEqual(act: any, exp: any, msg?: string):void;
+ notStrictEqual(act: any, exp: any, msg?: string):void;
+
+ deepEqual(act: any, exp: any, msg?: string):void;
+ notDeepEqual(act: any, exp: any, msg?: string):void;
+
+ isTrue(val: any, msg?: string):void;
+ isFalse(val: any, msg?: string):void;
+
+ isNull(val: any, msg?: string):void;
+ isNotNull(val: any, msg?: string):void;
+
+ isUndefined(val: any, msg?: string):void;
+ isDefined(val: any, msg?: string):void;
+
+ isFunction(val: any, msg?: string):void;
+ isNotFunction(val: any, msg?: string):void;
+
+ isObject(val: any, msg?: string):void;
+ isNotObject(val: any, msg?: string):void;
+
+ isArray(val: any, msg?: string):void;
+ isNotArray(val: any, msg?: string):void;
+
+ isString(val: any, msg?: string):void;
+ isNotString(val: any, msg?: string):void;
+
+ isNumber(val: any, msg?: string):void;
+ isNotNumber(val: any, msg?: string):void;
+
+ isBoolean(val: any, msg?: string):void;
+ isNotBoolean(val: any, msg?: string):void;
+
+ typeOf(val: any, type: string, msg?: string):void;
+ notTypeOf(val: any, type: string, msg?: string):void;
+
+ instanceOf(val: any, type: Function, msg?: string):void;
+ notInstanceOf(val: any, type: Function, msg?: string):void;
+
+ include(exp: string, inc: any, msg?: string):void;
+ include(exp: any[], inc: any, msg?: string):void;
+
+ notInclude(exp: string, inc: any, msg?: string):void;
+ notInclude(exp: any[], inc: any, msg?: string):void;
+
+ match(exp: any, re: RegExp, msg?: string):void;
+ notMatch(exp: any, re: RegExp, msg?: string):void;
+
+ property(obj: Object, prop: string, msg?: string):void;
+ notProperty(obj: Object, prop: string, msg?: string):void;
+ deepProperty(obj: Object, prop: string, msg?: string):void;
+ notDeepProperty(obj: Object, prop: string, msg?: string):void;
+
+ propertyVal(obj: Object, prop: string, val: any, msg?: string):void;
+ propertyNotVal(obj: Object, prop: string, val: any, msg?: string):void;
+
+ deepPropertyVal(obj: Object, prop: string, val: any, msg?: string):void;
+ deepPropertyNotVal(obj: Object, prop: string, val: any, msg?: string):void;
+
+ lengthOf(exp: any, len: number, msg?: string):void;
+ //alias frenzy
+ throw(fn: Function, msg?: string):void;
+ throw(fn: Function, regExp: RegExp):void;
+ throw(fn: Function, errType: Function, msg?: string):void;
+ throw(fn: Function, errType: Function, regExp: RegExp):void;
+
+ throws(fn: Function, msg?: string):void;
+ throws(fn: Function, regExp: RegExp):void;
+ throws(fn: Function, errType: Function, msg?: string):void;
+ throws(fn: Function, errType: Function, regExp: RegExp):void;
+
+ Throw(fn: Function, msg?: string):void;
+ Throw(fn: Function, regExp: RegExp):void;
+ Throw(fn: Function, errType: Function, msg?: string):void;
+ Throw(fn: Function, errType: Function, regExp: RegExp):void;
+
+ doesNotThrow(fn: Function, msg?: string):void;
+ doesNotThrow(fn: Function, regExp: RegExp):void;
+ doesNotThrow(fn: Function, errType: Function, msg?: string):void;
+ doesNotThrow(fn: Function, errType: Function, regExp: RegExp):void;
+
+ operator(val: any, operator: string, val2: any, msg?: string):void;
+ closeTo(act: number, exp: number, delta: number, msg?: string):void;
+
+ sameMembers(set1: any[], set2: any[], msg?: string):void;
+ includeMembers(set1: any[], set2: any[], msg?: string):void;
+
+ ifError(val: any, msg?: string):void;
+ }
+}
+
+declare module "chai" {
+export = chai;
+}
diff --git a/node-tests/definitions/mocha.d.ts b/node-tests/definitions/mocha.d.ts
new file mode 100644
index 000000000..7cd5abcae
--- /dev/null
+++ b/node-tests/definitions/mocha.d.ts
@@ -0,0 +1,112 @@
+/* tslint:disable */
+
+// 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;
diff --git a/node-tests/test-angular-xml.ts b/node-tests/test-angular-xml.ts
new file mode 100644
index 000000000..66e1ef92c
--- /dev/null
+++ b/node-tests/test-angular-xml.ts
@@ -0,0 +1,81 @@
+import {assert} from "chai";
+import xml = require('xml');
+
+describe("angular xml parser", () => {
+ let last_element = null;
+ let last_attrs = null;
+ let parser = null;
+
+ beforeEach(() => {
+ parser = new xml.XmlParser(function (event: xml.ParserEvent) {
+ switch (event.eventType) {
+ case xml.ParserEventType.StartElement:
+ last_element = event.elementName;
+ last_attrs = event.attributes;
+ break;
+ }
+ });
+ parser.angularSyntax = true;
+ });
+
+ it("parses [property] binding", () => {
+ parser.parse("");
+
+ assert.equal('TextField', last_element);
+ assert.equal(last_attrs['[text]'], 'somevar');
+ });
+
+ it("parses (event) binding", () => {
+ parser.parse("");
+
+ assert.equal('TextField', last_element);
+ assert.equal(last_attrs['(tap)'], 'onTap(blah)');
+ });
+
+ it("parses (^event) binding", () => {
+ parser.parse("");
+
+ assert.equal('TextField', last_element);
+ assert.equal(last_attrs['(^tap)'], 'onTap(blah)');
+ });
+
+ it("parses #id attribute", () => {
+ parser.parse("");
+
+ assert.equal('TextField', last_element);
+ assert.equal(last_attrs['#firstName'], '');
+ });
+
+ it("parses #id attribute followed by another", () => {
+ parser.parse("");
+
+ assert.equal('TextField', last_element);
+ assert.equal(last_attrs['#firstName'], '');
+ assert.equal(last_attrs['text'], 'Name');
+ });
+
+ it("detects equals without value", () => {
+ parser.parse("");
+
+ assert.isFalse(last_attrs);
+ });
+
+ it("detects no equals with quoted value", () => {
+ parser.parse("");
+
+ assert.isFalse(last_attrs);
+ });
+
+ it("detects unclosed tag after no value attribute", () => {
+ parser.parse(" {
+ parser.angularSyntax = false;
+ parser.parse("");
+
+ assert.isFalse(last_attrs);
+ });
+});
diff --git a/node-tests/test-xml.ts b/node-tests/test-xml.ts
new file mode 100644
index 000000000..713049dd1
--- /dev/null
+++ b/node-tests/test-xml.ts
@@ -0,0 +1,38 @@
+import {assert} from "chai";
+import xml = require('xml');
+
+describe("xml parser", () => {
+ let last_element = null;
+ let last_attrs = null;
+ let last_data = null;
+ let parser = null;
+
+ beforeEach(() => {
+ parser = new xml.XmlParser(function (event: xml.ParserEvent) {
+ switch (event.eventType) {
+ case xml.ParserEventType.StartElement:
+ last_element = event.elementName;
+ last_attrs = event.attributes;
+ break;
+ case xml.ParserEventType.Text:
+ last_data = event.data;
+ break;
+ }
+ });
+ });
+
+ it("handles whitespace around attribute =", () => {
+ let attributes = null;
+ let element = null;
+
+ parser.parse("");
+
+ assert.equal('TextField', last_element);
+ assert.equal('hello', last_attrs['text']);
+ });
+
+ it("resolves entities", () => {
+ parser.parse("<>"&'");
+ assert.equal("<>\"&'", last_data);
+ });
+});
diff --git a/package.json b/package.json
index c970e05ab..b7dd7c470 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,8 @@
},
"files": [
"**/*.*",
- "**/*"
+ "**/*",
+ "!node-tests/"
],
"license": "Apache-2.0",
"devDependencies": {
@@ -20,6 +21,10 @@
"grunt-shell": "1.1.2",
"grunt-ts": "4.0.1",
"grunt-tslint": "0.4.2",
+ "mocha": "2.2.5",
+ "grunt-simple-mocha": "0.4.0",
+ "grunt-env": "0.4.4",
+ "chai": "2.3.0",
"typescript": "1.5.0-beta"
}
}
diff --git a/xml/package.json b/xml/package.json
index f5006340c..c512836d5 100644
--- a/xml/package.json
+++ b/xml/package.json
@@ -1,2 +1,2 @@
-{ "name" : "xml",
- "main" : "xml.js" }
\ No newline at end of file
+{ "name" : "xml",
+ "main" : "xml.js" }
diff --git a/xml/xml.d.ts b/xml/xml.d.ts
index a71af02a0..728128793 100644
--- a/xml/xml.d.ts
+++ b/xml/xml.d.ts
@@ -86,7 +86,7 @@ declare module "xml" {
* @param onError The callback to execute when a parser error occurs. The 'error' parameter contains the error.
* @param processNamespaces Specifies whether namespaces should be processed.
*/
- constructor(onEvent: (event: ParserEvent) => void, onError?: (error: Error) => void, processNamespaces?: boolean);
+ constructor(onEvent: (event: ParserEvent) => void, onError?: (error: Error) => void, processNamespaces?: boolean, angularSyntax?: boolean);
/**
* Parses the supplied xml string.
@@ -94,4 +94,4 @@ declare module "xml" {
*/
parse(xmlString: string): void;
}
-}
\ No newline at end of file
+}
diff --git a/xml/xml.ts b/xml/xml.ts
index 2efd9efea..5acf9842c 100644
--- a/xml/xml.ts
+++ b/xml/xml.ts
@@ -148,6 +148,14 @@ export class XmlParser implements definition.XmlParser {
}
}
+ public get angularSyntax() : boolean {
+ return this._parser.angularSyntax;
+ }
+
+ public set angularSyntax(value: boolean) {
+ this._parser.angularSyntax = value;
+ }
+
public parse(xmlString: string): void {
if (this._processNamespaces) {
this._namespaceStack = [];
@@ -242,4 +250,4 @@ export class XmlParser implements definition.XmlParser {
return s;
}
-}
\ No newline at end of file
+}