moddle-xml
Advanced tools
Comparing version 11.0.0-exp.0 to 11.0.0-exp.1
@@ -14,14 +14,12 @@ import { forEach, assign, find, isString, findIndex, filter, has } from 'min-dash'; | ||
var XSI_TYPE = 'xsi:type'; | ||
var SERIALIZE_PROPERTY = 'property'; | ||
function serializeFormat(element) { | ||
function getSerialization(element) { | ||
return element.xml && element.xml.serialize; | ||
} | ||
function serializeAsType(element) { | ||
return serializeFormat(element) === XSI_TYPE; | ||
} | ||
function getSerializationType(element) { | ||
const type = getSerialization(element); | ||
function serializeAsProperty(element) { | ||
return serializeFormat(element) === 'property'; | ||
return type !== SERIALIZE_PROPERTY && (type || null); | ||
} | ||
@@ -42,2 +40,10 @@ | ||
/** | ||
* Un-prefix a potentially prefixed type name. | ||
* | ||
* @param {NsName} nameNs | ||
* @param {Object} [pkg] | ||
* | ||
* @return {string} | ||
*/ | ||
function prefixedToName(nameNs, pkg) { | ||
@@ -48,3 +54,3 @@ | ||
var typePrefix = pkg.xml && pkg.xml.typePrefix; | ||
var typePrefix = pkg && pkg.xml && pkg.xml.typePrefix; | ||
@@ -58,8 +64,15 @@ if (typePrefix && localName.indexOf(typePrefix) === 0) { | ||
function normalizeXsiTypeName(name, model) { | ||
function normalizeTypeName(name, nsMap, model) { | ||
var nameNs = parseNameNS(name); | ||
var pkg = model.getPackage(nameNs.prefix); | ||
// normalize against actual NS | ||
const nameNs = parseNameNS(name, nsMap.xmlns); | ||
return prefixedToName(nameNs, pkg); | ||
const normalizedName = `${ nsMap[nameNs.prefix] || nameNs.prefix }:${ nameNs.localName }`; | ||
const normalizedNameNs = parseNameNS(normalizedName); | ||
// determine actual type name, based on package-defined prefix | ||
var pkg = model.getPackage(normalizedNameNs.prefix); | ||
return prefixedToName(normalizedNameNs, pkg); | ||
} | ||
@@ -389,5 +402,3 @@ | ||
var propertyName = nameNs.name, | ||
property = descriptor.propertiesByName[propertyName], | ||
elementTypeName, | ||
elementType; | ||
property = descriptor.propertiesByName[propertyName]; | ||
@@ -398,14 +409,17 @@ // search for properties by name first | ||
if (serializeAsType(property)) { | ||
elementTypeName = node.attributes[XSI_TYPE]; | ||
const serializationType = getSerializationType(property); | ||
// xsi type is optional, if it does not exists the | ||
if (serializationType) { | ||
const elementTypeName = node.attributes[serializationType]; | ||
// type is optional, if it does not exists the | ||
// default type is assumed | ||
if (elementTypeName) { | ||
// convert the prefix used to the mapped form, but also | ||
// take possible type prefixes from XML | ||
// into account, i.e.: xsi:type="t{ActualType}" | ||
elementTypeName = normalizeXsiTypeName(elementTypeName, model); | ||
// into account, i.e.: xsi:type="t{ActualType}", | ||
const normalizedTypeName = normalizeTypeName(elementTypeName, node.ns, model); | ||
elementType = model.getType(elementTypeName); | ||
const elementType = model.getType(normalizedTypeName); | ||
@@ -425,4 +439,4 @@ return assign({}, property, { | ||
if (pkg) { | ||
elementTypeName = aliasToName(nameNs, pkg); | ||
elementType = model.getType(elementTypeName); | ||
const elementTypeName = aliasToName(nameNs, pkg); | ||
const elementType = model.getType(elementTypeName); | ||
@@ -849,5 +863,8 @@ // search for collection members later | ||
return uriMap; | ||
}, { | ||
'http://www.w3.org/XML/1998/namespace': 'xml' // add default xml ns | ||
}); | ||
}, Object.entries(DEFAULT_NS_MAP).reduce(function(map, [ prefix, url ]) { | ||
map[url] = prefix; | ||
return map; | ||
}, model.config && model.config.nsMap || {})); | ||
parser | ||
@@ -953,71 +970,78 @@ .ns(uriMap) | ||
var prefixMap = {}; | ||
var uriMap = {}; | ||
var used = {}; | ||
this.prefixMap = {}; | ||
this.uriMap = {}; | ||
this.used = {}; | ||
var wellknown = []; | ||
var custom = []; | ||
this.wellknown = []; | ||
this.custom = []; | ||
this.parent = parent; | ||
// API | ||
this.defaultPrefixMap = parent && parent.defaultPrefixMap || {}; | ||
} | ||
this.byUri = function(uri) { | ||
return uriMap[uri] || ( | ||
parent && parent.byUri(uri) | ||
); | ||
}; | ||
Namespaces.prototype.mapDefaultPrefixes = function(defaultPrefixMap) { | ||
this.defaultPrefixMap = defaultPrefixMap; | ||
}; | ||
this.add = function(ns, isWellknown) { | ||
Namespaces.prototype.defaultUriByPrefix = function(prefix) { | ||
return this.defaultPrefixMap[prefix]; | ||
}; | ||
uriMap[ns.uri] = ns; | ||
Namespaces.prototype.byUri = function(uri) { | ||
return this.uriMap[uri] || ( | ||
this.parent && this.parent.byUri(uri) | ||
); | ||
}; | ||
if (isWellknown) { | ||
wellknown.push(ns); | ||
} else { | ||
custom.push(ns); | ||
} | ||
Namespaces.prototype.add = function(ns, isWellknown) { | ||
this.mapPrefix(ns.prefix, ns.uri); | ||
}; | ||
this.uriMap[ns.uri] = ns; | ||
this.uriByPrefix = function(prefix) { | ||
return prefixMap[prefix || 'xmlns']; | ||
}; | ||
if (isWellknown) { | ||
this.wellknown.push(ns); | ||
} else { | ||
this.custom.push(ns); | ||
} | ||
this.mapPrefix = function(prefix, uri) { | ||
prefixMap[prefix || 'xmlns'] = uri; | ||
}; | ||
this.mapPrefix(ns.prefix, ns.uri); | ||
}; | ||
this.getNSKey = function(ns) { | ||
return (ns.prefix !== undefined) ? (ns.uri + '|' + ns.prefix) : ns.uri; | ||
}; | ||
Namespaces.prototype.uriByPrefix = function(prefix) { | ||
return this.prefixMap[prefix || 'xmlns'] || ( | ||
this.parent && this.parent.uriByPrefix(prefix) | ||
); | ||
}; | ||
this.logUsed = function(ns) { | ||
Namespaces.prototype.mapPrefix = function(prefix, uri) { | ||
this.prefixMap[prefix || 'xmlns'] = uri; | ||
}; | ||
var uri = ns.uri; | ||
var nsKey = this.getNSKey(ns); | ||
Namespaces.prototype.getNSKey = function(ns) { | ||
return (ns.prefix !== undefined) ? (ns.uri + '|' + ns.prefix) : ns.uri; | ||
}; | ||
used[nsKey] = this.byUri(uri); | ||
Namespaces.prototype.logUsed = function(ns) { | ||
// Inform parent recursively about the usage of this NS | ||
if (parent) { | ||
parent.logUsed(ns); | ||
} | ||
}; | ||
var uri = ns.uri; | ||
var nsKey = this.getNSKey(ns); | ||
this.getUsed = function(ns) { | ||
this.used[nsKey] = this.byUri(uri); | ||
function isUsed(ns) { | ||
var nsKey = self.getNSKey(ns); | ||
// Inform parent recursively about the usage of this NS | ||
if (this.parent) { | ||
this.parent.logUsed(ns); | ||
} | ||
}; | ||
return used[nsKey]; | ||
} | ||
Namespaces.prototype.getUsed = function(ns) { | ||
var self = this; | ||
var allNs = [].concat(this.wellknown, this.custom); | ||
var allNs = [].concat(wellknown, custom); | ||
return allNs.filter(ns => { | ||
var nsKey = this.getNSKey(ns); | ||
return allNs.filter(isUsed); | ||
}; | ||
return this.used[nsKey]; | ||
}); | ||
}; | ||
} | ||
@@ -1237,3 +1261,3 @@ function lower(string) { | ||
if (isGeneric) { | ||
otherAttrs = this.parseGeneric(element); | ||
otherAttrs = this.parseGenericNsAttributes(element); | ||
} else { | ||
@@ -1252,3 +1276,5 @@ otherAttrs = this.parseNsAttributes(element); | ||
if (!isGeneric) { | ||
if (isGeneric) { | ||
this.parseGenericContainments(element); | ||
} else { | ||
properties = getSerializableProperties(element); | ||
@@ -1316,31 +1342,25 @@ | ||
ElementSerializer.prototype.parseGeneric = function(element) { | ||
ElementSerializer.prototype.parseGenericNsAttributes = function(element) { | ||
var self = this, | ||
body = this.body; | ||
return Object.entries(element).filter( | ||
([ key, value ]) => !key.startsWith('$') && this.parseNsAttribute(element, key, value) | ||
).map( | ||
([ key, value ]) => ({ name: key, value: value }) | ||
); | ||
}; | ||
var attributes = []; | ||
ElementSerializer.prototype.parseGenericContainments = function(element) { | ||
var body = element.$body; | ||
forEach(element, function(val, key) { | ||
if (body) { | ||
this.body.push(new BodySerializer().build({ type: 'String' }, body)); | ||
} | ||
var nonNsAttr; | ||
var children = element.$children; | ||
if (key === '$body') { | ||
body.push(new BodySerializer().build({ type: 'String' }, val)); | ||
} else | ||
if (key === '$children') { | ||
forEach(val, function(child) { | ||
body.push(new ElementSerializer(self).build(child)); | ||
}); | ||
} else | ||
if (key.indexOf('$') !== 0) { | ||
nonNsAttr = self.parseNsAttribute(element, key, val); | ||
if (nonNsAttr) { | ||
attributes.push({ name: key, value: val }); | ||
} | ||
} | ||
}); | ||
return attributes; | ||
if (children) { | ||
forEach(children, child => { | ||
this.body.push(new ElementSerializer(this).build(child)); | ||
}); | ||
} | ||
}; | ||
@@ -1392,3 +1412,3 @@ | ||
*/ | ||
ElementSerializer.prototype.parseNsAttributes = function(element, attrs) { | ||
ElementSerializer.prototype.parseNsAttributes = function(element) { | ||
var self = this; | ||
@@ -1421,8 +1441,2 @@ | ||
// do not serialize xsi:type attribute | ||
// it is set manually based on the actual implementation type | ||
if (attr.name === XSI_TYPE) { | ||
return; | ||
} | ||
try { | ||
@@ -1473,4 +1487,3 @@ self.addAttribute(self.nsAttributeName(attr.name), attr.value); | ||
// rather than element name | ||
var asType = serializeAsType(p), | ||
asProperty = serializeAsProperty(p); | ||
var serialization = getSerialization(p); | ||
@@ -1480,7 +1493,8 @@ forEach(value, function(v) { | ||
if (asType) { | ||
serializer = new TypeSerializer(self, p); | ||
} else | ||
if (asProperty) { | ||
serializer = new ElementSerializer(self, p); | ||
if (serialization) { | ||
if (serialization === SERIALIZE_PROPERTY) { | ||
serializer = new ElementSerializer(self, p); | ||
} else { | ||
serializer = new TypeSerializer(self, p, serialization); | ||
} | ||
} else { | ||
@@ -1533,5 +1547,3 @@ serializer = new ElementSerializer(self); | ||
ElementSerializer.prototype.logNamespaceUsed = function(ns, local) { | ||
var element = this.element, | ||
model = element.$model, | ||
namespaces = this.getNamespaces(local); | ||
var namespaces = this.getNamespaces(local); | ||
@@ -1554,3 +1566,3 @@ // ns may be | ||
wellknownUri = DEFAULT_NS_MAP[prefix] || model && (model.getPackage(prefix) || {}).uri; | ||
wellknownUri = namespaces.defaultUriByPrefix(prefix); | ||
@@ -1565,2 +1577,7 @@ uri = uri || wellknownUri || namespaces.uriByPrefix(prefix); | ||
// register new default prefix <xmlns> in local scope | ||
if (!ns && !prefix) { | ||
ns = this.logNamespace({ uri }, wellknownUri === uri, true); | ||
} | ||
if (!ns) { | ||
@@ -1597,4 +1614,3 @@ newPrefix = prefix; | ||
value = value.id; | ||
} | ||
else { | ||
} else { | ||
var values = []; | ||
@@ -1703,4 +1719,6 @@ forEach(value, function(v) { | ||
*/ | ||
function TypeSerializer(parent, propertyDescriptor) { | ||
function TypeSerializer(parent, propertyDescriptor, serialization) { | ||
ElementSerializer.call(this, parent, propertyDescriptor); | ||
this.serialization = serialization; | ||
} | ||
@@ -1712,8 +1730,11 @@ | ||
// extracted attributes | ||
var attributes = ElementSerializer.prototype.parseNsAttributes.call(this, element); | ||
// extracted attributes with serialization attribute | ||
// <type=typeName> stripped; it may be later | ||
var attributes = ElementSerializer.prototype.parseNsAttributes.call(this, element).filter( | ||
attr => attr.name !== this.serialization | ||
); | ||
var descriptor = element.$descriptor; | ||
// only serialize xsi:type if necessary | ||
// only serialize <type=typeName> if necessary | ||
if (descriptor.name === this.propertyDescriptor.type) { | ||
@@ -1733,3 +1754,3 @@ return attributes; | ||
this.addAttribute( | ||
this.nsAttributeName(XSI_TYPE), | ||
this.nsAttributeName(this.serialization), | ||
(typeNs.prefix ? typeNs.prefix + ':' : '') + typePrefix + descriptor.ns.localName | ||
@@ -1807,4 +1828,10 @@ ); | ||
new ElementSerializer().build(tree).serializeTo(formatingWriter); | ||
var serializer = new ElementSerializer(); | ||
var model = tree.$model; | ||
serializer.getNamespaces().mapDefaultPrefixes(getDefaultPrefixMappings(model)); | ||
serializer.build(tree).serializeTo(formatingWriter); | ||
if (!writer) { | ||
@@ -1820,2 +1847,36 @@ return internalWriter.value; | ||
// helpers /////////// | ||
/** | ||
* @param {Moddle} model | ||
* | ||
* @return { Record<string, string> } map from prefix to URI | ||
*/ | ||
function getDefaultPrefixMappings(model) { | ||
const nsMap = model.config && model.config.nsMap || {}; | ||
const prefixMap = {}; | ||
// { prefix -> uri } | ||
for (const prefix in DEFAULT_NS_MAP) { | ||
prefixMap[prefix] = DEFAULT_NS_MAP[prefix]; | ||
} | ||
// { uri -> prefix } | ||
for (const uri in nsMap) { | ||
const prefix = nsMap[uri]; | ||
prefixMap[prefix] = uri; | ||
} | ||
for (const pkg of model.getPackages()) { | ||
prefixMap[pkg.prefix] = pkg.uri; | ||
} | ||
return prefixMap; | ||
} | ||
export { Reader, Writer }; | ||
//# sourceMappingURL=index.esm.js.map |
{ | ||
"name": "moddle-xml", | ||
"version": "11.0.0-exp.0", | ||
"version": "11.0.0-exp.1", | ||
"description": "XML import/export for documents described with moddle", | ||
@@ -44,2 +44,5 @@ "scripts": { | ||
], | ||
"files": [ | ||
"dist" | ||
], | ||
"license": "MIT", | ||
@@ -50,2 +53,3 @@ "sideEffects": false, | ||
"@rollup/plugin-node-resolve": "^14.1.0", | ||
"@rollup/plugin-terser": "^0.2.1", | ||
"chai": "^4.3.6", | ||
@@ -55,11 +59,13 @@ "eslint": "^8.24.0", | ||
"mocha": "^10.0.0", | ||
"moddle": "^7.0.0-exp.1", | ||
"npm-run-all": "^4.1.5", | ||
"rollup": "^2.79.1", | ||
"rollup-plugin-terser": "^7.0.2" | ||
"rollup": "^2.79.1" | ||
}, | ||
"dependencies": { | ||
"min-dash": "^4.0.0", | ||
"moddle": "^7.0.0-exp.0", | ||
"saxen": "^8.1.2" | ||
"saxen": "^9.0.0" | ||
}, | ||
"peerDependencies": { | ||
"moddle": ">= 6.2.0" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
373340
10
8
6003
+ Addedsaxen@9.0.0(transitive)
- Removedmoddle@^7.0.0-exp.0
- Removedsaxen@8.1.2(transitive)
Updatedsaxen@^9.0.0