cellml-text-editor 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -414,10 +414,40 @@ class g {
|
|
|
414
414
|
const s = this.scanner.value;
|
|
415
415
|
return this.scanner.nextToken(), s;
|
|
416
416
|
}
|
|
417
|
+
/**
|
|
418
|
+
* Checks if the element or any of its descendants use a CellML attribute
|
|
419
|
+
* (e.g. cellml:units).
|
|
420
|
+
*/
|
|
421
|
+
usesCellMLNamespace(e) {
|
|
422
|
+
const s = e.getElementsByTagName("*");
|
|
423
|
+
for (let i = 0; i < s.length; i++) {
|
|
424
|
+
const t = s[i];
|
|
425
|
+
for (let r = 0; t && r < t.attributes.length; r++) {
|
|
426
|
+
const c = t.attributes[r];
|
|
427
|
+
if (c && c.namespaceURI === m)
|
|
428
|
+
return !0;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return !1;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Checks if a specific Namespace URI is declared on this node
|
|
435
|
+
* and returns the prefix used (e.g. 'cellml', 'cellml2', or '' for default).
|
|
436
|
+
* Returns null if not found.
|
|
437
|
+
*/
|
|
438
|
+
getPrefixForNamespace(e, s) {
|
|
439
|
+
const i = "http://www.w3.org/2000/xmlns/";
|
|
440
|
+
for (let t = 0; t < e.attributes.length; t++) {
|
|
441
|
+
const r = e.attributes[t];
|
|
442
|
+
if (r && r.namespaceURI === i && r.value === s)
|
|
443
|
+
return r.localName === "xmlns" ? "" : r.localName;
|
|
444
|
+
}
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
417
447
|
serialize(e, s = 0) {
|
|
418
448
|
const i = " ".repeat(s), t = e.tagName, r = e.localName;
|
|
419
449
|
let c = "";
|
|
420
|
-
r === "model" && !e.hasAttribute("xmlns") && (c += ` xmlns="${m}"`), r === "math" && !e.hasAttribute("xmlns") && (c += ` xmlns="${h}" xmlns:cellml="${m}"`);
|
|
450
|
+
r === "model" && !e.hasAttribute("xmlns") && (c += ` xmlns="${m}"`), r === "math" && !e.hasAttribute("xmlns") && (c += ` xmlns="${h}"`, this.usesCellMLNamespace(e) && !e.hasAttribute("xmlns:cellml") && this.getPrefixForNamespace(e, m) === null && (c += ` xmlns:cellml="${m}"`));
|
|
421
451
|
for (let d = 0; d < e.attributes.length; d++) {
|
|
422
452
|
const f = e.attributes[d];
|
|
423
453
|
if (f) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
(function(m,n){typeof exports=="object"&&typeof module<"u"?n(exports):typeof define=="function"&&define.amd?define(["exports"],n):(m=typeof globalThis<"u"?globalThis:m||self,n(m.CellMLTextEditor={}))})(this,(function(m){"use strict";var n=(a=>(a[a.Unknown=0]="Unknown",a[a.EOF=1]="EOF",a[a.Identifier=2]="Identifier",a[a.Number=3]="Number",a[a.String=4]="String",a[a.KwDef=5]="KwDef",a[a.KwModel=6]="KwModel",a[a.KwComp=7]="KwComp",a[a.KwEndDef=8]="KwEndDef",a[a.KwAs=9]="KwAs",a[a.KwVar=10]="KwVar",a[a.KwUnit=11]="KwUnit",a[a.KwSel=12]="KwSel",a[a.KwCase=13]="KwCase",a[a.KwOtherwise=14]="KwOtherwise",a[a.KwEndSel=15]="KwEndSel",a[a.OpAss=16]="OpAss",a[a.OpPlus=17]="OpPlus",a[a.OpMinus=18]="OpMinus",a[a.OpTimes=19]="OpTimes",a[a.OpDivide=20]="OpDivide",a[a.OpComma=21]="OpComma",a[a.Colon=22]="Colon",a[a.SemiColon=23]="SemiColon",a[a.LParam=24]="LParam",a[a.RParam=25]="RParam",a[a.LBrace=26]="LBrace",a[a.RBrace=27]="RBrace",a[a.OpEq=28]="OpEq",a[a.OpNe=29]="OpNe",a[a.OpLt=30]="OpLt",a[a.OpLe=31]="OpLe",a[a.OpGt=32]="OpGt",a[a.OpGe=33]="OpGe",a[a.OpAnd=34]="OpAnd",a[a.OpOr=35]="OpOr",a))(n||{});class
|
|
1
|
+
(function(m,n){typeof exports=="object"&&typeof module<"u"?n(exports):typeof define=="function"&&define.amd?define(["exports"],n):(m=typeof globalThis<"u"?globalThis:m||self,n(m.CellMLTextEditor={}))})(this,(function(m){"use strict";var n=(a=>(a[a.Unknown=0]="Unknown",a[a.EOF=1]="EOF",a[a.Identifier=2]="Identifier",a[a.Number=3]="Number",a[a.String=4]="String",a[a.KwDef=5]="KwDef",a[a.KwModel=6]="KwModel",a[a.KwComp=7]="KwComp",a[a.KwEndDef=8]="KwEndDef",a[a.KwAs=9]="KwAs",a[a.KwVar=10]="KwVar",a[a.KwUnit=11]="KwUnit",a[a.KwSel=12]="KwSel",a[a.KwCase=13]="KwCase",a[a.KwOtherwise=14]="KwOtherwise",a[a.KwEndSel=15]="KwEndSel",a[a.OpAss=16]="OpAss",a[a.OpPlus=17]="OpPlus",a[a.OpMinus=18]="OpMinus",a[a.OpTimes=19]="OpTimes",a[a.OpDivide=20]="OpDivide",a[a.OpComma=21]="OpComma",a[a.Colon=22]="Colon",a[a.SemiColon=23]="SemiColon",a[a.LParam=24]="LParam",a[a.RParam=25]="RParam",a[a.LBrace=26]="LBrace",a[a.RBrace=27]="RBrace",a[a.OpEq=28]="OpEq",a[a.OpNe=29]="OpNe",a[a.OpLt=30]="OpLt",a[a.OpLe=31]="OpLe",a[a.OpGt=32]="OpGt",a[a.OpGe=33]="OpGe",a[a.OpAnd=34]="OpAnd",a[a.OpOr=35]="OpOr",a))(n||{});class g{input;pos=0;line=1;length;currentToken=1;currentValue="";constructor(e){this.input=e,this.length=e.length,this.nextToken()}get token(){return this.currentToken}get value(){return this.currentValue}nextToken(){const e=this.skipWhitespace();if(this.line+=e,this.pos>=this.length){this.currentToken=1;return}const s=this.input[this.pos];if(/[a-zA-Z_]/.test(s||"")){let i=this.pos;for(;this.pos<this.length&&/[a-zA-Z0-9_]/.test(this.input[this.pos]||"");)this.pos++;const t=this.input.slice(i,this.pos);this.currentValue=t,this.currentToken=this.getKeywordType(t);return}if(/[0-9]/.test(s||"")||s==="."&&/[0-9]/.test(this.input[this.pos+1]||"")){let i=this.pos;for(;this.pos<this.length&&/[0-9]/.test(this.input[this.pos]||"");)this.pos++;if(this.input[this.pos]===".")for(this.pos++;this.pos<this.length&&/[0-9]/.test(this.input[this.pos]||"");)this.pos++;if(this.input[this.pos]==="e"||this.input[this.pos]==="E")for(this.pos++,(this.input[this.pos]==="+"||this.input[this.pos]==="-")&&this.pos++;this.pos<this.length&&/[0-9]/.test(this.input[this.pos]||"");)this.pos++;this.currentValue=this.input.slice(i,this.pos),this.currentToken=3;return}switch(this.pos++,this.currentValue=s||"",s){case"=":this.input[this.pos]==="="?(this.pos++,this.currentValue="==",this.currentToken=28):this.currentToken=16;break;case"!":this.input[this.pos]==="="?(this.pos++,this.currentValue="!=",this.currentToken=29):(console.warn(`Unexpected character '!' at pos ${this.pos}`),this.currentToken=0);break;case"<":this.input[this.pos]==="="?(this.pos++,this.currentValue="<=",this.currentToken=31):this.currentToken=30;break;case">":this.input[this.pos]==="="?(this.pos++,this.currentValue=">=",this.currentToken=33):this.currentToken=32;break;case"+":this.currentToken=17;break;case"-":this.currentToken=18;break;case"*":this.currentToken=19;break;case"/":this.currentToken=20;break;case"(":this.currentToken=24;break;case")":this.currentToken=25;break;case"{":this.currentToken=26;break;case"}":this.currentToken=27;break;case":":this.currentToken=22;break;case";":this.currentToken=23;break;case",":this.currentToken=21;break;default:console.warn("Unknown char:",s),this.currentToken=0}}getLine(){return this.line}skipWhitespace(){let e=0;for(;this.pos<this.length;){const s=this.input[this.pos];if(/\s/.test(s||""))s===`
|
|
2
2
|
`&&e++,this.pos++;else if(s==="/"&&this.input[this.pos+1]==="/")for(this.pos+=2;this.pos<this.length&&this.input[this.pos]!==`
|
|
3
|
-
`;)this.pos++;else break}return e}getKeywordType(e){switch(e){case"def":return 5;case"model":return 6;case"comp":return 7;case"enddef":return 8;case"as":return 9;case"var":return 10;case"unit":return 11;case"sel":return 12;case"case":return 13;case"otherwise":return 14;case"endsel":return 15;case"and":return 34;case"or":return 35;default:return 2}}}const f="http://www.cellml.org/cellml/2.0#",o="http://www.w3.org/1998/Math/MathML";class
|
|
4
|
-
`+this.serialize(s),errors:[]}}catch(s){return{xml:null,errors:[{line:this.scanner.getLine(),message:s.message||"Unknown parsing error"}]}}}parseBlock(e){if(this.expect(n.KwDef),this.scanner.token===n.KwComp)this.parseComponent(e);else if(this.scanner.token===n.KwUnit)this.parseUnit(e);else throw new Error("Expected 'comp' or 'unit' after 'def'")}parseComponent(e){this.expect(n.KwComp);const s=this.expectValue(n.Identifier);this.expect(n.KwAs);const i=this.doc.createElementNS(f,"component");for(i.setAttribute("name",s),e.appendChild(i);this.scanner.token!==n.KwEndDef&&this.scanner.token!==n.EOF;)this.scanner.token===n.KwVar?this.parseVariable(i):this.scanner.token===n.Identifier||this.scanner.token===n.KwSel?this.parseMathEquation(i):this.scanner.nextToken();this.expect(n.KwEndDef),this.expect(n.SemiColon)}parseVariable(e){this.expect(n.KwVar);const s=this.expectValue(n.Identifier);this.expect(n.Colon);const i=this.expectValue(n.Identifier),t=this.doc.createElementNS(f,"variable");if(t.setAttribute("name",s),t.setAttribute("units",i),this.scanner.token===n.LBrace){for(this.scanner.nextToken();this.scanner.token!==n.RBrace&&this.scanner.token!==n.EOF;){const r=this.expectValue(n.Identifier);this.expect(n.Colon);let c="";this.scanner.token===n.OpMinus?(this.scanner.nextToken(),c="-"+this.expectValue(n.Number)):this.scanner.token===n.Number?c=this.expectValue(n.Number):c=this.expectValue(n.Identifier),r==="init"?t.setAttribute("initial_value",c):r==="interface"&&t.setAttribute("interface",c),this.scanner.token===n.OpComma&&this.scanner.nextToken()}this.expect(n.RBrace)}this.expect(n.SemiColon),e.appendChild(t)}parseUnit(e){for(this.expect(n.KwUnit);this.scanner.token!==n.KwEndDef&&this.scanner.token!==n.EOF;)this.scanner.nextToken();this.expect(n.KwEndDef),this.expect(n.SemiColon)}parseMathEquation(e){const s=this.scanner.getLine();let i=e.getElementsByTagNameNS(o,"math")[0];i||(i=this.doc.createElementNS(o,"math"),e.appendChild(i));const t=this.doc.createElementNS(o,"apply"),r=this.doc.createElementNS(o,"eq");t.appendChild(r);const c=this.parseExpression();this.expect(n.OpAss);const h=this.parseExpression(),u=this.scanner.getLine();this.sourceLineAttr&&t.setAttribute(this.sourceLineAttr,`${s.toString()}`+(u!==s?`-${u.toString()}`:"")),t.appendChild(c),t.appendChild(h),i.appendChild(t),this.expect(n.SemiColon)}parseCondition(){let e=this.parseComparison();for(;this.scanner.token===n.OpAnd||this.scanner.token===n.OpOr;){const s=this.scanner.token;this.scanner.nextToken();const i=this.parseComparison(),t=this.doc.createElementNS(o,"apply"),r=this.doc.createElementNS(o,s===n.OpAnd?"and":"or");t.appendChild(r),t.appendChild(e),t.appendChild(i),e=t}return e}isComparisonToken(e){return[n.OpEq,n.OpNe,n.OpLt,n.OpLe,n.OpGt,n.OpGe].includes(e)}parseComparison(){let e=this.parseExpression();if(this.isComparisonToken(this.scanner.token)){const s=this.scanner.token;this.scanner.nextToken();const i=this.parseExpression(),t=this.doc.createElementNS(o,"apply");let r="";switch(s){case n.OpEq:r="eq";break;case n.OpNe:r="neq";break;case n.OpLt:r="lt";break;case n.OpLe:r="leq";break;case n.OpGt:r="gt";break;case n.OpGe:r="geq";break;case n.OpAnd:r="and";break}const c=this.doc.createElementNS(o,r);return t.appendChild(c),t.appendChild(e),t.appendChild(i),t}return e}isMathMLApply(e,s){if(e.localName!=="apply")return!1;const i=e.firstElementChild;return i?i.localName===s:!1}parseExpression(){let e=this.parseTerm();for(;this.scanner.token===n.OpPlus||this.scanner.token===n.OpMinus;){const s=this.scanner.token;this.scanner.nextToken();const i=this.parseTerm();if(s===n.OpPlus&&this.isMathMLApply(e,"plus"))e.appendChild(i);else{const t=this.doc.createElementNS(o,"apply"),r=this.doc.createElementNS(o,s===n.OpPlus?"plus":"minus");t.appendChild(r),t.appendChild(e),t.appendChild(i),e=t}}return e}parseTerm(){let e=this.parseFactor();for(;this.scanner.token===n.OpTimes||this.scanner.token===n.OpDivide;){const s=this.scanner.token;this.scanner.nextToken();const i=this.parseFactor();if(s===n.OpTimes&&this.isMathMLApply(e,"times"))e.appendChild(i);else{const t=this.doc.createElementNS(o,"apply"),r=this.doc.createElementNS(o,s===n.OpTimes?"times":"divide");t.appendChild(r),t.appendChild(e),t.appendChild(i),e=t}}return e}createMathMLConstant(e){const s={pi:"pi",e:"exponentiale",inf:"infinity",infinity:"infinity",NaN:"notanumber",true:"true",false:"false"};return s.hasOwnProperty(e)?this.doc.createElementNS(o,s[e]||""):null}parseFactor(){if(this.scanner.token===n.OpMinus){this.scanner.nextToken();const e=this.parseFactor(),s=this.doc.createElementNS(o,"apply"),i=this.doc.createElementNS(o,"minus");return s.appendChild(i),s.appendChild(e),s}if(this.scanner.token===n.Number){const e=this.scanner.value;this.scanner.nextToken();const s=this.doc.createElementNS(o,"cn");if(s.textContent=e,this.scanner.token===n.LBrace){if(this.scanner.nextToken(),this.scanner.value==="units"){this.scanner.nextToken(),this.expect(n.Colon);const i=this.expectValue(n.Identifier);s.setAttributeNS(f,"cellml:units",i)}for(;this.scanner.token!==n.RBrace&&this.scanner.token!==n.EOF;)this.scanner.nextToken();this.expect(n.RBrace)}return s}else if(this.scanner.token===n.Identifier){const e=this.scanner.value;if(this.scanner.nextToken(),this.scanner.token===n.LParam)return this.parseFunctionCall(e);const s=this.createMathMLConstant(e);if(s)return s;const i=this.doc.createElementNS(o,"ci");return i.textContent=e,i}else if(this.scanner.token===n.LParam){this.scanner.nextToken();const e=this.parseExpression();return this.expect(n.RParam),e}else if(this.scanner.token===n.KwSel)return this.parsePiecewise();throw new Error(`Unexpected token in math: ${this.scanner.value}`)}parsePiecewise(){const e=this.doc.createElementNS(o,"piecewise");for(this.expect(n.KwSel);this.scanner.token===n.KwCase;){this.expect(n.KwCase);const s=this.parseCondition();this.expect(n.Colon);const i=this.parseExpression();this.expect(n.SemiColon);const t=this.doc.createElementNS(o,"piece");t.appendChild(i),t.appendChild(s),e.appendChild(t)}if(this.scanner.token===n.KwOtherwise){this.expect(n.KwOtherwise),this.expect(n.Colon);const s=this.parseExpression();this.expect(n.SemiColon);const i=this.doc.createElementNS(o,"otherwise");i.appendChild(s),e.appendChild(i)}return this.expect(n.KwEndSel),e}parseFunctionCall(e){if(this.expect(n.LParam),e==="ode"){const t=this.parseExpression();this.expect(n.OpComma);const r=this.parseExpression();this.expect(n.RParam);const c=this.doc.createElementNS(o,"apply");c.appendChild(this.doc.createElementNS(o,"diff"));const h=this.doc.createElementNS(o,"bvar");return h.appendChild(r),c.appendChild(h),c.appendChild(t),c}const s=this.doc.createElementNS(o,"apply"),i=this.doc.createElementNS(o,e);if(s.appendChild(i),this.scanner.token!==n.RParam)do this.scanner.token===n.OpComma&&this.scanner.nextToken(),s.appendChild(this.parseExpression());while(this.scanner.token===n.OpComma);return this.expect(n.RParam),s}expect(e){if(this.scanner.token!==e)throw new Error(`Syntax Error: Expected ${n[e]} but found '${this.scanner.value}'`);this.scanner.nextToken()}expectValue(e){if(this.scanner.token!==e)throw new Error(`Expected value of type ${n[e]}, got ${this.scanner.token}`);const s=this.scanner.value;return this.scanner.nextToken(),s}serialize(e,s=0){const i=" ".repeat(s),t=e.tagName,r=e.localName;let c="";r==="model"&&!e.hasAttribute("xmlns")&&(c+=` xmlns="${f}"`),r==="math"&&!e.hasAttribute("xmlns")&&(c+=` xmlns="${o}" xmlns:cellml="${f}"`);for(let d=0;d<e.attributes.length;d++){const w=e.attributes[d];if(w){if(this.sourceLineAttr&&w.name===this.sourceLineAttr)continue;c+=` ${w.name}="${w.value}"`}}const h=Array.from(e.childNodes),u=h.some(d=>d.nodeType===1),l=e.textContent?.trim();if(h.length===0&&!l)return`${i}<${t}${c}/>`;if(!u)return`${i}<${t}${c}>${l}</${t}>`;let p=`${i}<${t}${c}>
|
|
3
|
+
`;)this.pos++;else break}return e}getKeywordType(e){switch(e){case"def":return 5;case"model":return 6;case"comp":return 7;case"enddef":return 8;case"as":return 9;case"var":return 10;case"unit":return 11;case"sel":return 12;case"case":return 13;case"otherwise":return 14;case"endsel":return 15;case"and":return 34;case"or":return 35;default:return 2}}}const f="http://www.cellml.org/cellml/2.0#",o="http://www.w3.org/1998/Math/MathML";class ${scanner;doc;sourceLineAttr;constructor(e={}){this.sourceLineAttr=e.sourceLineAttribute===void 0?"data-source-location":e.sourceLineAttribute}parse(e){this.scanner=new g(e),this.doc=document.implementation.createDocument(f,"model",null);try{const s=this.doc.documentElement;for(this.expect(n.KwDef),this.expect(n.KwModel),this.scanner.token===n.Identifier&&(s.setAttribute("name",this.scanner.value),this.scanner.nextToken()),this.expect(n.KwAs);this.scanner.token!==n.KwEndDef&&this.scanner.token!==n.EOF;)this.scanner.token===n.KwDef?this.parseBlock(s):this.scanner.nextToken();return this.expect(n.KwEndDef),this.expect(n.SemiColon),{xml:`<?xml version="1.0" encoding="UTF-8"?>
|
|
4
|
+
`+this.serialize(s),errors:[]}}catch(s){return{xml:null,errors:[{line:this.scanner.getLine(),message:s.message||"Unknown parsing error"}]}}}parseBlock(e){if(this.expect(n.KwDef),this.scanner.token===n.KwComp)this.parseComponent(e);else if(this.scanner.token===n.KwUnit)this.parseUnit(e);else throw new Error("Expected 'comp' or 'unit' after 'def'")}parseComponent(e){this.expect(n.KwComp);const s=this.expectValue(n.Identifier);this.expect(n.KwAs);const i=this.doc.createElementNS(f,"component");for(i.setAttribute("name",s),e.appendChild(i);this.scanner.token!==n.KwEndDef&&this.scanner.token!==n.EOF;)this.scanner.token===n.KwVar?this.parseVariable(i):this.scanner.token===n.Identifier||this.scanner.token===n.KwSel?this.parseMathEquation(i):this.scanner.nextToken();this.expect(n.KwEndDef),this.expect(n.SemiColon)}parseVariable(e){this.expect(n.KwVar);const s=this.expectValue(n.Identifier);this.expect(n.Colon);const i=this.expectValue(n.Identifier),t=this.doc.createElementNS(f,"variable");if(t.setAttribute("name",s),t.setAttribute("units",i),this.scanner.token===n.LBrace){for(this.scanner.nextToken();this.scanner.token!==n.RBrace&&this.scanner.token!==n.EOF;){const r=this.expectValue(n.Identifier);this.expect(n.Colon);let c="";this.scanner.token===n.OpMinus?(this.scanner.nextToken(),c="-"+this.expectValue(n.Number)):this.scanner.token===n.Number?c=this.expectValue(n.Number):c=this.expectValue(n.Identifier),r==="init"?t.setAttribute("initial_value",c):r==="interface"&&t.setAttribute("interface",c),this.scanner.token===n.OpComma&&this.scanner.nextToken()}this.expect(n.RBrace)}this.expect(n.SemiColon),e.appendChild(t)}parseUnit(e){for(this.expect(n.KwUnit);this.scanner.token!==n.KwEndDef&&this.scanner.token!==n.EOF;)this.scanner.nextToken();this.expect(n.KwEndDef),this.expect(n.SemiColon)}parseMathEquation(e){const s=this.scanner.getLine();let i=e.getElementsByTagNameNS(o,"math")[0];i||(i=this.doc.createElementNS(o,"math"),e.appendChild(i));const t=this.doc.createElementNS(o,"apply"),r=this.doc.createElementNS(o,"eq");t.appendChild(r);const c=this.parseExpression();this.expect(n.OpAss);const h=this.parseExpression(),u=this.scanner.getLine();this.sourceLineAttr&&t.setAttribute(this.sourceLineAttr,`${s.toString()}`+(u!==s?`-${u.toString()}`:"")),t.appendChild(c),t.appendChild(h),i.appendChild(t),this.expect(n.SemiColon)}parseCondition(){let e=this.parseComparison();for(;this.scanner.token===n.OpAnd||this.scanner.token===n.OpOr;){const s=this.scanner.token;this.scanner.nextToken();const i=this.parseComparison(),t=this.doc.createElementNS(o,"apply"),r=this.doc.createElementNS(o,s===n.OpAnd?"and":"or");t.appendChild(r),t.appendChild(e),t.appendChild(i),e=t}return e}isComparisonToken(e){return[n.OpEq,n.OpNe,n.OpLt,n.OpLe,n.OpGt,n.OpGe].includes(e)}parseComparison(){let e=this.parseExpression();if(this.isComparisonToken(this.scanner.token)){const s=this.scanner.token;this.scanner.nextToken();const i=this.parseExpression(),t=this.doc.createElementNS(o,"apply");let r="";switch(s){case n.OpEq:r="eq";break;case n.OpNe:r="neq";break;case n.OpLt:r="lt";break;case n.OpLe:r="leq";break;case n.OpGt:r="gt";break;case n.OpGe:r="geq";break;case n.OpAnd:r="and";break}const c=this.doc.createElementNS(o,r);return t.appendChild(c),t.appendChild(e),t.appendChild(i),t}return e}isMathMLApply(e,s){if(e.localName!=="apply")return!1;const i=e.firstElementChild;return i?i.localName===s:!1}parseExpression(){let e=this.parseTerm();for(;this.scanner.token===n.OpPlus||this.scanner.token===n.OpMinus;){const s=this.scanner.token;this.scanner.nextToken();const i=this.parseTerm();if(s===n.OpPlus&&this.isMathMLApply(e,"plus"))e.appendChild(i);else{const t=this.doc.createElementNS(o,"apply"),r=this.doc.createElementNS(o,s===n.OpPlus?"plus":"minus");t.appendChild(r),t.appendChild(e),t.appendChild(i),e=t}}return e}parseTerm(){let e=this.parseFactor();for(;this.scanner.token===n.OpTimes||this.scanner.token===n.OpDivide;){const s=this.scanner.token;this.scanner.nextToken();const i=this.parseFactor();if(s===n.OpTimes&&this.isMathMLApply(e,"times"))e.appendChild(i);else{const t=this.doc.createElementNS(o,"apply"),r=this.doc.createElementNS(o,s===n.OpTimes?"times":"divide");t.appendChild(r),t.appendChild(e),t.appendChild(i),e=t}}return e}createMathMLConstant(e){const s={pi:"pi",e:"exponentiale",inf:"infinity",infinity:"infinity",NaN:"notanumber",true:"true",false:"false"};return s.hasOwnProperty(e)?this.doc.createElementNS(o,s[e]||""):null}parseFactor(){if(this.scanner.token===n.OpMinus){this.scanner.nextToken();const e=this.parseFactor(),s=this.doc.createElementNS(o,"apply"),i=this.doc.createElementNS(o,"minus");return s.appendChild(i),s.appendChild(e),s}if(this.scanner.token===n.Number){const e=this.scanner.value;this.scanner.nextToken();const s=this.doc.createElementNS(o,"cn");if(s.textContent=e,this.scanner.token===n.LBrace){if(this.scanner.nextToken(),this.scanner.value==="units"){this.scanner.nextToken(),this.expect(n.Colon);const i=this.expectValue(n.Identifier);s.setAttributeNS(f,"cellml:units",i)}for(;this.scanner.token!==n.RBrace&&this.scanner.token!==n.EOF;)this.scanner.nextToken();this.expect(n.RBrace)}return s}else if(this.scanner.token===n.Identifier){const e=this.scanner.value;if(this.scanner.nextToken(),this.scanner.token===n.LParam)return this.parseFunctionCall(e);const s=this.createMathMLConstant(e);if(s)return s;const i=this.doc.createElementNS(o,"ci");return i.textContent=e,i}else if(this.scanner.token===n.LParam){this.scanner.nextToken();const e=this.parseExpression();return this.expect(n.RParam),e}else if(this.scanner.token===n.KwSel)return this.parsePiecewise();throw new Error(`Unexpected token in math: ${this.scanner.value}`)}parsePiecewise(){const e=this.doc.createElementNS(o,"piecewise");for(this.expect(n.KwSel);this.scanner.token===n.KwCase;){this.expect(n.KwCase);const s=this.parseCondition();this.expect(n.Colon);const i=this.parseExpression();this.expect(n.SemiColon);const t=this.doc.createElementNS(o,"piece");t.appendChild(i),t.appendChild(s),e.appendChild(t)}if(this.scanner.token===n.KwOtherwise){this.expect(n.KwOtherwise),this.expect(n.Colon);const s=this.parseExpression();this.expect(n.SemiColon);const i=this.doc.createElementNS(o,"otherwise");i.appendChild(s),e.appendChild(i)}return this.expect(n.KwEndSel),e}parseFunctionCall(e){if(this.expect(n.LParam),e==="ode"){const t=this.parseExpression();this.expect(n.OpComma);const r=this.parseExpression();this.expect(n.RParam);const c=this.doc.createElementNS(o,"apply");c.appendChild(this.doc.createElementNS(o,"diff"));const h=this.doc.createElementNS(o,"bvar");return h.appendChild(r),c.appendChild(h),c.appendChild(t),c}const s=this.doc.createElementNS(o,"apply"),i=this.doc.createElementNS(o,e);if(s.appendChild(i),this.scanner.token!==n.RParam)do this.scanner.token===n.OpComma&&this.scanner.nextToken(),s.appendChild(this.parseExpression());while(this.scanner.token===n.OpComma);return this.expect(n.RParam),s}expect(e){if(this.scanner.token!==e)throw new Error(`Syntax Error: Expected ${n[e]} but found '${this.scanner.value}'`);this.scanner.nextToken()}expectValue(e){if(this.scanner.token!==e)throw new Error(`Expected value of type ${n[e]}, got ${this.scanner.token}`);const s=this.scanner.value;return this.scanner.nextToken(),s}usesCellMLNamespace(e){const s=e.getElementsByTagName("*");for(let i=0;i<s.length;i++){const t=s[i];for(let r=0;t&&r<t.attributes.length;r++){const c=t.attributes[r];if(c&&c.namespaceURI===f)return!0}}return!1}getPrefixForNamespace(e,s){const i="http://www.w3.org/2000/xmlns/";for(let t=0;t<e.attributes.length;t++){const r=e.attributes[t];if(r&&r.namespaceURI===i&&r.value===s)return r.localName==="xmlns"?"":r.localName}return null}serialize(e,s=0){const i=" ".repeat(s),t=e.tagName,r=e.localName;let c="";r==="model"&&!e.hasAttribute("xmlns")&&(c+=` xmlns="${f}"`),r==="math"&&!e.hasAttribute("xmlns")&&(c+=` xmlns="${o}"`,this.usesCellMLNamespace(e)&&!e.hasAttribute("xmlns:cellml")&&this.getPrefixForNamespace(e,f)===null&&(c+=` xmlns:cellml="${f}"`));for(let d=0;d<e.attributes.length;d++){const w=e.attributes[d];if(w){if(this.sourceLineAttr&&w.name===this.sourceLineAttr)continue;c+=` ${w.name}="${w.value}"`}}const h=Array.from(e.childNodes),u=h.some(d=>d.nodeType===1),l=e.textContent?.trim();if(h.length===0&&!l)return`${i}<${t}${c}/>`;if(!u)return`${i}<${t}${c}>${l}</${t}>`;let p=`${i}<${t}${c}>
|
|
5
5
|
`;return h.forEach(d=>{d.nodeType===1&&(p+=this.serialize(d,s+1)+`
|
|
6
|
-
`)}),p+=`${i}</${t}>`,p}}const
|
|
7
|
-
`:"")}generate(e){this.output="",this.indentLevel=0;try{const s=this.domParser.parseFromString(e,"application/xml");if(s.querySelector("parsererror"))throw new Error("XML Parsing Error");const t=s.getElementsByTagNameNS("http://www.cellml.org/cellml/2.0#","model")[0];if(!t)throw new Error("No CellML 2.0 Model found");this.processModel(t)}catch(s){return`// Error generating text: ${s.message}`}return this.output}processModel(e){const s=e.getAttribute("name")||"unnamed_model";this.append(`def model ${s} as`),this.indentLevel++;const i=e.getElementsByTagName("units");for(let r=0;r<i.length;r++)i[r]?.parentElement===e&&this.processUnits(i[r]);const t=e.getElementsByTagName("component");for(let r=0;r<t.length;r++)this.processComponent(t[r]);this.indentLevel--,this.append("enddef;")}processUnits(e){const s=e?.getAttribute("name")||"unnamed_units";this.append(`def unit ${s} as`),this.indentLevel++;const i=e?.getElementsByTagName("unit")||[];for(let t=0;t<i.length;t++){const r=i[t];if(!r)continue;const c=r.getAttribute("prefix"),h=r.getAttribute("units"),u=r.getAttribute("exponent"),l=r.getAttribute("multiplier");let p=`unit ${h}`;c&&(p+=` {prefix: ${c}}`),u&&(p+=` {exponent: ${u}}`),l&&(p+=` {multiplier: ${l}}`),p+=";",this.append(p)}this.indentLevel--,this.append("enddef;"),this.append("")}processComponent(e){const s=e?.getAttribute("name")||"unnamed_component";this.append(`def comp ${s} as`),this.indentLevel++;const i=e?.getElementsByTagName("variable")||[];for(let r=0;r<i.length;r++)this.processVariable(i[r]);const t=e?.getElementsByTagNameNS("http://www.w3.org/1998/Math/MathML","math")||[];for(let r=0;r<t.length;r++)this.processMath(t[r]);this.indentLevel--,this.append("enddef;"),this.append("")}processVariable(e){const s=e?.getAttribute("name"),i=e?.getAttribute("units"),t=e?.getAttribute("initial_value"),r=e?.getAttribute("interface");let c=`var ${s}: ${i}`,h=[];t&&h.push(`init: ${t}`),r&&h.push(`interface: ${r}`),h.length>0&&(c+=` {${h.join(", ")}}`),c+=";",this.append(c)}processMath(e){const s=Array.from(e?.children||[]);for(const i of s)if(i.localName==="apply"&&i.firstElementChild?.localName==="eq"){const r=Array.from(i.children).slice(1),c=this.parseMathNode(r[0]),h=this.parseMathNode(r[1]);this.append(`${c} = ${h};`)}else{const r=this.parseMathNode(i);r&&this.append(r+";")}}parseMathNode(e){if(!e)return"";const s=e.localName;if(s==="apply")return this.parseApply(e);if(s==="ci")return e.textContent?.trim()||"";if(s==="cn"){const i=e.textContent?.trim()||"0",t=e.getAttributeNS(
|
|
6
|
+
`)}),p+=`${i}</${t}>`,p}}const N="http://www.cellml.org/cellml/2.0#";class C{output="";indentLevel=0;domParser;standardIndent=" ";constructor(){this.domParser=new DOMParser}indent(){return this.standardIndent.repeat(this.indentLevel)}append(e,s=!0){this.output+=(s?this.indent():"")+e+(s?`
|
|
7
|
+
`:"")}generate(e){this.output="",this.indentLevel=0;try{const s=this.domParser.parseFromString(e,"application/xml");if(s.querySelector("parsererror"))throw new Error("XML Parsing Error");const t=s.getElementsByTagNameNS("http://www.cellml.org/cellml/2.0#","model")[0];if(!t)throw new Error("No CellML 2.0 Model found");this.processModel(t)}catch(s){return`// Error generating text: ${s.message}`}return this.output}processModel(e){const s=e.getAttribute("name")||"unnamed_model";this.append(`def model ${s} as`),this.indentLevel++;const i=e.getElementsByTagName("units");for(let r=0;r<i.length;r++)i[r]?.parentElement===e&&this.processUnits(i[r]);const t=e.getElementsByTagName("component");for(let r=0;r<t.length;r++)this.processComponent(t[r]);this.indentLevel--,this.append("enddef;")}processUnits(e){const s=e?.getAttribute("name")||"unnamed_units";this.append(`def unit ${s} as`),this.indentLevel++;const i=e?.getElementsByTagName("unit")||[];for(let t=0;t<i.length;t++){const r=i[t];if(!r)continue;const c=r.getAttribute("prefix"),h=r.getAttribute("units"),u=r.getAttribute("exponent"),l=r.getAttribute("multiplier");let p=`unit ${h}`;c&&(p+=` {prefix: ${c}}`),u&&(p+=` {exponent: ${u}}`),l&&(p+=` {multiplier: ${l}}`),p+=";",this.append(p)}this.indentLevel--,this.append("enddef;"),this.append("")}processComponent(e){const s=e?.getAttribute("name")||"unnamed_component";this.append(`def comp ${s} as`),this.indentLevel++;const i=e?.getElementsByTagName("variable")||[];for(let r=0;r<i.length;r++)this.processVariable(i[r]);const t=e?.getElementsByTagNameNS("http://www.w3.org/1998/Math/MathML","math")||[];for(let r=0;r<t.length;r++)this.processMath(t[r]);this.indentLevel--,this.append("enddef;"),this.append("")}processVariable(e){const s=e?.getAttribute("name"),i=e?.getAttribute("units"),t=e?.getAttribute("initial_value"),r=e?.getAttribute("interface");let c=`var ${s}: ${i}`,h=[];t&&h.push(`init: ${t}`),r&&h.push(`interface: ${r}`),h.length>0&&(c+=` {${h.join(", ")}}`),c+=";",this.append(c)}processMath(e){const s=Array.from(e?.children||[]);for(const i of s)if(i.localName==="apply"&&i.firstElementChild?.localName==="eq"){const r=Array.from(i.children).slice(1),c=this.parseMathNode(r[0]),h=this.parseMathNode(r[1]);this.append(`${c} = ${h};`)}else{const r=this.parseMathNode(i);r&&this.append(r+";")}}parseMathNode(e){if(!e)return"";const s=e.localName;if(s==="apply")return this.parseApply(e);if(s==="ci")return e.textContent?.trim()||"";if(s==="cn"){const i=e.textContent?.trim()||"0",t=e.getAttributeNS(N,"units");return t?`${i} {units: ${t}}`:i}else{if(s==="piecewise")return this.parsePiecewise(e);if(s==="pi")return"pi";if(s==="bvar")return""}return console.log(`Unsupported MathML node: ${s}`),`/* Unsupported MathML node: ${s} */`}parseApply(e){const s=Array.from(e.children);if(s.length===0)return"";const i=s[0]?.localName,t=s.slice(1).map(r=>this.parseMathNode(r));switch(i){case"plus":return`(${t.join(" + ")})`;case"minus":return t.length===1?`-${t[0]}`:`(${t[0]} - ${t[1]})`;case"times":return`(${t.join(" * ")})`;case"divide":return`(${t[0]} / ${t[1]})`;case"eq":return`${t[0]} == ${t[1]}`;case"neq":return`${t[0]} != ${t[1]}`;case"lt":return`${t[0]} < ${t[1]}`;case"leq":return`${t[0]} <= ${t[1]}`;case"gt":return`${t[0]} > ${t[1]}`;case"geq":return`${t[0]} >= ${t[1]}`;case"and":return`${t.join(" and ")}`;case"or":return`${t.join(" or ")}`;case"diff":const r=s.find(l=>l.localName==="bvar"),c=s.find(l=>l.localName!=="diff"&&l.localName!=="bvar"),h=r?.children[0]?.textContent||"t";return`ode(${c?this.parseMathNode(c):"unknown"}, ${h})`;case"sin":case"cos":case"tan":case"exp":case"ln":case"log":return`${i}(${t[0]})`;case"root":return`sqrt(${t[0]})`;default:return`${i}(${t.join(", ")})`}}parsePiecewise(e){let s=[];return Array.from(e?.children||[]).forEach(t=>{if(t.localName==="piece"){const r=this.parseMathNode(t.children[0]),c=this.parseMathNode(t.children[1]);s.push(`${this.standardIndent}case ${c}: ${r};`)}else if(t.localName==="otherwise"){const r=this.parseMathNode(t.children[0]);s.push(`${this.standardIndent}otherwise: ${r};`)}}),`sel
|
|
8
8
|
${this.indent()}${s.join(`
|
|
9
9
|
${this.indent()}`)}
|
|
10
10
|
${this.indent()}endsel`}}class E{convert(e){if(!e)return"";if(e.localName==="math")return Array.from(e.children).map(s=>this.convert(s)).join(`
|
|
11
|
-
`);if(e.localName==="apply"&&e.firstElementChild?.localName==="eq"){const s=Array.from(e.children),i=this.parseNode(s[1]),t=this.parseNode(s[2]);return`${i} = ${t}`}return this.parseNode(e)}parseNode(e){if(!e)return"";const s=e.localName;return s==="apply"?this.parseApply(e):s==="ci"?this.parseIdentifier(e.textContent||""):s==="cn"?e.textContent||"0":s==="piecewise"?this.parsePiecewise(e):""}escapeGreek(e){return["alpha","beta","gamma","delta","epsilon","zeta","eta","theta","iota","kappa","lambda","mu","nu","xi","omicron","pi","rho","sigma","tau","upsilon","phi","chi","psi","omega"].includes(e.toLowerCase())?`\\${e}`:e}parseIdentifier(e){if(!e.includes("_"))return this.escapeGreek(e);const s=e.split("_"),i=this.escapeGreek(s[0]||""),t=[];s[1]&&t.push(s[1]),s.length>4&&t.push(...s.slice(4));let r="";s.length===3&&(s[2]||[]).length===1?t.push(this.escapeGreek(s[2]||"")):s[2]&&(r=this.escapeGreek(s[2]),s[3]&&(r+=`_{${this.escapeGreek(s[3])}}`)),t.forEach((u,l)=>{t[l]=this.escapeGreek(u)});const c=t.join(",");let h=i;return c&&(h+=`_{${c}}`),r&&(h+=`^{${r}}`),h}parseApply(e){const s=Array.from(e?.children||[]),i=s[0]?.localName,t=s.slice(1).map(r=>this.parseNode(r));switch(i){case"plus":return t.join(" + ");case"minus":return t.length===1?`-${t[0]}`:`${t[0]} - ${t[1]}`;case"times":return t.join(" \\cdot ");case"divide":return`\\frac{${t[0]}}{${t[1]}}`;case"eq":return`${t[0]} == ${t[1]}`;case"neq":return`${t[0]} \\neq ${t[1]}`;case"lt":return`${t[0]} < ${t[1]}`;case"leq":return`${t[0]} \\leq ${t[1]}`;case"gt":return`${t[0]} > ${t[1]}`;case"geq":return`${t[0]} \\geq ${t[1]}`;case"and":return t.join(" \\land ");case"or":return t.join(" \\lor ");case"power":const r=s[1],c=t[0]||"",h=t[1];return r?.localName==="ci"||r?.localName==="cn"&&!c.trim().startsWith("-")?`{${c}}^{${h}}`:`\\left({${c}}\\right)^{${h}}`;case"root":case"sqrt":return`\\sqrt{${t[0]}}`;case"diff":const l=s.find(x=>x.localName==="bvar"),p=s.find(x=>x.localName!=="diff"&&x.localName!=="bvar"),d=l?this.parseNode(l.firstElementChild):"x";return`\\frac{d${p?this.parseNode(p):"y"}}{d${d}}`;case"exp":return`e^{${t[0]}}`;case"abs":return`\\left|${t[0]}\\right|`;case"floor":return`\\lfloor ${t[0]} \\rfloor`;case"ceil":return`\\lceil ${t[0]} \\rceil`;case"cos":case"cosh":case"log10":case"log":case"ln":case"max":case"min":case"sin":case"sinh":case"tan":case"tanh":return`\\${i}\\left(${t[0]}\\right)`;default:return console.log(`Unsupported MathML operator: ${i}`),`\\text{${i}}(${t.join(", ")})`}}parsePiecewise(e){let s="";return Array.from(e.children).forEach(t=>{if(t.localName==="piece"){const r=this.parseNode(t.children[0]),c=this.parseNode(t.children[1]);s+=`${r} & \\text{if } ${c} \\\\ `}else if(t.localName==="otherwise"){const r=this.parseNode(t.children[0]);s+=`${r} & \\text{otherwise}`}}),`\\begin{cases} ${s} \\end{cases}`}}m.CellMLLatexGenerator=E,m.CellMLTextGenerator=
|
|
11
|
+
`);if(e.localName==="apply"&&e.firstElementChild?.localName==="eq"){const s=Array.from(e.children),i=this.parseNode(s[1]),t=this.parseNode(s[2]);return`${i} = ${t}`}return this.parseNode(e)}parseNode(e){if(!e)return"";const s=e.localName;return s==="apply"?this.parseApply(e):s==="ci"?this.parseIdentifier(e.textContent||""):s==="cn"?e.textContent||"0":s==="piecewise"?this.parsePiecewise(e):""}escapeGreek(e){return["alpha","beta","gamma","delta","epsilon","zeta","eta","theta","iota","kappa","lambda","mu","nu","xi","omicron","pi","rho","sigma","tau","upsilon","phi","chi","psi","omega"].includes(e.toLowerCase())?`\\${e}`:e}parseIdentifier(e){if(!e.includes("_"))return this.escapeGreek(e);const s=e.split("_"),i=this.escapeGreek(s[0]||""),t=[];s[1]&&t.push(s[1]),s.length>4&&t.push(...s.slice(4));let r="";s.length===3&&(s[2]||[]).length===1?t.push(this.escapeGreek(s[2]||"")):s[2]&&(r=this.escapeGreek(s[2]),s[3]&&(r+=`_{${this.escapeGreek(s[3])}}`)),t.forEach((u,l)=>{t[l]=this.escapeGreek(u)});const c=t.join(",");let h=i;return c&&(h+=`_{${c}}`),r&&(h+=`^{${r}}`),h}parseApply(e){const s=Array.from(e?.children||[]),i=s[0]?.localName,t=s.slice(1).map(r=>this.parseNode(r));switch(i){case"plus":return t.join(" + ");case"minus":return t.length===1?`-${t[0]}`:`${t[0]} - ${t[1]}`;case"times":return t.join(" \\cdot ");case"divide":return`\\frac{${t[0]}}{${t[1]}}`;case"eq":return`${t[0]} == ${t[1]}`;case"neq":return`${t[0]} \\neq ${t[1]}`;case"lt":return`${t[0]} < ${t[1]}`;case"leq":return`${t[0]} \\leq ${t[1]}`;case"gt":return`${t[0]} > ${t[1]}`;case"geq":return`${t[0]} \\geq ${t[1]}`;case"and":return t.join(" \\land ");case"or":return t.join(" \\lor ");case"power":const r=s[1],c=t[0]||"",h=t[1];return r?.localName==="ci"||r?.localName==="cn"&&!c.trim().startsWith("-")?`{${c}}^{${h}}`:`\\left({${c}}\\right)^{${h}}`;case"root":case"sqrt":return`\\sqrt{${t[0]}}`;case"diff":const l=s.find(x=>x.localName==="bvar"),p=s.find(x=>x.localName!=="diff"&&x.localName!=="bvar"),d=l?this.parseNode(l.firstElementChild):"x";return`\\frac{d${p?this.parseNode(p):"y"}}{d${d}}`;case"exp":return`e^{${t[0]}}`;case"abs":return`\\left|${t[0]}\\right|`;case"floor":return`\\lfloor ${t[0]} \\rfloor`;case"ceil":return`\\lceil ${t[0]} \\rceil`;case"cos":case"cosh":case"log10":case"log":case"ln":case"max":case"min":case"sin":case"sinh":case"tan":case"tanh":return`\\${i}\\left(${t[0]}\\right)`;default:return console.log(`Unsupported MathML operator: ${i}`),`\\text{${i}}(${t.join(", ")})`}}parsePiecewise(e){let s="";return Array.from(e.children).forEach(t=>{if(t.localName==="piece"){const r=this.parseNode(t.children[0]),c=this.parseNode(t.children[1]);s+=`${r} & \\text{if } ${c} \\\\ `}else if(t.localName==="otherwise"){const r=this.parseNode(t.children[0]);s+=`${r} & \\text{otherwise}`}}),`\\begin{cases} ${s} \\end{cases}`}}m.CellMLLatexGenerator=E,m.CellMLTextGenerator=C,m.CellMLTextParser=$,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})}));
|
|
@@ -45,5 +45,16 @@ export declare class CellMLTextParser {
|
|
|
45
45
|
private parseFunctionCall;
|
|
46
46
|
private expect;
|
|
47
47
|
private expectValue;
|
|
48
|
+
/**
|
|
49
|
+
* Checks if the element or any of its descendants use a CellML attribute
|
|
50
|
+
* (e.g. cellml:units).
|
|
51
|
+
*/
|
|
52
|
+
private usesCellMLNamespace;
|
|
53
|
+
/**
|
|
54
|
+
* Checks if a specific Namespace URI is declared on this node
|
|
55
|
+
* and returns the prefix used (e.g. 'cellml', 'cellml2', or '' for default).
|
|
56
|
+
* Returns null if not found.
|
|
57
|
+
*/
|
|
58
|
+
private getPrefixForNamespace;
|
|
48
59
|
private serialize;
|
|
49
60
|
}
|