src/utils.js
'use strict';
const xml2js = require('xml2js');
const parseXml = xml2js.parseString;
const FZP = require('./fzp/fzp');
const FZPConnector = require('./fzp/connector');
const FZPConnectorView = require('./fzp/connector-view');
const {FritzingPartsAPI, FritzingPartsAPIClient} = require('fritzing-parts-api-client-js');
/**
* Load a FZP file from the given URL.
*
* @example
* const {FZPUtils} = require('fzp-js')
*
* FZPUtils.loadFZP('core/Arduino Nano3(fix).fzp')
* .then((fzz) => {
* console.log(fzz.fz)
* })
* .catch((err) => {
* console.error(err)
* })
*
* @param {String} src
* @param {String} url URL to the FZP file.
* @return {Promise}
*/
function loadFZP(src, url = FritzingPartsAPI) {
return FritzingPartsAPIClient.getFzp(src, url)
.then((fzp) => {
// let tmp = parseFZP(fzp);
// console.log(tmp);
return parseFZP(fzp);
});
}
/**
* Load a FZP and all linked SVGs
*
* @example
* const {FZPUtils} = require('fzp-js')
*
* FZPUtils.loadFZPandSVGs('core/Arduino Nano3(fix).fzp')
* .then((fzz) => {
* console.log(fzz)
* })
* .catch((err) => {
* console.error(err)
* })
*
* @param {String} src
* @param {String} url URL to the FZP file.
* @return {FZP}
*/
function loadFZPandSVGs(src, url = FritzingPartsAPI) {
return loadFZP(src, url).then((fzp) => {
return fzp.loadSVGs(`${url}/svg/core/`).then(() => {
return fzp;
});
});
}
/**
* parse a fzp xml string
* @param {String} data
* @return {Promise}
*/
function parseFZP(data) {
return new Promise(function(resolve, reject) {
let fzp = new FZP();
if (data) {
parseXml(data, (err, xml) => {
if (err) {
return reject(err);
}
console.log(xml.module.tags);
fzp.moduleId = xml.module.$.moduleId;
fzp.fritzingVersion = xml.module.$.fritzingVersion;
if (xml.module.version) fzp.version = xml.module.version[0];
if (xml.module.title) fzp.title = xml.module.title[0];
if (xml.module.description) fzp.description = xml.module.description[0];
if (xml.module.author) fzp.author = xml.module.author[0];
if (xml.module.date) fzp.date = xml.module.date[0];
if (xml.module.url) fzp.url = xml.module.url[0];
if (xml.module.label) fzp.label = xml.module.label[0];
if (xml.module.tags) fzp.tags = xml.module.tags[0].tag;
if (xml.module.taxonomy) fzp.taxonomy = xml.module.taxonomy;
if (xml.module.language) fzp.language = xml.module.language;
if (xml.module.family) fzp.family = xml.module.family;
if (xml.module.variant) fzp.variant = xml.module.variant;
if (xml.module.properties) {
fzp.properties = parseProperties(xml.module.properties[0].property);
}
if (xml.module.views) {
if (xml.module.views[0].iconView) {
const iconViewLayer = xml.module.views[0].iconView[0].layers[0];
fzp.views.icon.setImage(iconViewLayer.$.image);
fzp.views.icon.setLayerId(iconViewLayer.layer[0].$.layerId);
}
if (xml.module.views[0].breadboardView) {
const breadboardLayer = xml.module.views[0].breadboardView[0].layers[0];
fzp.views.breadboard.setImage(breadboardLayer.$.image);
fzp.views.breadboard.setLayerId(breadboardLayer.layer[0].$.layerId);
}
if (xml.module.views[0].pcbView) {
const pcbViewLayer = xml.module.views[0].pcbView[0].layers[0];
fzp.views.pcb.setImage(pcbViewLayer.$.image);
for (let iLayer = 0; iLayer < pcbViewLayer.layer.length; iLayer++) {
fzp.views.pcb.setLayerId(pcbViewLayer.layer[iLayer].$.layerId);
}
}
if (xml.module.views[0].schematicView) {
const schematicViewLayer = xml.module.views[0].schematicView[0].layers[0];
fzp.views.schematic.setImage(schematicViewLayer.$.image);
fzp.views.schematic.setLayerId(schematicViewLayer.layer[0].$.layerId);
}
}
if (xml.module.connectors) {
if (xml.module.connectors[0].connector) {
for (let i = 0; i < xml.module.connectors[0].connector.length; i++) {
const connector = xml.module.connectors[0].connector[i];
// create the connector for the three views.
let c = new FZPConnector();
c.id = connector.$.id;
c.name = connector.$.name;
c.type = connector.$.type;
if (connector.description) {
c.description = connector.description[0];
}
if (connector.views[0].breadboardView) {
c.views.breadboard = parseConnectorView(connector.views[0].breadboardView[0].p[0]);
}
if (connector.views[0].schematicView) {
c.views.schematic = parseConnectorView(connector.views[0].schematicView[0].p[0]);
}
if (connector.views[0].pcbView) {
for (let iPcb = 0; iPcb < connector.views[0].pcbView[0].p.length; iPcb++) {
switch (connector.views[0].pcbView[0].p[iPcb].$.layer) {
case 'copper0':
c.views.pcb.copper0 = parseConnectorView(connector.views[0].pcbView[0].p[iPcb]);
break;
case 'copper1':
c.views.pcb.copper1 = parseConnectorView(connector.views[0].pcbView[0].p[iPcb]);
break;
}
}
}
fzp.connectors[c.id] = c;
}
}
}
return resolve(fzp);
});
}
});
}
/**
* Get the parsed xml object and map to a proper structure
* @param {String} xml
* @return {Object}
*/
function parseProperties(xml) {
let data = {};
// if (xml) {
// if (xml.length > 0) {
for (let i = 0; i < xml.length; i++) {
data[xml[i].$.name] = {
value: xml[i]._,
showInLabel: xml[i].$.showInLabel,
};
}
// }
// }
return data;
}
/**
* @param {Object} xml
* @return {FZPConnectorView}
*/
function parseConnectorView(xml) {
let conView = new FZPConnectorView();
conView.layer = xml.$.layer || null;
conView.svgId = xml.$.svgId || null;
conView.legId = xml.$.legId || null;
conView.terminalId = xml.$.terminalId || null;
return conView;
}
/**
* Create a xml string of a FZP instance.
*
* @example
* const {marshalToXML} = require('fzp-js')
*
* const xmlData = FZPUtils.marshalToXML(fzp)
* console.log(xmlData)
*
* @param {FZP} fzp
* @return {String}
*/
function marshalToXML(fzp) {
let builder = new xml2js.Builder();
let data = {
module: {
$: {
moduleId: fzp.moduleId,
fritzingVersion: fzp.fritzingVersion,
},
version: [fzp.version],
title: [fzp.title],
author: [fzp.author],
label: [fzp.label],
date: [fzp.date],
tags: [{tag: fzp.tags}],
// properties: fzp.properties,
description: [fzp.description],
views: [[{}]],
connectors: [[{}]],
},
};
// let data = {
// module: Object.assign({}, fzp),
// };
// data.module.$ = {
// };
// delete data.moduleId;
// delete data.fritzingVersion;
//
// data.module.tags =
//
// if (data.module) {
// if (data.module.views) {
// if (data.module.icon) {
// delete data.module.views.icon.svg;
// }
// if (data.module.breadboard) {
// delete data.module.views.breadboard.svg;
// }
// if (data.module.schematic) {
// delete data.module.views.schematic.svg;
// }
// if (data.module.pcb) {
// delete data.module.views.pcb.svg;
// }
// }
// }
return builder.buildObject(data);
}
module.exports = {
loadFZP,
loadFZPandSVGs,
parseFZP,
parseProperties,
marshalToXML,
};