Comparing version 1.2.2 to 1.3.0
@@ -29,3 +29,4 @@ #!/usr/bin/env node | ||
{arg: 'full-tag', type: 'flag', option:'fullTagEmptyElement', desc: 'XML elements will always be in <a></a> form.'}, | ||
{arg: 'no-decl', type: 'flag', option:'ignoreDeclaration', desc: 'Declaration instruction <?xml ..?> will be ignored.'}, | ||
{arg: 'no-decl', type: 'flag', option:'ignoreDeclaration', desc: 'Declaration instruction <?xml?> will be ignored.'}, | ||
{arg: 'no-decl', type: 'flag', option:'ignoreInstruction', desc: 'Processing instruction <?...?> will be ignored.'}, | ||
{arg: 'no-attr', type: 'flag', option:'ignoreAttributes', desc: 'Attributes of elements will be ignored.'}, | ||
@@ -41,3 +42,4 @@ {arg: 'no-text', type: 'flag', option:'ignoreText', desc: 'Texts of elements will be ignored.'}, | ||
{arg: 'attributes-key', type: 'string', option:'attributesKey', desc: 'To change the default \'attributes\' key.'}, | ||
{arg: 'declaration-key', type: 'string', option:'declarationKey', desc: 'To change the default \'declaration\' key.'}, | ||
{arg: 'declaration-key', type: 'string', option:'declarationKey', desc: 'To change the default \'declaration\' key <?xml?>.'}, | ||
{arg: 'instruction-key', type: 'string', option:'instructionKey', desc: 'To change the default \'processing instruction\' key <?...?>.'}, | ||
{arg: 'type-key', type: 'string', option:'typeKey', desc: 'To change the default \'type\' key (applicable if --compact is not set).'}, | ||
@@ -44,0 +46,0 @@ {arg: 'name-key', type: 'string', option:'nameKey', desc: 'To change the default \'name\' key (applicable if --compact is not set).'}, |
var common = require('./common'); | ||
function validateOptions (userOptions) { | ||
function validateOptions(userOptions) { | ||
var options = common.copyOptions(userOptions); | ||
common.ensureFlagExists('ignoreDeclaration', options); | ||
common.ensureFlagExists('ignoreInstruction', options); | ||
common.ensureFlagExists('ignoreAttributes', options); | ||
@@ -14,2 +15,3 @@ common.ensureFlagExists('ignoreText', options); | ||
common.ensureFlagExists('indentCdata', options); | ||
common.ensureFlagExists('indentInstruction', options); | ||
common.ensureFlagExists('fullTagEmptyElement', options); | ||
@@ -21,2 +23,3 @@ common.ensureSpacesExists(options); | ||
common.ensureKeyExists('declaration', options); | ||
common.ensureKeyExists('instruction', options); | ||
common.ensureKeyExists('attributes', options); | ||
@@ -33,7 +36,7 @@ common.ensureKeyExists('text', options); | ||
function writeIndentation (options, depth, firstLine) { | ||
function writeIndentation(options, depth, firstLine) { | ||
return (!firstLine && options.spaces ? '\n' : '') + Array(depth + 1).join(options.spaces); | ||
} | ||
function writeAttributes (attributes) { | ||
function writeAttributes(attributes) { | ||
var key, result = ''; | ||
@@ -48,23 +51,33 @@ for (key in attributes) { | ||
function writeDeclaration (declaration, options) { | ||
function writeDeclaration(declaration, options) { | ||
return '<?xml' + writeAttributes(declaration[options.attributesKey]) + '?>'; | ||
} | ||
function writeComment (comment, options) { | ||
function writeInstruction(instruction, options) { | ||
var key; | ||
for (key in instruction) { | ||
if (instruction.hasOwnProperty(key)) { | ||
break; | ||
} | ||
} | ||
return '<?' + key + (instruction[key] ? ' ' + instruction[key] : '') + '?>'; | ||
} | ||
function writeComment(comment, options) { | ||
return options.ignoreComment ? '' : '<!--' + comment + '-->'; | ||
} | ||
function writeCdata (cdata, options) { | ||
function writeCdata(cdata, options) { | ||
return options.ignoreCdata ? '' : '<![CDATA[' + cdata + ']]>'; | ||
} | ||
function writeDoctype (doctype, options) { | ||
function writeDoctype(doctype, options) { | ||
return options.ignoreDoctype ? '' : '<!DOCTYPE ' + doctype + '>'; | ||
} | ||
function writeText (text, options) { | ||
function writeText(text, options) { | ||
return options.ignoreText ? '' : text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"); | ||
} | ||
function hasContent (element, options) { | ||
function hasContent(element, options) { | ||
var i; | ||
@@ -84,2 +97,7 @@ if (element.elements && element.elements.length) { | ||
break; // skip to next key | ||
case 'instruction': | ||
if (options.indentInstruction) { | ||
return true; | ||
} | ||
break; // skip to next key | ||
case 'doctype': | ||
@@ -97,3 +115,3 @@ case 'comment': | ||
function writeElement (element, options, depth) { | ||
function writeElement(element, options, depth) { | ||
var xml = ''; | ||
@@ -117,3 +135,3 @@ xml += '<' + element.name; | ||
function writeElements (elements, options, depth, firstLine) { | ||
function writeElements(elements, options, depth, firstLine) { | ||
return elements.reduce(function (xml, element) { | ||
@@ -127,2 +145,6 @@ var indent = writeIndentation(options, depth, firstLine && !xml); | ||
case 'text': return xml + (options.indentText ? indent : '') + writeText(element[options.textKey], options); | ||
case 'instruction': | ||
var instruction = {}; | ||
instruction[element[options.nameKey]] = element[options.instructionKey]; | ||
return xml + (options.indentInstruction ? indent : '') + writeInstruction(instruction, options); | ||
} | ||
@@ -132,3 +154,3 @@ }, ''); | ||
function hasContentCompact (element, options, anyContent) { | ||
function hasContentCompact(element, options, anyContent) { | ||
var key; | ||
@@ -151,5 +173,10 @@ for (key in element) { | ||
break; // skip to next key | ||
case options.instructionKey: | ||
if (options.indentInstruction || anyContent) { | ||
return true; | ||
} | ||
break; // skip to next key | ||
case options.doctypeKey: | ||
case options.commentKey: | ||
case options.declarationKey: | ||
case options.instructionKey: | ||
return true; | ||
@@ -164,3 +191,3 @@ default: | ||
function writeElementCompact (element, name, options, depth, indent) { | ||
function writeElementCompact(element, name, options, depth, indent) { | ||
var xml = ''; | ||
@@ -186,3 +213,3 @@ if (name) { | ||
function writeElementsCompact (element, options, depth, firstLine) { | ||
function writeElementsCompact(element, options, depth, firstLine) { | ||
var i, key, nodes, xml = ''; | ||
@@ -195,2 +222,3 @@ for (key in element) { | ||
case options.declarationKey: xml += writeDeclaration(nodes[i], options); break; | ||
case options.instructionKey: xml += (options.indentInstruction ? writeIndentation(options, depth, firstLine) : '') + writeInstruction(nodes[i], options); break; | ||
case options.attributesKey: case options.parentKey: break; // skip | ||
@@ -197,0 +225,0 @@ case options.textKey: xml += (options.indentText ? writeIndentation(options, depth, firstLine) : '') + writeText(nodes[i], options); break; |
var sax = require('sax'); | ||
var expat /*= require('node-expat');*/ = {on: function () {}, parse: function () {}}; | ||
var expat /*= require('node-expat');*/ = { on: function () { }, parse: function () { } }; | ||
var common = require('./common'); | ||
var options; | ||
var pureJsParser = 1; //true; | ||
var pureJsParser = true; | ||
var currentElement; | ||
function validateOptions (userOptions) { | ||
function validateOptions(userOptions) { | ||
options = common.copyOptions(userOptions); | ||
common.ensureFlagExists('ignoreDeclaration', options); | ||
common.ensureFlagExists('ignoreInstruction', options); | ||
common.ensureFlagExists('ignoreAttributes', options); | ||
@@ -25,2 +26,3 @@ common.ensureFlagExists('ignoreText', options); | ||
common.ensureKeyExists('declaration', options); | ||
common.ensureKeyExists('instruction', options); | ||
common.ensureKeyExists('attributes', options); | ||
@@ -38,3 +40,3 @@ common.ensureKeyExists('text', options); | ||
function nativeType (value) { | ||
function nativeType(value) { | ||
var nValue = Number(value); | ||
@@ -53,3 +55,3 @@ if (!isNaN(nValue)) { | ||
function addField (type, value, options) { | ||
function addField(type, value, options) { | ||
if (options.compact) { | ||
@@ -71,5 +73,15 @@ if (!currentElement[options[type + 'Key']] && options.alwaysArray) { | ||
} | ||
var element = {}; | ||
var key, element = {}; | ||
element[options.typeKey] = type; | ||
element[options[type + 'Key']] = value; | ||
if (typeof value === 'object') { | ||
for (key in value) { | ||
if (value.hasOwnProperty(key)) { | ||
element[options.nameKey] = key; | ||
element[options[type + 'Key']] = value[key]; | ||
break; | ||
} | ||
} | ||
} else { | ||
element[options[type + 'Key']] = value; | ||
} | ||
if (options.addParent) { | ||
@@ -82,27 +94,39 @@ element[options.parentKey] = currentElement; | ||
function onDeclaration (declaration) { | ||
if (options.ignoreDeclaration) { | ||
return; | ||
} | ||
if (currentElement[options.declarationKey]) { | ||
return; | ||
} | ||
currentElement[options.declarationKey] = {}; | ||
while (declaration.body) { | ||
var attribute = declaration.body.match(/([\w:-]+)\s*=\s*"([^"]*)"|'([^']*)'|(\w+)\s*/); | ||
if (!attribute) { | ||
break; | ||
function onInstruction(instruction) { | ||
if (instruction.name.toLowerCase() === 'xml') { | ||
if (options.ignoreDeclaration) { | ||
return; | ||
} | ||
if (!currentElement[options.declarationKey][options.attributesKey]) { | ||
currentElement[options.declarationKey][options.attributesKey] = {}; | ||
currentElement[options.declarationKey] = {}; | ||
while (instruction.body) { | ||
var attribute = instruction.body.match(/([\w:-]+)\s*=\s*"([^"]*)"|'([^']*)'|(\w+)\s*/); | ||
if (!attribute) { | ||
break; | ||
} | ||
if (!currentElement[options.declarationKey][options.attributesKey]) { | ||
currentElement[options.declarationKey][options.attributesKey] = {}; | ||
} | ||
currentElement[options.declarationKey][options.attributesKey][attribute[1]] = attribute[2]; | ||
instruction.body = instruction.body.slice(attribute[0].length); // advance the string | ||
} | ||
currentElement[options.declarationKey][options.attributesKey][attribute[1]] = attribute[2]; | ||
declaration.body = declaration.body.slice(attribute[0].length); // advance the string | ||
if (options.addParent) { | ||
currentElement[options.declarationKey][options.parentKey] = currentElement; | ||
} | ||
} else { | ||
if (options.ignoreInstruction) { | ||
return; | ||
} | ||
if (options.trim) { | ||
instruction.body = instruction.body.trim(); | ||
} | ||
if (options.sanitize) { | ||
instruction.body = common.sanitize(instruction.body); | ||
} | ||
var value = {}; | ||
value[instruction.name] = instruction.body; | ||
addField('instruction', value, options); | ||
} | ||
if (options.addParent) { | ||
currentElement[options.declarationKey][options.parentKey] = currentElement; | ||
} | ||
} | ||
function onStartElement (name, attributes) { | ||
function onStartElement(name, attributes) { | ||
var key, element; | ||
@@ -130,3 +154,2 @@ if (typeof name === 'object') { | ||
} | ||
element[options.parentKey] = currentElement; | ||
if (!(name in currentElement) && options.alwaysArray) { | ||
@@ -153,3 +176,2 @@ currentElement[name] = []; | ||
} | ||
element[options.parentKey] = currentElement; | ||
if (options.alwaysChildren) { | ||
@@ -160,6 +182,9 @@ element[options.elementsKey] = []; | ||
} | ||
// if (options.addParent) { | ||
element[options.parentKey] = currentElement; | ||
// } | ||
currentElement = element; | ||
} | ||
function onText (text) { | ||
function onText(text) { | ||
if (options.ignoreText) { | ||
@@ -183,3 +208,3 @@ return; | ||
function onComment (comment) { | ||
function onComment(comment) { | ||
if (options.ignoreComment) { | ||
@@ -197,3 +222,3 @@ return; | ||
function onEndElement (name) { | ||
function onEndElement(name) { | ||
var parentElement = currentElement[options.parentKey]; | ||
@@ -206,3 +231,3 @@ if (!options.addParent) { | ||
function onCdata (cdata) { | ||
function onCdata(cdata) { | ||
if (options.ignoreCdata) { | ||
@@ -217,3 +242,3 @@ return; | ||
function onDoctype (doctype) { | ||
function onDoctype(doctype) { | ||
if (options.ignoreDoctype) { | ||
@@ -229,3 +254,3 @@ return; | ||
function onError (error) { | ||
function onError(error) { | ||
error.note = error; //console.error(error); | ||
@@ -250,3 +275,3 @@ } | ||
parser.ondoctype = onDoctype; | ||
parser.onprocessinginstruction = onDeclaration; | ||
parser.onprocessinginstruction = onInstruction; | ||
} else { | ||
@@ -253,0 +278,0 @@ parser.on('startElement', onStartElement); |
@@ -16,2 +16,3 @@ var common = require('./common'); | ||
parentKey = 'compact' in options && options.compact ? '_parent' : 'parent'; | ||
// parentKey = ptions.compact ? '_parent' : 'parent'; // consider this | ||
if ('addParent' in options && options.addParent) { | ||
@@ -23,2 +24,2 @@ json = JSON.stringify(js, function (k, v) { return k === parentKey? '_' : v; }, options.spaces); | ||
return json.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029'); | ||
}; | ||
}; |
{ | ||
"name": "xml-js", | ||
"version": "1.2.2", | ||
"version": "1.3.0", | ||
"description": "A convertor between XML text and Javascript object / JSON text.", | ||
@@ -44,21 +44,3 @@ "repository": { | ||
"bin": "./bin/cli.js", | ||
"dependencies": { | ||
"sax": "^1.2.1" | ||
}, | ||
"devDependencies": { | ||
"biased-opener": "^0.2.8", | ||
"browser-sync": "^2.18.6", | ||
"cash-cat": "^0.2.0", | ||
"codacy-coverage": "^2.0.2", | ||
"codeclimate-test-reporter": "^0.4.0", | ||
"coveralls": "^2.13.0", | ||
"cross-env": "^4.0.0", | ||
"globify": "^2.0.0", | ||
"istanbul": "^0.4.5", | ||
"jasmine": "^2.6.0", | ||
"nodemon": "^1.11.0", | ||
"npm-run-all": "^4.0.1", | ||
"typescript": "^2.2.2", | ||
"watch": "^1.0.1" | ||
}, | ||
"types": "./types/index.d.ts", | ||
"scripts": { | ||
@@ -90,3 +72,21 @@ "debug": "nodemon --inspect --watch lib/ --watch test/ --debug-brk test/index.js", | ||
}, | ||
"types": "./types/index.d.ts" | ||
"dependencies": { | ||
"sax": "^1.2.1" | ||
}, | ||
"devDependencies": { | ||
"biased-opener": "^0.2.8", | ||
"browser-sync": "^2.18.6", | ||
"cash-cat": "^0.2.0", | ||
"codacy-coverage": "^2.0.2", | ||
"codeclimate-test-reporter": "^0.4.0", | ||
"coveralls": "^2.13.0", | ||
"cross-env": "^4.0.0", | ||
"globify": "^2.0.0", | ||
"istanbul": "^0.4.5", | ||
"jasmine": "^2.6.0", | ||
"nodemon": "^1.11.0", | ||
"npm-run-all": "^4.0.1", | ||
"typescript": "^2.2.2", | ||
"watch": "^1.0.1" | ||
} | ||
} |
@@ -33,3 +33,3 @@ ![XML ⇔ JS/JSON](http://nashwaan.github.io/xml-js/images/logo.svg) | ||
* **Fully XML Compliant**: | ||
Can parse: elements, attributes, texts, comments, CData, DOCTYPE, and XML declarations. | ||
Can parse: elements, attributes, texts, comments, CData, DOCTYPE, XML declarations, and Processing Instructions. | ||
@@ -62,3 +62,3 @@ * **Reversible**: | ||
Most XML to JSON convertors (including online convertors) convert `<a/>` to some compact output like `{"a":{}}` | ||
Most XML to JSON converters (including online converters) convert `<a/>` to some compact output like `{"a":{}}` | ||
instead of non-compact output like `{"elements":[{"type":"element","name":"a"}]}`. | ||
@@ -69,6 +69,6 @@ | ||
which has merged both `<a>` elements into an array! If you try to convert this back to xml, you will get `<a x="1"/><a x="3"/><b x="2"/>` | ||
which has not preserved the order of elements! This is an inherit limitation in the compact representation | ||
which has not preserved the order of elements! This is an inherent limitation in the compact representation | ||
because output like `{a:{_:{x:"1"}}, b:{_:{x:"2"}}, a:{_:{x:"3"}}}` is illegal (same property name `a` should not appear twice in an object). | ||
The non-compact output, which is supported by this library, will produce more information and always gurantees the order of the elements as they appeared in the XML file. | ||
The non-compact output, which is supported by this library, will produce more information and always guarantees the order of the elements as they appeared in the XML file. | ||
@@ -79,4 +79,7 @@ Another drawback of compact output is the resultant element can be an object or an array and therefore makes the client code a little awkwards in terms of the extra check needed on object type before processing. | ||
This library provides both options. Use `{compact: false}` if you are not sure because it preserves everything; | ||
otherwise use `{compact: true}` if you want to save space and you don't care about mixing elements of same type and loosing their order. | ||
otherwise use `{compact: true}` if you want to save space and you don't care about mixing elements of same type and losing their order. | ||
# Usage | ||
@@ -126,2 +129,3 @@ | ||
| `<?xml?>` | `{"_declaration":{}}` | `{"declaration":{}}` | | ||
| `<?go there?>` | `{"_instruction":{"go":"there"}}` | `{"elements":[{"type":"instruction","name":"go","instruction":"there"}]}` | | ||
| `<?xml version="1.0" encoding="utf-8"?>` | `{"_declaration":{"_attributes":{"version":"1.0","encoding":"utf-8"}}}` | `{"declaration":{"attributes":{"version":"1.0","encoding":"utf-8"}}}` | | ||
@@ -165,2 +169,3 @@ | `<!--Hello, World!-->` | `{"_comment":"Hello, World!"}` | `{"elements":[{"type":"comment","comment":"Hello, World!"}]}` | | ||
| `ignoreDeclaration` | `false` | Whether to ignore writing declaration directives of xml. For example, `<?xml?>` will be ignored. | | ||
| `ignoreInstruction` | `false` | Whether to ignore writing processing instruction of xml. For example, `<?go there?>` will be ignored. | | ||
| `ignoreAttributes` | `false` | Whether to ignore writing attributes of the elements. For example, `x="1"` in `<a x="1"></a>` will be ignored | | ||
@@ -191,3 +196,3 @@ | `ignoreComment` | `false` | Whether to ignore writing comments of the elements. That is, no `<!-- -->` will be generated. | | ||
| `compact` | `false` | Whether to produce detailed object or compact object. | | ||
| `trim` | `false` | Whether to trim white space characters that may exist before and after the text. | | ||
| `trim` | `false` | Whether to trim whitespace characters that may exist before and after the text. | | ||
| `sanitize` | `false` | Whether to replace `&` `<` `>` `"` `'` with `&` `<` `>` `"` `'` respectively in the resultant text. | | ||
@@ -199,2 +204,3 @@ | `nativeType` | `false` | Whether to attempt converting text of numerals or of boolean values to native type. For example, `"123"` will be `123` and `"true"` will be `true` | | ||
| `ignoreDeclaration` | `false` | Whether to ignore writing declaration property. That is, no `declaration` property will be generated. | | ||
| `ignoreInstruction` | `false` | Whether to ignore writing processing instruction property. That is, no `instruction` property will be generated. | | ||
| `ignoreAttributes` | `false` | Whether to ignore writing attributes of elements.That is, no `attributes` property will be generated. | | ||
@@ -210,3 +216,3 @@ | `ignoreComment` | `false` | Whether to ignore writing comments of the elements. That is, no `comment` will be generated. | | ||
|:--------------------|:--------|:------------| | ||
| `spaces` | `0` | Number of spaces to be used for indenting JSON output. Passing characters like `' '` or `'\t'` are also accpeted. | | ||
| `spaces` | `0` | Number of spaces to be used for indenting JSON output. Passing characters like `' '` or `'\t'` are also accepted. | | ||
@@ -220,2 +226,3 @@ ## Options for Changing Key Names | ||
| `declarationKey` | `"declaration"` or `"_declaration"` | Name of the property key which will be used for the declaration. For example, if `declarationKey: '$declaration'` then output of `<?xml?>` will be `{"$declaration":{}}` *(in compact form)* | | ||
| `instructionKey` | `"instruction"` or `"_instruction"` | Name of the property key which will be used for the processing instruction. For example, if `instructionKey: '$instruction'` then output of `<?go there?>` will be `{"$instruction":{"go":"there"}}` *(in compact form)* | | ||
| `attributesKey` | `"attributes"` or `"_attributes"` | Name of the property key which will be used for the attributes. For example, if `attributesKey: '$attributes'` then output of `<a x="hello"/>` will be `{"a":{$attributes:{"x":"hello"}}}` *(in compact form)* | | ||
@@ -287,3 +294,4 @@ | `textKey` | `"text"` or `"_text"` | Name of the property key which will be used for the text. For example, if `textKey: '$text'` then output of `<a>hi</a>` will be `{"a":{"$text":"Hi"}}` *(in compact form)* | | ||
--full-tag XML elements will always be in <a></a> form. | ||
--no-decl Declaration instruction <?xml ..?> will be ignored. | ||
--no-decl Declaration directive <?xml?> will be ignored. | ||
--no-inst Processing instruction <?...?> will be ignored. | ||
--no-attr Attributes of elements will be ignored. | ||
@@ -306,2 +314,3 @@ --no-text Texts of elements will be ignored. | ||
--declaration-key To change the default 'declaration' key. | ||
--instruction-key To change the default 'processing instruction' key. | ||
--type-key To change the default 'type' key (applicable if --compact is not set). | ||
@@ -308,0 +317,0 @@ --name-key To change the default 'name' key (applicable if --compact is not set). |
export interface ElementCompact { | ||
[key: string]: any | ||
_declaration?: { | ||
_attributes?: { | ||
version?: string | number | ||
encoding?: string | number | ||
} | ||
} | ||
_instruction?: { | ||
[key: string]: string | ||
} | ||
_attributes?: { | ||
@@ -9,8 +18,2 @@ [key: string]: string | number | ||
_comment?: string | ||
_declaration?: { | ||
_attributes?: { | ||
version?: string | number | ||
encoding?: string | number | ||
} | ||
} | ||
_text?: string | number | ||
@@ -20,2 +23,9 @@ } | ||
export interface Element { | ||
declaration?: { | ||
attributes?: { | ||
version: string | number | ||
encoding: string | number | ||
} | ||
} | ||
instruction?: string | ||
attributes?: { | ||
@@ -27,8 +37,2 @@ [key: string]: string | number | ||
comment?: string | ||
declaration?: { | ||
attributes?: { | ||
version: string | number | ||
encoding: string | number | ||
} | ||
} | ||
text?: string | number | boolean | ||
@@ -57,2 +61,3 @@ type?: string | ||
indentCdata?: boolean | ||
indentInstruction?: boolean | ||
fullTagEmptyElement?: boolean | ||
@@ -63,2 +68,3 @@ } | ||
ignoreDeclaration?: boolean | ||
ignoreInstruction?: boolean | ||
ignoreAttributes?: boolean | ||
@@ -73,2 +79,3 @@ ignoreComment?: boolean | ||
declarationKey?: string | ||
instructionKey?: string | ||
attributesKey?: string | ||
@@ -75,0 +82,0 @@ textKey?: string |
@@ -10,2 +10,6 @@ import { Element, ElementCompact } from './index' | ||
// Processing Instruction | ||
const instructionCompact: ElementCompact = { _instruction: { go: 'there' }}; | ||
const instruction: Element = { elements:[{ type: 'instruction', name: 'go', instruction: 'there' }]}; | ||
// Comment | ||
@@ -12,0 +16,0 @@ const commentCompact: ElementCompact = { _comment : 'Hello, World!' }; |
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
64742
860
329