moddle-xml
Advanced tools
| { | ||
| "name": "Base", | ||
| "uri": "http://base", | ||
| "prefix": "b", | ||
| "types": [ | ||
| { | ||
| "name": "Root", | ||
| "properties": [ | ||
| { "name": "own", "type": "Own" }, | ||
| { "name": "ownAttr", "type": "String", "isAttr": true }, | ||
| { "name": "generic", "type": "Element" }, | ||
| { "name": "genericCollection", "type": "Element", "isMany": true } | ||
| ] | ||
| }, | ||
| { | ||
| "name": "Own", | ||
| "properties": [ | ||
| { "name": "count", "type": "Integer", "isAttr": true } | ||
| ] | ||
| } | ||
| ] | ||
| } |
| { | ||
| "name": "Custom", | ||
| "uri": "http://custom", | ||
| "prefix": "c", | ||
| "types": [ | ||
| { | ||
| "name": "CustomRoot", | ||
| "extends": [ "b:Root" ], | ||
| "properties": [ | ||
| { "name": "customAttr", "type": "Integer", "isAttr": true }, | ||
| { "name": "generic", "type": "CustomGeneric", "redefines": "b:Root#generic" } | ||
| ] | ||
| }, | ||
| { | ||
| "name": "CustomGeneric", | ||
| "superClass": [ "Element" ], | ||
| "properties": [ | ||
| { "name": "count", "type": "Integer", "isAttr": true } | ||
| ] | ||
| }, | ||
| { | ||
| "name": "Property", | ||
| "superClass": [ "Element" ], | ||
| "properties": [ | ||
| { "name": "key", "type": "String", "isAttr": true }, | ||
| { "name": "value", "type": "String", "isAttr": true } | ||
| ] | ||
| } | ||
| ] | ||
| } |
+3
-1
| { | ||
| "node" : true, | ||
| "strict": true, | ||
| "unused": "vars", | ||
| "maxlen" : 120, | ||
| "unused": "vars", | ||
| "expr": true, | ||
| "globals": { | ||
@@ -6,0 +8,0 @@ "describe": false, |
+2
-0
@@ -0,1 +1,3 @@ | ||
| 'use strict'; | ||
| module.exports = function(grunt) { | ||
@@ -2,0 +4,0 @@ |
+4
-4
@@ -1,4 +0,4 @@ | ||
| 'use strict'; | ||
| module.exports.Reader = require('./lib/reader'); | ||
| module.exports.Writer = require('./lib/writer'); | ||
| module.exports = { | ||
| Reader: require('./lib/reader'), | ||
| Writer: require('./lib/writer') | ||
| }; |
+0
-1
| 'use strict'; | ||
| function capitalize(string) { | ||
@@ -5,0 +4,0 @@ return string.charAt(0).toUpperCase() + string.slice(1); |
+21
-19
| 'use strict'; | ||
| var sax = require('sax'), | ||
| _ = require('lodash'); | ||
| var reduce = require('lodash/collection/reduce'), | ||
| forEach = require('lodash/collection/forEach'), | ||
| find = require('lodash/collection/find'), | ||
| assign = require('lodash/object/assign'), | ||
| defer = require('lodash/function/defer'); | ||
| var common = require('./common'), | ||
| var Stack = require('tiny-stack'), | ||
| SaxParser = require('sax').parser, | ||
| Types = require('moddle/lib/types'), | ||
| parseNameNs = require('moddle/lib/ns').parseName, | ||
| common = require('./common'), | ||
| XSI_TYPE = common.XSI_TYPE, | ||
| XSI_URI = common.DEFAULT_NS_MAP.xsi, | ||
| Types = require('moddle').types, | ||
| Stack = require('tiny-stack'), | ||
| parseNameNs = require('moddle').ns.parseName, | ||
| aliasToName = common.aliasToName; | ||
| function parseNodeAttributes(node) { | ||
| var nodeAttrs = node.attributes; | ||
| return _.reduce(nodeAttrs, function(result, v, k) { | ||
| return reduce(nodeAttrs, function(result, v, k) { | ||
| var name, ns; | ||
@@ -78,3 +81,3 @@ | ||
| _.forEach(node.attributes, function(attr) { | ||
| forEach(node.attributes, function(attr) { | ||
@@ -91,2 +94,3 @@ // normalize xsi:type attributes because the | ||
| /** | ||
@@ -262,3 +266,3 @@ * A parse context. | ||
| _.forEach(attributes, function(value, name) { | ||
| forEach(attributes, function(value, name) { | ||
@@ -315,3 +319,3 @@ var prop = descriptor.propertiesByName[name]; | ||
| return _.extend({}, property, { effectiveType: elementType.$descriptor.name }); | ||
| return assign({}, property, { effectiveType: elementType.$descriptor.name }); | ||
| } | ||
@@ -332,3 +336,3 @@ } | ||
| // search for collection members later | ||
| property = _.find(descriptor.properties, function(p) { | ||
| property = find(descriptor.properties, function(p) { | ||
| return !p.isVirtual && !p.isReference && !p.isAttribute && elementType.hasType(p.type); | ||
@@ -338,7 +342,7 @@ }); | ||
| if (property) { | ||
| return _.extend({}, property, { effectiveType: elementType.$descriptor.name }); | ||
| return assign({}, property, { effectiveType: elementType.$descriptor.name }); | ||
| } | ||
| } else { | ||
| // parse unknown element (maybe extension) | ||
| property = _.find(descriptor.properties, function(p) { | ||
| property = find(descriptor.properties, function(p) { | ||
| return !p.isReference && !p.isAttribute && p.type === 'Element'; | ||
@@ -411,3 +415,3 @@ }); | ||
| if (propertyDesc.isReference) { | ||
| _.extend(newElement, { | ||
| assign(newElement, { | ||
| element: element | ||
@@ -476,4 +480,2 @@ }); | ||
| * | ||
| * @class XMLReader | ||
| * | ||
| * @param {Model} model used to read xml files | ||
@@ -490,3 +492,3 @@ */ | ||
| var parser = sax.parser(true, { xmlns: true, trim: true }), | ||
| var parser = new SaxParser(true, { xmlns: true, trim: true }), | ||
| stack = new Stack(); | ||
@@ -580,3 +582,3 @@ | ||
| // can kick in | ||
| _.defer(function() { | ||
| defer(function() { | ||
| var error; | ||
@@ -583,0 +585,0 @@ |
+47
-40
| 'use strict'; | ||
| var _ = require('lodash'); | ||
| var map = require('lodash/collection/map'), | ||
| forEach = require('lodash/collection/forEach'), | ||
| isString = require('lodash/lang/isString'), | ||
| filter = require('lodash/collection/filter'), | ||
| assign = require('lodash/object/assign'); | ||
| var Types = require('moddle').types, | ||
| var Types = require('moddle/lib/types'), | ||
| parseNameNs = require('moddle/lib/ns').parseName, | ||
| common = require('./common'), | ||
| parseNameNs = require('moddle').ns.parseName, | ||
| nameToAlias = common.nameToAlias; | ||
| var XML_PREAMBLE = '<?xml version="1.0" encoding="UTF-8"?>\n'; | ||
| var CDATA_ESCAPE = /[<>"&]+/; | ||
| var DEFAULT_NS_MAP = common.DEFAULT_NS_MAP, | ||
| var XML_PREAMBLE = '<?xml version="1.0" encoding="UTF-8"?>\n', | ||
| ESCAPE_CHARS = /(<|>|'|"|&|\n\r|\n)/g, | ||
| DEFAULT_NS_MAP = common.DEFAULT_NS_MAP, | ||
| XSI_TYPE = common.XSI_TYPE; | ||
@@ -19,3 +21,3 @@ | ||
| function nsName(ns) { | ||
| if (_.isString(ns)) { | ||
| if (isString(ns)) { | ||
| return ns; | ||
@@ -31,3 +33,3 @@ } else { | ||
| } else { | ||
| return _.extend({ localName: nameToAlias(descriptor.ns.localName, descriptor.$pkg) }, ns); | ||
| return assign({ localName: nameToAlias(descriptor.ns.localName, descriptor.$pkg) }, ns); | ||
| } | ||
@@ -37,3 +39,3 @@ } | ||
| function getPropertyNs(ns, descriptor) { | ||
| return _.extend({ localName: descriptor.ns.localName }, ns); | ||
| return assign({ localName: descriptor.ns.localName }, ns); | ||
| } | ||
@@ -44,3 +46,3 @@ | ||
| return _.filter(descriptor.properties, function(p) { | ||
| return filter(descriptor.properties, function(p) { | ||
| var name = p.name; | ||
@@ -64,2 +66,12 @@ | ||
| var ESCAPE_MAP = { | ||
| '\n': '10', | ||
| '\n\r': '10', | ||
| '"': '34', | ||
| '\'': '39', | ||
| '<': '60', | ||
| '>': '62', | ||
| '&': '38' | ||
| }; | ||
| /** | ||
@@ -72,13 +84,8 @@ * Escape a string attribute to not contain any bad values (line breaks, '"', ...) | ||
| function escapeAttr(str) { | ||
| var escapeMap = { | ||
| '\n': ' ', | ||
| '\n\r': ' ', | ||
| '"': '"' | ||
| }; | ||
| // ensure we are handling strings here | ||
| str = _.isString(str) ? str : '' + str; | ||
| str = isString(str) ? str : '' + str; | ||
| return str.replace(/(\n|\n\r|")/g, function(str) { | ||
| return escapeMap[str]; | ||
| return str.replace(ESCAPE_CHARS, function(str) { | ||
| return '&#' + ESCAPE_MAP[str] + ';'; | ||
| }); | ||
@@ -88,7 +95,7 @@ } | ||
| function filterAttributes(props) { | ||
| return _.filter(props, function(p) { return p.isAttr; }); | ||
| return filter(props, function(p) { return p.isAttr; }); | ||
| } | ||
| function filterContained(props) { | ||
| return _.filter(props, function(p) { return !p.isAttr; }); | ||
| return filter(props, function(p) { return !p.isAttr; }); | ||
| } | ||
@@ -132,3 +139,3 @@ | ||
| if (prop.type === 'String' && CDATA_ESCAPE.test(value)) { | ||
| if (prop.type === 'String' && ESCAPE_CHARS.test(value)) { | ||
| this.escape = true; | ||
@@ -208,3 +215,3 @@ } | ||
| if (_.isString(element)) { | ||
| if (isString(element)) { | ||
| ns = parseNameNs(element); | ||
@@ -222,3 +229,3 @@ } else | ||
| } else { | ||
| return _.extend({ localName: ns.localName }, effectiveNs); | ||
| return assign({ localName: ns.localName }, effectiveNs); | ||
| } | ||
@@ -233,3 +240,3 @@ }; | ||
| _.forEach(element, function(val, key) { | ||
| forEach(element, function(val, key) { | ||
@@ -240,3 +247,3 @@ if (key === '$body') { | ||
| if (key === '$children') { | ||
| _.forEach(val, function(child) { | ||
| forEach(val, function(child) { | ||
| body.push(new ElementSerializer(self).build(child)); | ||
@@ -267,3 +274,3 @@ }); | ||
| // and process them later | ||
| _.forEach(genericAttrs, function(value, name) { | ||
| forEach(genericAttrs, function(value, name) { | ||
| var nameNs = parseNameNs(name); | ||
@@ -288,3 +295,3 @@ | ||
| _.forEach(attributes, function(attr) { | ||
| forEach(attributes, function(attr) { | ||
@@ -311,3 +318,3 @@ // do not serialize xsi:type attribute | ||
| _.forEach(properties, function(p) { | ||
| forEach(properties, function(p) { | ||
| var value = element.get(p.name), | ||
@@ -327,3 +334,3 @@ isReference = p.isReference, | ||
| if (Types.isSimple(p.type)) { | ||
| _.forEach(value, function(v) { | ||
| forEach(value, function(v) { | ||
| body.push(new ValueSerializer(ns).build(p, v)); | ||
@@ -333,3 +340,3 @@ }); | ||
| if (isReference) { | ||
| _.forEach(value, function(v) { | ||
| forEach(value, function(v) { | ||
| body.push(new ReferenceSerializer(self, ns).build(v)); | ||
@@ -342,3 +349,3 @@ }); | ||
| _.forEach(value, function(v) { | ||
| forEach(value, function(v) { | ||
| var serializer; | ||
@@ -423,3 +430,3 @@ | ||
| _.forEach(properties, function(p) { | ||
| forEach(properties, function(p) { | ||
| self.logNamespaceUsed(p.ns); | ||
@@ -440,3 +447,3 @@ | ||
| if (_.isString(value)) { | ||
| if (isString(value)) { | ||
| value = escapeAttr(value); | ||
@@ -454,3 +461,3 @@ } | ||
| function collectNsAttrs() { | ||
| return _.collect(namespaces.used, function(ns) { | ||
| return map(namespaces.used, function(ns) { | ||
| var name = 'xmlns' + (ns.prefix ? ':' + ns.prefix : ''); | ||
@@ -465,3 +472,3 @@ return { name: name, value: ns.uri }; | ||
| _.forEach(attrs, function(a) { | ||
| forEach(attrs, function(a) { | ||
| writer | ||
@@ -493,3 +500,3 @@ .append(' ') | ||
| _.forEach(this.body, function(b) { | ||
| forEach(this.body, function(b) { | ||
| b.serializeTo(writer); | ||
@@ -593,7 +600,7 @@ }); | ||
| * | ||
| * @class XMLWriter | ||
| * @param {Object} options output options to pass into the writer | ||
| */ | ||
| function XMLWriter(options) { | ||
| options = _.extend({ format: false, preamble: true }, options || {}); | ||
| options = assign({ format: false, preamble: true }, options || {}); | ||
@@ -600,0 +607,0 @@ function toXML(tree, writer) { |
+3
-3
| { | ||
| "name": "moddle-xml", | ||
| "version": "0.5.1", | ||
| "version": "0.6.0", | ||
| "description": "XML import/export for documents described with moddle", | ||
@@ -53,4 +53,4 @@ "directories": { | ||
| "dependencies": { | ||
| "moddle": "~0.5.0", | ||
| "lodash": "~2.4.0", | ||
| "lodash": "^3.0.0", | ||
| "moddle": "^0.6.0", | ||
| "sax": "~0.6.0", | ||
@@ -57,0 +57,0 @@ "tiny-stack": "^0.1.0" |
+2
-2
@@ -5,3 +5,3 @@ 'use strict'; | ||
| var _ = require('lodash'); | ||
| var map = require('lodash/collection/map'); | ||
@@ -31,3 +31,3 @@ var Moddle = require('moddle'); | ||
| var packages = _.collect(packageNames, function(f) { | ||
| var packages = map(packageNames, function(f) { | ||
| var pkg = cache[f]; | ||
@@ -34,0 +34,0 @@ var file = base + f + '.json'; |
+209
-14
@@ -25,4 +25,6 @@ 'use strict'; | ||
| var xml = '<props:complexAttrs xmlns:props="http://properties"></props:complexAttrs>'; | ||
| // when | ||
| reader.fromXML('<props:complexAttrs xmlns:props="http://properties"></props:complexAttrs>', rootHandler, function(err, result, context) { | ||
| reader.fromXML(xml, rootHandler, function(err, result, context) { | ||
@@ -103,3 +105,4 @@ // then | ||
| var xml = '<props:complexAttrs xmlns:props="http://properties" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + | ||
| var xml = '<props:complexAttrs xmlns:props="http://properties" ' + | ||
| 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + | ||
| '<props:attrs xsi:type="props:SubAttributes" integerValue="10" />' + | ||
@@ -232,3 +235,4 @@ '</props:complexAttrs>'; | ||
| var xml = | ||
| '<dt:root xmlns:dt="http://datatypes" xmlns:do="http://datatypes2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + | ||
| '<dt:root xmlns:dt="http://datatypes" xmlns:do="http://datatypes2" ' + | ||
| 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + | ||
| '<dt:otherBounds xsi:type="dt:Rect" y="100" />' + | ||
@@ -268,3 +272,4 @@ '<dt:otherBounds xsi:type="do:Rect" x="200" />' + | ||
| var xml = | ||
| '<root xmlns="http://datatypes" xmlns:do="http://datatypes2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + | ||
| '<root xmlns="http://datatypes" xmlns:do="http://datatypes2" ' + | ||
| 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + | ||
| '<otherBounds xsi:type="Rect" y="100" />' + | ||
@@ -304,3 +309,4 @@ '<otherBounds xsi:type="do:Rect" x="200" />' + | ||
| var xml = | ||
| '<root xmlns="http://datatypes" xmlns:da="http://datatypes-aliased" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + | ||
| '<root xmlns="http://datatypes" xmlns:da="http://datatypes-aliased" ' + | ||
| 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + | ||
| '<otherBounds xsi:type="dt:Rect" y="100" />' + | ||
@@ -360,3 +366,3 @@ '<otherBounds xsi:type="da:tRect" z="200" />' + | ||
| it('with line breaks', function(done) { | ||
| it('with special characters', function(done) { | ||
@@ -367,4 +373,6 @@ // given | ||
| var xml = '<props:baseWithId xmlns:props="http://properties" id="<> &" />'; | ||
| // when | ||
| reader.fromXML('<props:baseWithId xmlns:props="http://properties" id="FOO BAR" />', rootHandler, function(err, result) { | ||
| reader.fromXML(xml, rootHandler, function(err, result) { | ||
@@ -374,3 +382,3 @@ // then | ||
| $type: 'props:BaseWithId', | ||
| id: 'FOO\nBAR' | ||
| id: '<>\n&' | ||
| }); | ||
@@ -393,4 +401,8 @@ | ||
| var xml = '<props:simpleBodyProperties xmlns:props="http://properties">' + | ||
| '<props:intValue>5</props:intValue>' + | ||
| '</props:simpleBodyProperties>'; | ||
| // when | ||
| reader.fromXML('<props:simpleBodyProperties xmlns:props="http://properties"><props:intValue>5</props:intValue></props:simpleBodyProperties>', rootHandler, function(err, result) { | ||
| reader.fromXML(xml, rootHandler, function(err, result) { | ||
@@ -414,4 +426,8 @@ // then | ||
| var xml = '<props:simpleBodyProperties xmlns:props="http://properties">' + | ||
| '<props:boolValue>false</props:boolValue>' + | ||
| '</props:simpleBodyProperties>'; | ||
| // when | ||
| reader.fromXML('<props:simpleBodyProperties xmlns:props="http://properties"><props:boolValue>false</props:boolValue></props:simpleBodyProperties>', rootHandler, function(err, result) { | ||
| reader.fromXML(xml, rootHandler, function(err, result) { | ||
@@ -435,4 +451,10 @@ // then | ||
| var xml = '<props:simpleBodyProperties xmlns:props="http://properties">' + | ||
| '<props:str>A</props:str>' + | ||
| '<props:str>B</props:str>' + | ||
| '<props:str>C</props:str>' + | ||
| '</props:simpleBodyProperties>'; | ||
| // when | ||
| reader.fromXML('<props:simpleBodyProperties xmlns:props="http://properties"><props:str>A</props:str><props:str>B</props:str><props:str>C</props:str></props:simpleBodyProperties>', rootHandler, function(err, result) { | ||
| reader.fromXML(xml, rootHandler, function(err, result) { | ||
@@ -459,4 +481,6 @@ // then | ||
| var xml = '<props:simpleBody xmlns:props="http://properties">textContent</props:simpleBody>'; | ||
| // when | ||
| reader.fromXML('<props:simpleBody xmlns:props="http://properties">textContent</props:simpleBody>', rootHandler, function(err, result) { | ||
| reader.fromXML(xml, rootHandler, function(err, result) { | ||
@@ -480,4 +504,8 @@ // then | ||
| var xml = '<props:simpleBody xmlns:props="http://properties">' + | ||
| '<![CDATA[<h2>HTML markup</h2>]]>' + | ||
| '</props:simpleBody>'; | ||
| // when | ||
| reader.fromXML('<props:simpleBody xmlns:props="http://properties"><![CDATA[<h2>HTML markup</h2>]]></props:simpleBody>', rootHandler, function(err, result) { | ||
| reader.fromXML(xml, rootHandler, function(err, result) { | ||
@@ -1233,4 +1261,9 @@ // then | ||
| var xml = '<props:complexAttrs xmlns:props="http://properties" ' + | ||
| 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + | ||
| '<props:attrs xsi:type="props:Attributes" integerValue="10" />' + | ||
| '</props:complexAttrs>'; | ||
| // when | ||
| reader.fromXML('<props:complexAttrs xmlns:props="http://properties" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><props:attrs xsi:type="props:Attributes" integerValue="10" /></props:complexAttrs>', rootHandler, function(err, result) { | ||
| reader.fromXML(xml, rootHandler, function(err, result) { | ||
@@ -1332,4 +1365,166 @@ if (err) { | ||
| }); | ||
| }); | ||
| describe('qualified extensions', function() { | ||
| var extensionModel = createModel([ 'extension/base', 'extension/custom' ]); | ||
| it('should read typed extension property', function(done) { | ||
| // given | ||
| var reader = new Reader(extensionModel); | ||
| var rootHandler = reader.handler('b:Root'); | ||
| var xml = | ||
| '<b:Root xmlns:b="http://base" xmlns:c="http://custom">' + | ||
| '<c:CustomGeneric count="10" />' + | ||
| '</b:Root>'; | ||
| // when | ||
| reader.fromXML(xml, rootHandler, function(err, result) { | ||
| if (err) { | ||
| return done(err); | ||
| } | ||
| expect(result).to.jsonEqual({ | ||
| $type: 'b:Root', | ||
| generic: { | ||
| $type: 'c:CustomGeneric', | ||
| count: 10 | ||
| } | ||
| }); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('should read typed extension attribute', function(done) { | ||
| // given | ||
| var reader = new Reader(extensionModel); | ||
| var rootHandler = reader.handler('b:Root'); | ||
| var xml = | ||
| '<b:Root xmlns:b="http://base" xmlns:c="http://custom" ' + | ||
| 'c:customAttr="666">' + | ||
| '</b:Root>'; | ||
| // when | ||
| reader.fromXML(xml, rootHandler, function(err, result) { | ||
| if (err) { | ||
| return done(err); | ||
| } | ||
| expect(result).to.jsonEqual({ | ||
| $type: 'b:Root', | ||
| customAttr: 666 | ||
| }); | ||
| done(); | ||
| }); | ||
| }); | ||
| it('should read generic collection', function(done) { | ||
| // given | ||
| var reader = new Reader(extensionModel); | ||
| var rootHandler = reader.handler('b:Root'); | ||
| var xml = | ||
| '<b:Root xmlns:b="http://base" xmlns:c="http://custom" ' + | ||
| 'xmlns:other="http://other">' + | ||
| '<c:Property key="foo" value="FOO" />' + | ||
| '<c:Property key="bar" value="BAR" />' + | ||
| '<other:Xyz>content</other:Xyz>' + | ||
| '</b:Root>'; | ||
| // when | ||
| reader.fromXML(xml, rootHandler, function(err, result) { | ||
| if (err) { | ||
| return done(err); | ||
| } | ||
| expect(result).to.jsonEqual({ | ||
| $type: 'b:Root', | ||
| genericCollection: [ | ||
| { | ||
| $type: 'c:Property', | ||
| key: 'foo', | ||
| value: 'FOO' | ||
| }, | ||
| { | ||
| $type: 'c:Property', | ||
| key: 'bar', | ||
| value: 'BAR' | ||
| }, | ||
| { | ||
| $type: 'other:Xyz', | ||
| $body: 'content' | ||
| } | ||
| ] | ||
| }); | ||
| done(); | ||
| }); | ||
| }); | ||
| describe('validation', function() { | ||
| it('should not fail parsing unknown attribute', function(done) { | ||
| // given | ||
| var reader = new Reader(extensionModel); | ||
| var rootHandler = reader.handler('b:Root'); | ||
| var xml = | ||
| '<b:Root xmlns:b="http://base" xmlns:c="http://custom" ' + | ||
| 'xmlns:other="http://other" c:unknownAttribute="XXX">' + | ||
| '</b:Root>'; | ||
| // when | ||
| reader.fromXML(xml, rootHandler, function(err, result) { | ||
| expect(err).not.to.exist; | ||
| done(); | ||
| }); | ||
| }); | ||
| it('should fail parsing unknown element', function(done) { | ||
| // given | ||
| var reader = new Reader(extensionModel); | ||
| var rootHandler = reader.handler('b:Root'); | ||
| var xml = | ||
| '<b:Root xmlns:b="http://base" xmlns:c="http://custom" ' + | ||
| 'xmlns:other="http://other">' + | ||
| '<c:NonExisting />' + | ||
| '</b:Root>'; | ||
| // when | ||
| reader.fromXML(xml, rootHandler, function(err, result) { | ||
| expect(err).to.exist; | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
| }); |
+204
-19
@@ -13,5 +13,2 @@ 'use strict'; | ||
| var model = createModel(['properties']); | ||
| var extendedModel = createModel(['properties', 'properties-extended']); | ||
| function createWriter(model, options) { | ||
@@ -24,2 +21,6 @@ return new Writer(_.extend({ preamble: false }, options || {})); | ||
| var model = createModel([ 'properties' ]); | ||
| var extendedModel = createModel([ 'properties', 'properties-extended' ]); | ||
| describe('base', function() { | ||
@@ -124,3 +125,5 @@ | ||
| expect(xml).to.eql( | ||
| '<dt:root xmlns:dt="http://datatypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:do="http://datatypes2">' + | ||
| '<dt:root xmlns:dt="http://datatypes" ' + | ||
| 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' + | ||
| 'xmlns:do="http://datatypes2">' + | ||
| '<dt:otherBounds xsi:type="dt:Rect" y="200" />' + | ||
@@ -149,3 +152,5 @@ '<dt:otherBounds xsi:type="do:Rect" x="100" />' + | ||
| expect(xml).to.eql( | ||
| '<dt:root xmlns:dt="http://datatypes" xmlns:da="http://datatypes-aliased" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + | ||
| '<dt:root xmlns:dt="http://datatypes" ' + | ||
| 'xmlns:da="http://datatypes-aliased" ' + | ||
| 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + | ||
| '<dt:otherBounds xsi:type="da:tRect" z="200" />' + | ||
@@ -243,2 +248,17 @@ '<dt:otherBounds xsi:type="dt:Rect" y="100" />' + | ||
| it('attribute, escaping special characters', function() { | ||
| // given | ||
| var writer = createWriter(model); | ||
| var complex = model.create('props:Complex', { id: '<>\n&' }); | ||
| // when | ||
| var xml = writer.toXML(complex); | ||
| // then | ||
| expect(xml).to.eql('<props:complex xmlns:props="http://properties" id="<> &" />'); | ||
| }); | ||
| it('write integer property', function() { | ||
@@ -256,4 +276,9 @@ | ||
| var expectedXml = | ||
| '<props:simpleBodyProperties xmlns:props="http://properties">' + | ||
| '<props:intValue>5</props:intValue>' + | ||
| '</props:simpleBodyProperties>'; | ||
| // then | ||
| expect(xml).to.eql('<props:simpleBodyProperties xmlns:props="http://properties"><props:intValue>5</props:intValue></props:simpleBodyProperties>'); | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
@@ -274,4 +299,9 @@ | ||
| var expectedXml = | ||
| '<props:simpleBodyProperties xmlns:props="http://properties">' + | ||
| '<props:boolValue>false</props:boolValue>' + | ||
| '</props:simpleBodyProperties>'; | ||
| // then | ||
| expect(xml).to.eql('<props:simpleBodyProperties xmlns:props="http://properties"><props:boolValue>false</props:boolValue></props:simpleBodyProperties>'); | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
@@ -292,4 +322,11 @@ | ||
| var expectedXml = | ||
| '<props:simpleBodyProperties xmlns:props="http://properties">' + | ||
| '<props:str>A</props:str>' + | ||
| '<props:str>B</props:str>' + | ||
| '<props:str>C</props:str>' + | ||
| '</props:simpleBodyProperties>'; | ||
| // then | ||
| expect(xml).to.eql('<props:simpleBodyProperties xmlns:props="http://properties"><props:str>A</props:str><props:str>B</props:str><props:str>C</props:str></props:simpleBodyProperties>'); | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
@@ -313,4 +350,9 @@ | ||
| var expectedXml = | ||
| '<props:embedding xmlns:props="http://properties">' + | ||
| '<props:complexCount id="ComplexCount_1" />' + | ||
| '</props:embedding>'; | ||
| // then | ||
| expect(xml).to.eql('<props:embedding xmlns:props="http://properties"><props:complexCount id="ComplexCount_1" /></props:embedding>'); | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
@@ -339,4 +381,11 @@ | ||
| var expectedXml = | ||
| '<props:root xmlns:props="http://properties">' + | ||
| '<props:attributes id="Attributes_1" />' + | ||
| '<props:simpleBody />' + | ||
| '<props:containedCollection />' + | ||
| '</props:root>'; | ||
| // then | ||
| expect(xml).to.eql('<props:root xmlns:props="http://properties"><props:attributes id="Attributes_1" /><props:simpleBody /><props:containedCollection /></props:root>'); | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
@@ -368,4 +417,12 @@ | ||
| var expectedXml = | ||
| '<ext:root xmlns:ext="http://extended" xmlns:props="http://properties">' + | ||
| '<props:attributes id="Attributes_1" />' + | ||
| '<props:attributes id="Attributes_2" />' + | ||
| '<ext:extendedComplex numCount="100" />' + | ||
| '<ext:base />' + | ||
| '</ext:root>'; | ||
| // then | ||
| expect(xml).to.eql('<ext:root xmlns:ext="http://extended" xmlns:props="http://properties"><props:attributes id="Attributes_1" /><props:attributes id="Attributes_2" /><ext:extendedComplex numCount="100" /><ext:base /></ext:root>'); | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
@@ -407,6 +464,33 @@ | ||
| var expectedXml = | ||
| '<props:simpleBody xmlns:props="http://properties">' + | ||
| '<![CDATA[<h2>HTML markup</h2>]]>' + | ||
| '</props:simpleBody>'; | ||
| // then | ||
| expect(xml).to.eql('<props:simpleBody xmlns:props="http://properties"><![CDATA[<h2>HTML markup</h2>]]></props:simpleBody>'); | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
| it('write body CDATA property with special chars', function() { | ||
| // given | ||
| var writer = createWriter(model); | ||
| var root = model.create('props:SimpleBody', { | ||
| body: '&\n<>' | ||
| }); | ||
| // when | ||
| var xml = writer.toXML(root); | ||
| var expectedXml = | ||
| '<props:simpleBody xmlns:props="http://properties">' + | ||
| '<![CDATA[&\n<>]]>' + | ||
| '</props:simpleBody>'; | ||
| // then | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
| }); | ||
@@ -479,4 +563,10 @@ | ||
| var expectedXml = | ||
| '<props:root xmlns:props="http://properties" ' + | ||
| 'xmlns:ext="http://extended">' + | ||
| '<ext:extendedComplex />' + | ||
| '</props:root>'; | ||
| // then | ||
| expect(xml).to.eql('<props:root xmlns:props="http://properties" xmlns:ext="http://extended"><ext:extendedComplex /></props:root>'); | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
@@ -528,3 +618,8 @@ | ||
| var root = extendedModel.create('props:Root', { xmlns: 'http://properties', 'xmlns:foo': 'http://fooo', id: 'Root', 'foo:bar': 'BAR' }); | ||
| var root = extendedModel.create('props:Root', { | ||
| xmlns: 'http://properties', | ||
| 'xmlns:foo': 'http://fooo', | ||
| id: 'Root', | ||
| 'foo:bar': 'BAR' | ||
| }); | ||
@@ -582,3 +677,5 @@ // when | ||
| var referencingCollection = model.create('props:ReferencingCollection', { references: [ complexCount, complexNesting ] }); | ||
| var referencingCollection = model.create('props:ReferencingCollection', { | ||
| references: [ complexCount, complexNesting ] | ||
| }); | ||
@@ -619,4 +716,9 @@ // when | ||
| var expectedXml = | ||
| '<e:root xmlns:e="http://extensions" ' + | ||
| 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' + | ||
| 'xsi:schemaLocation="http://fooo ./foo.xsd" />'; | ||
| // then | ||
| expect(xml).to.eql('<e:root xmlns:e="http://extensions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://fooo ./foo.xsd" />'); | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
@@ -756,4 +858,3 @@ | ||
| // then | ||
| expect(xml).to.eql( | ||
| var expectedXml = | ||
| '<e:root xmlns:e="http://extensions" xmlns:other="http://other">' + | ||
@@ -768,3 +869,6 @@ '<e:id>FOO</e:id>' + | ||
| '</other:nestedMeta>' + | ||
| '</e:root>'); | ||
| '</e:root>'; | ||
| // then | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
@@ -775,2 +879,83 @@ }); | ||
| describe('qualified extensions', function() { | ||
| var extensionModel = createModel([ 'extension/base', 'extension/custom' ]); | ||
| it('should write typed extension property', function() { | ||
| // given | ||
| var writer = createWriter(extensionModel); | ||
| var customGeneric = extensionModel.create('c:CustomGeneric', { count: 10 }); | ||
| var root = extensionModel.create('b:Root', { | ||
| generic: customGeneric | ||
| }); | ||
| // when | ||
| var xml = writer.toXML(root); | ||
| var expectedXml = | ||
| '<b:Root xmlns:b="http://base" xmlns:c="http://custom">' + | ||
| '<c:CustomGeneric count="10" />' + | ||
| '</b:Root>'; | ||
| // then | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
| it('should write typed extension attribute', function() { | ||
| // given | ||
| var writer = createWriter(extensionModel); | ||
| var root = extensionModel.create('b:Root', { customAttr: 666 }); | ||
| // when | ||
| var xml = writer.toXML(root); | ||
| var expectedXml = | ||
| '<b:Root xmlns:b="http://base" xmlns:c="http://custom" c:customAttr="666" />'; | ||
| // then | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
| it('should write generic collection', function() { | ||
| // given | ||
| var writer = createWriter(extensionModel); | ||
| var property1 = extensionModel.create('c:Property', { key: 'foo', value: 'FOO' }); | ||
| var property2 = extensionModel.create('c:Property', { key: 'bar', value: 'BAR' }); | ||
| var any = extensionModel.createAny('other:Xyz', 'http://other', { | ||
| $body: 'content' | ||
| }); | ||
| var root = extensionModel.create('b:Root', { | ||
| genericCollection: [ property1, property2, any ] | ||
| }); | ||
| var xml = writer.toXML(root); | ||
| var expectedXml = | ||
| '<b:Root xmlns:b="http://base" xmlns:c="http://custom" ' + | ||
| 'xmlns:other="http://other">' + | ||
| '<c:Property key="foo" value="FOO" />' + | ||
| '<c:Property key="bar" value="BAR" />' + | ||
| '<other:Xyz>content</other:Xyz>' + | ||
| '</b:Root>'; | ||
| // then | ||
| expect(xml).to.eql(expectedXml); | ||
| }); | ||
| }); | ||
| }); |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
108538
10.25%28
7.69%3100
12.08%4
33.33%+ Added
+ Added
- Removed
- Removed
Updated
Updated