Comparing version 1.0.0 to 1.1.0
@@ -1,1 +0,1 @@ | ||
!function(e,n){if("function"==typeof define&&define.amd)define(["exports"],n);else if("undefined"!=typeof exports)n(exports);else{var t={exports:{}};n(t.exports),e.jstoxml=t.exports}}(this,function(e){"use strict";function n(e){if(Array.isArray(e)){for(var n=0,t=Array(e.length);n<e.length;n++)t[n]=e[n];return t}return Array.from(e)}Object.defineProperty(e,"__esModule",{value:!0});var t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r=["_selfCloseTag","_attrs"],o=r.join("|"),a=new RegExp(o,"g"),i=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return e.repeat(n)},c=function(e){return Array.isArray(e)?"array":"object"===(void 0===e?"undefined":t(e))&&null!==e&&e._name?"special-object":e instanceof Date?"date":null===e?"null":void 0===e?"undefined":t(e)},s=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return Array.isArray(e)?e.map(function(e){var n=Object.keys(e)[0],t=e[n];return""+n+(!0===t?"":'="'+t+'"')}):Object.keys(e).map(function(n){return""+n+(!0===e[n]?"":'="'+e[n]+'"')})},u=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=s(e);return 0===n.length?"":" "+n.join(" ")},f=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},t="("+Object.keys(n).join("|")+")",r=new RegExp(t,"g");return String(e).replace(r,function(e,t){return n[t]||""})},l=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return Object.keys(e).map(function(n){return{_name:n,_content:e[n]}})},d=function(e){var n=c(e);return"string"===n||"number"===n||"boolean"===n||"date"===n||"special-object"===n},b=function(e){return!e.match("<")},v=function(e,n,t){var r="";return e.header&&t&&(r="boolean"==typeof e.header?'<?xml version="1.0" encoding="UTF-8"?>':e.header,e.indent&&(r+="\n")),r};e.toXML=function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},s=o.depth?o.depth:0,y=i(o.indent,s),p=c(t),g=d(t),m=0===s&&(g||!g&&o._isFirstItem),h="";switch(p){case"special-object":var _=t._name,j=t._content;if(null===j){h=_;break}if(_.match(a))break;var k=Object.assign({},o,{depth:s+1}),O=e(j,k),x=c(O),A=b(O),S=""+(o.indent&&!m?"\n":"")+y,I="undefined"===x||""===O,F="boolean"==typeof t._selfCloseTag?I&&t._selfCloseTag:I,T=F?"/":"",w="<"+_+u(t._attrs)+T+">",C=o.indent&&!A?"\n"+y:"";h=""+S+w+(F?"":""+O+C+"</"+_+">");break;case"object":var E=Object.keys(t);h=E.map(function(a,i){var s=Object.assign({},o,{_isFirstItem:0===i,_isLastItem:i+1===E.length}),u={_name:a};if("object"===c(t[a])&&(r.forEach(function(e){var n=t[a][e];void 0!==n&&(u[e]=n,delete t[a][e])}),void 0!==t[a]._content&&Object.keys(t[a]).length>1)){var f=Object.assign({},t[a]);delete f._content,u._content=[].concat(n(l(f)),[t[a]._content])}return void 0===u._content&&(u._content=t[a]),e(u,s)},o).join("");break;case"function":var L=t(o);h=e(L,o);break;case"array":h=t.map(function(n,r){var a=Object.assign({},o,{_isFirstItem:0===r,_isLastItem:r+1===t.length});return e(n,a)}).join("");break;case"number":case"string":case"boolean":case"date":case"null":default:h=f(t,o.filter)}return h=""+v(o,0,m)+h}}); | ||
!function(e,t){if("function"==typeof define&&define.amd)define(["exports"],t);else if("undefined"!=typeof exports)t(exports);else{var n={exports:{}};t(n.exports),e.jstoxml=n.exports}}(this,function(e){"use strict";function t(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}Object.defineProperty(e,"__esModule",{value:!0});var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r=["_selfCloseTag","_attrs"],o=r.join("|"),a=new RegExp(o,"g"),i=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return e.repeat(t)},c=function(e){return Array.isArray(e)?"array":"object"===(void 0===e?"undefined":n(e))&&null!==e&&e._name?"special-object":e instanceof Date?"date":null===e?"null":void 0===e?"undefined":n(e)},s=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=arguments[1];return Array.isArray(e)?e.map(function(e){var n=Object.keys(e)[0],r=e[n],o=t?f(r,t):r;return""+n+(!0===o?"":'="'+o+'"')}):Object.keys(e).map(function(n){var r=t?f(e[n],t):e[n];return""+n+(!0===e[n]?"":'="'+r+'"')})},u=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=arguments[1],n=s(e,t);return 0===n.length?"":" "+n.join(" ")},f=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n="("+Object.keys(t).join("|")+")",r=new RegExp(n,"g");return String(e).replace(r,function(e,n){return t[n]||""})},l=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return Object.keys(e).map(function(t){return{_name:t,_content:e[t]}})},d=function(e){var t=c(e);return"string"===t||"number"===t||"boolean"===t||"date"===t||"special-object"===t},b=function(e){return!e.match("<")},v=function(e,t,n){var r="";return e.header&&n&&(r="boolean"==typeof e.header?'<?xml version="1.0" encoding="UTF-8"?>':e.header,e.indent&&(r+="\n")),r};e.toXML=function e(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},s=o.depth?o.depth:0,y=i(o.indent,s),p=c(n),g=d(n),m=0===s&&(g||!g&&o._isFirstItem),h="";switch(p){case"special-object":var _=n._name,j=n._content;if(null===j){h=_;break}if(_.match(a))break;var k=Object.assign({},o,{depth:s+1}),O=e(j,k),x=c(O),A=b(O),S=""+(o.indent&&!m?"\n":"")+y,F="undefined"===x||""===O,I="boolean"==typeof n._selfCloseTag?F&&n._selfCloseTag:F,T=I?"/":"",w="<"+_+u(n._attrs,o.attributesFilter)+T+">",C=o.indent&&!A?"\n"+y:"";h=""+S+w+(I?"":""+O+C+"</"+_+">");break;case"object":var E=Object.keys(n);h=E.map(function(a,i){var s=Object.assign({},o,{_isFirstItem:0===i,_isLastItem:i+1===E.length}),u={_name:a};if("object"===c(n[a])&&(r.forEach(function(e){var t=n[a][e];void 0!==t&&(u[e]=t,delete n[a][e])}),void 0!==n[a]._content&&Object.keys(n[a]).length>1)){var f=Object.assign({},n[a]);delete f._content,u._content=[].concat(t(l(f)),[n[a]._content])}return void 0===u._content&&(u._content=n[a]),e(u,s)},o).join("");break;case"function":var L=n(o);h=e(L,o);break;case"array":h=n.map(function(t,r){var a=Object.assign({},o,{_isFirstItem:0===r,_isLastItem:r+1===n.length});return e(t,a)}).join("");break;case"number":case"string":case"boolean":case"date":case"null":default:h=f(n,o.filter)}return h=""+v(o,0,m)+h}}); |
@@ -80,2 +80,3 @@ (function (global, factory) { | ||
var attributes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
var filter = arguments[1]; | ||
@@ -91,3 +92,4 @@ var isArray = Array.isArray(attributes); | ||
var valStr = val === true ? '' : '="' + val + '"'; | ||
var filteredVal = filter ? filterStr(val, filter) : val; | ||
var valStr = filteredVal === true ? '' : '="' + filteredVal + '"'; | ||
return '' + key + valStr; | ||
@@ -101,3 +103,4 @@ }); | ||
// For boolean true, simply output the key. | ||
var valStr = attributes[key] === true ? '' : '="' + attributes[key] + '"'; | ||
var filteredVal = filter ? filterStr(attributes[key], filter) : attributes[key]; | ||
var valStr = attributes[key] === true ? '' : '="' + filteredVal + '"'; | ||
@@ -119,4 +122,5 @@ return '' + key + valStr; | ||
var attributes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
var filter = arguments[1]; | ||
var keyVals = getAttributeKeyVals(attributes); | ||
var keyVals = getAttributeKeyVals(attributes, filter); | ||
if (keyVals.length === 0) return ''; | ||
@@ -259,3 +263,3 @@ | ||
var selfCloseStr = shouldSelfClose ? '/' : ''; | ||
var attributesString = formatAttributes(obj._attrs); | ||
var attributesString = formatAttributes(obj._attrs, config.attributesFilter); | ||
var tag = '<' + _name + attributesString + selfCloseStr + '>'; | ||
@@ -262,0 +266,0 @@ |
@@ -32,2 +32,16 @@ const privateVars = ['_selfCloseTag', '_attrs']; | ||
/** | ||
* Replaces matching values in a string with a new value. | ||
* Example: | ||
* filterStr('foo&bar', { '&': '&' }); | ||
*/ | ||
const filterStr = (inputStr = '', filter = {}) => { | ||
const searches = Object.keys(filter); | ||
const joinedSearches = searches.join('|'); | ||
const regexpStr = `(${joinedSearches})`; | ||
const regexp = new RegExp(regexpStr, 'g'); | ||
return String(inputStr).replace(regexp, (str, entity) => filter[entity] || ''); | ||
}; | ||
/** | ||
* Maps an object or array of arribute keyval pairs to a string. | ||
@@ -38,3 +52,3 @@ * Examples: | ||
*/ | ||
const getAttributeKeyVals = (attributes = {}) => { | ||
const getAttributeKeyVals = (attributes = {}, filter) => { | ||
const isArray = Array.isArray(attributes); | ||
@@ -49,3 +63,4 @@ | ||
const valStr = (val === true) ? '' : `="${val}"`; | ||
const filteredVal = (filter) ? filterStr(val, filter) : val; | ||
const valStr = (filteredVal === true) ? '' : `="${filteredVal}"`; | ||
return `${key}${valStr}`; | ||
@@ -59,3 +74,4 @@ }); | ||
// For boolean true, simply output the key. | ||
const valStr = (attributes[key] === true) ? '' : `="${attributes[key]}"`; | ||
const filteredVal = (filter) ? filterStr(attributes[key], filter) : attributes[key]; | ||
const valStr = (attributes[key] === true) ? '' : `="${filteredVal}"`; | ||
@@ -75,4 +91,4 @@ return `${key}${valStr}`; | ||
*/ | ||
const formatAttributes = (attributes = {}) => { | ||
const keyVals = getAttributeKeyVals(attributes); | ||
const formatAttributes = (attributes = {}, filter) => { | ||
const keyVals = getAttributeKeyVals(attributes, filter); | ||
if (keyVals.length === 0) return ''; | ||
@@ -85,16 +101,2 @@ | ||
/** | ||
* Replaces matching values in a string with a new value. | ||
* Example: | ||
* filterStr('foo&bar', { '&': '&' }); | ||
*/ | ||
const filterStr = (inputStr = '', filter = {}) => { | ||
const searches = Object.keys(filter); | ||
const joinedSearches = searches.join('|'); | ||
const regexpStr = `(${joinedSearches})`; | ||
const regexp = new RegExp(regexpStr, 'g'); | ||
return String(inputStr).replace(regexp, (str, entity) => filter[entity] || ''); | ||
}; | ||
/** | ||
* Converts an object to a jstoxml array. | ||
@@ -201,3 +203,3 @@ * Example: | ||
const selfCloseStr = (shouldSelfClose) ? '/' : ''; | ||
const attributesString = formatAttributes(obj._attrs); | ||
const attributesString = formatAttributes(obj._attrs, config.attributesFilter); | ||
const tag = `<${_name}${attributesString}${selfCloseStr}>`; | ||
@@ -204,0 +206,0 @@ |
{ | ||
"name": "jstoxml", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "Converts JavaScript/JSON to XML (for RSS, Podcasts, AMP, etc.)", | ||
@@ -22,4 +22,3 @@ "homepage": "http://github.com/davidcalhoun/jstoxml", | ||
"postinstall": "./install.sh", | ||
"test": "./node_modules/mocha/bin/mocha test.js", | ||
"test-dist": "./node_modules/mocha/bin/mocha dist/jstoxml.js" | ||
"test": "./install.sh && ./node_modules/mocha/bin/mocha test.js" | ||
}, | ||
@@ -26,0 +25,0 @@ "dependencies": {}, |
@@ -12,7 +12,2 @@ jstoxml | ||
### Features | ||
* supports a variety of inputs: objects, arrays, strings, | ||
* tabbed output (optional) | ||
* custom filters (```&``` -> ```&```, etc) (optional) | ||
### Installation | ||
@@ -22,36 +17,9 @@ * npm install jstoxml | ||
### Version 1.0.0 | ||
-Complete rewrite! The code should now be easier to understand and maintain. | ||
-now supports emoji/UTF8 tag attributes (needed for AMP pages - e.g. `<html ⚡ lang="en">`) (see example 14) | ||
-now supports duplicate attribute key names (see example 15) | ||
-Fixed: functions returning objects now have now that output passed through toXML for XML conversion | ||
-Fixed: empty text strings now properly output self-closing tags | ||
-Migrated tests to mocha | ||
* Complete rewrite! The code should now be easier to understand and maintain. | ||
* now supports emoji/UTF8 tag attributes (needed for AMP pages - e.g. `<html ⚡ lang="en">`) (see example 14) | ||
* now supports duplicate attribute key names (see example 15) | ||
* Fixed: functions returning objects now have now that output passed through toXML for XML conversion | ||
* Fixed: empty text strings now properly output self-closing tags | ||
* Migrated tests to mocha | ||
### Version 0.2.1 | ||
* IMPORTANT: empty text strings will now output as empty XML tags (NOT text content), which makes more sense and is more intuitive (see issue #3). To output text content, set the value to null instead (see Example 5 below). | ||
For instance: | ||
``` | ||
jstoxml.toXML({ | ||
a: '1', | ||
foo: '', | ||
b: '2' | ||
}); | ||
// Output: <a>1</a><foo></foo><b>2</b> | ||
``` | ||
``` | ||
jstoxml.toXML({ | ||
a: '1', | ||
foo: null, | ||
b: '2' | ||
}); | ||
// Output: <a>1</a>foo<b>2</b> | ||
``` | ||
### Version 0.1.0 | ||
* Added support for custom filters (for XML, UTF-8 entities, or whatever you need it for) | ||
* Changed to a single options object, passed as the second parameter. This will break older versions that use the XML header or indentation! They will need to be updated (see the examples below). | ||
### Examples | ||
@@ -64,10 +32,2 @@ First you'll want to require jstoxml in your script, and assign the result to the namespace variable you want to use (in this case jstoxml): | ||
#### Interface | ||
jstoxml has a very simple interface: jstoxml.toXML(input, addHeader [Boolean or String], indent [String]); | ||
* input: accepts objects, arrays, strings, and even functions | ||
* addHeader (optional): pass in true to include the default XML header (<?xml version="1.0" encoding="UTF-8"?>). For a custom XML header, pass in a string. | ||
* indent (optional): string which is used as an indent (i.e. ' ') | ||
#### Example 1: Simple object | ||
@@ -479,3 +439,27 @@ ```javascript | ||
#### Example 11b: Custom filter for XML attributes | ||
```javascript | ||
jstoxml.toXML({ | ||
_name: 'foo', | ||
_attrs: { a: '<"\'&"foo>' } | ||
}, | ||
{ | ||
attributesFilter: { | ||
'<': '<', | ||
'>': '>', | ||
'"': '"', | ||
'\'': ''', | ||
'&': '&' | ||
} | ||
}); | ||
``` | ||
Output: | ||
``` | ||
<foo a="<"'&"foo>"/> | ||
``` | ||
#### Example 12: Avoiding self-closing tags | ||
@@ -548,3 +532,3 @@ If for some reason you want to avoid self-closing tags, you can pass in a special config option `_selfCloseTag`: | ||
``` | ||
<html lang="sen" lang="klingon"/> | ||
<html lang="en" lang="klingon"/> | ||
``` | ||
@@ -551,0 +535,0 @@ |
45
test.js
@@ -403,3 +403,3 @@ const jstoxml = require('./dist/jstoxml'); | ||
describe('filtering', () => { | ||
it('entities', () => { | ||
it('values', () => { | ||
const val = { | ||
@@ -424,2 +424,21 @@ foo: '<a>', | ||
}); | ||
it('attributes', () => { | ||
const val = { | ||
_name: 'foo', | ||
_attrs: { a: '<"\'&"foo>' } | ||
}; | ||
const config = { | ||
attributesFilter: { | ||
'<': '<', | ||
'>': '>', | ||
'"': '"', | ||
'\'': ''', | ||
'&': '&' | ||
} | ||
}; | ||
const result = jstoxml.toXML(val, config); | ||
const expectedResult = '<foo a="<"'&"foo>"/>'; | ||
assert.equal(result, expectedResult); | ||
}); | ||
}); | ||
@@ -842,2 +861,26 @@ | ||
it('11b attributes filter', () => { | ||
const val = { | ||
_name: 'foo', | ||
_content: 'bar', | ||
_attrs: { | ||
a: 'http://example.com/?test=\'1\'&foo=<bar>&whee="sha"', | ||
b: 'http://example2.com/?test=\'2\'&md=<5>&sum="sha"' | ||
} | ||
}; | ||
const config = { | ||
attributesFilter: { | ||
'<': '<', | ||
'>': '>', | ||
'"': '"', | ||
'\'': ''', | ||
'&': '&' | ||
} | ||
}; | ||
const result = jstoxml.toXML(val, config); | ||
const expectedResult = | ||
'<foo a="http://example.com/?test='1'&foo=<bar>&whee="sha"" b="http://example2.com/?test='2'&md=<5>&sum="sha"">bar</foo>'; | ||
assert.equal(result, expectedResult); | ||
}); | ||
it('12 avoiding self closing tags', () => { | ||
@@ -844,0 +887,0 @@ const val = [ |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
63943
1437
0
538