abi.js
Version:
[![typescript-icon]][typescript-link] [![license-icon]][license-link] [![status-icon]][status-link] [![ci-icon]][ci-link] [![twitter-icon]][twitter-link]
443 lines (439 loc) • 11.4 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/view.ts
var view_exports = {};
__export(view_exports, {
Component: () => Component,
Doc: () => Doc,
Element: () => Element,
Node: () => Node,
Slot: () => Slot,
Tag: () => Tag,
Template: () => Template,
Text: () => Text,
Translate: () => Translate,
component: () => component,
doc: () => doc,
element: () => element,
render: () => render,
template: () => template,
text: () => text
});
module.exports = __toCommonJS(view_exports);
// src/parser.ts
function parse_str(val) {
val = val.trim();
const res = /^('|")(.*?)\1$/gms.exec(val);
if (res) {
val = res[2];
}
return val;
}
// src/view.ts
var Doc = class {
constructor(root, type = "html", charset = "UTF-8", version, mode) {
this.root = root;
this.type = type;
this.charset = charset;
if (version === void 0) {
this.version = this.type === "html" ? 5 : 1;
} else {
this.version = version;
}
if (mode === void 0) {
this.mode = "strict";
} else {
this.mode = mode;
}
}
version;
mode;
render(locale) {
let str = "";
switch (this.type) {
case "xml":
str += `<?xml version="${this.version.toFixed(1)}" encoding="${this.charset}"?>
`;
break;
case "xhtml":
if (this.version === 1.1) {
str += `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">`;
} else if (this.version === 1) {
switch (this.mode) {
case "strict":
str += `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">`;
break;
case "frameset":
str += `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">`;
break;
default:
str += `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">`;
}
}
break;
case "html":
if (this.version >= 5) {
str += "<!DOCTYPE html>";
} else if (this.version === 4.01) {
switch (this.mode) {
case "strict":
str += '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">';
break;
case "frameset":
str += '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">';
break;
default:
str += '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';
}
} else if (this.version === 4) {
switch (this.mode) {
case "strict":
str += '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">';
break;
case "frameset":
str += '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">';
break;
default:
str += '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">';
}
} else if (this.version === 3.2) {
str += '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">';
} else if (this.version === 2) {
str += '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">';
} else if (this.version === 1) {
str += '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 1.0//EN">';
}
break;
default:
throw new Error(`Unsupported document type: ${this.type}`);
}
return str + this.root.render(locale);
}
};
var Node = class {
};
var Tag = class extends Node {
constructor(name, ...nodes) {
super();
this.name = name;
this.addNodes(nodes);
}
nodes = [];
addNodes(nodes) {
for (const node of nodes) {
this.addNode(node);
}
return this;
}
addNode(node) {
this.nodes.push(node);
return this;
}
getNodes() {
return this.nodes;
}
getTexts() {
const texts = [];
for (const node of this.nodes) {
if (node instanceof Text) {
texts.push(node);
}
}
return texts;
}
getElements() {
const elements = [];
for (const node of this.nodes) {
if (node instanceof Element) {
elements.push(node);
}
}
return elements;
}
get slot() {
return new Slot(this.nodes);
}
get is_empty() {
return this.slot.is_empty;
}
render(locale) {
return this.open() + this.renderSlot(locale) + this.close();
}
renderSlot(locale) {
return this.slot.render(locale);
}
};
var Component = class extends Tag {
constructor(name, props, ...nodes) {
super(name, ...nodes);
this.props = props;
}
open() {
return `<${this.name}${this.renderProps()}${this.slot.is_empty ? "" : ">"}`;
}
close() {
return this.slot.is_empty ? "/>" : `</${this.name}>`;
}
renderProps() {
let props = "";
for (const prop of Object.entries(this.props)) {
props += ` ${prop[0]}="${prop[1].toString()}"`;
}
return props;
}
};
var Element = class _Element extends Tag {
constructor(name, attrs = {}, ...nodes) {
super(name, ...nodes);
this.attrs = attrs;
}
static ORPHAN = [
"area",
"base",
"basefont",
"br",
"col",
"command",
"embed",
"frame",
"hr",
"img",
"input",
"isindex",
"keygen",
"link",
"meta",
"param",
"source",
"track",
"wbr"
];
static INLINE = [
"a",
"abbr",
"acronym",
"b",
"bdi",
"bdo",
"big",
"br",
"cite",
"code",
"data",
"del",
"dfn",
"em",
"font",
"i",
"img",
"ins",
"kbd",
"map",
"mark",
"object",
"q",
"rp",
"rt",
"rtc",
"ruby",
"s",
"samp",
"small",
"span",
"strike",
"strong",
"sub",
"sup",
"time",
"tt",
"u",
"var"
];
renderAttrs() {
let attrs = "";
for (const attr of Object.entries(this.attrs)) {
attrs += ` ${attr[0]}="${attr[1]}"`;
}
return attrs;
}
open() {
return `<${this.name}${this.renderAttrs()}>`;
}
close() {
return this.is_orphan ? "" : `</${this.name}>`;
}
get is_orphan() {
return _Element.ORPHAN.includes(this.name);
}
get is_paired() {
return !this.is_orphan;
}
get is_inline() {
return _Element.INLINE.includes(this.name);
}
get is_block() {
return !this.is_inline;
}
get is_custom() {
return this.name.includes("-");
}
};
var Slot = class extends Node {
constructor(nodes) {
super();
this.nodes = nodes;
}
get is_empty() {
return this.nodes.length === 0;
}
render(locale) {
let str = "";
for (const node of this.nodes) {
str += node.render(locale);
}
return str;
}
};
var Text = class _Text extends Node {
constructor(value, translations = {}) {
super();
this.value = value;
_Text.setTranslations(value, translations);
}
static locale = "en_US";
static dictionnary = {};
static setTranslations(value, translations) {
for (const translation of Object.entries(translations)) {
_Text.setTranslation(value, translation[0], translation[1]);
}
}
static setTranslation(value, locale, translation) {
if (_Text.dictionnary[value] === void 0) {
_Text.dictionnary[value] = {};
}
_Text.dictionnary[value][locale] = translation;
}
static getTranslation(value, locale) {
return _Text.getTranslations(value)[locale];
}
static getTranslations(value) {
const translations = _Text.dictionnary[value];
if (!translations) {
for (const [defaultValue, translations2] of Object.entries(
_Text.dictionnary
)) {
for (const translation of Object.values(translations2)) {
if (value === translation) {
translations2[_Text.locale] = defaultValue;
return translations2;
}
}
}
}
return translations;
}
static translate(value) {
const translations = _Text.getTranslations(value);
return Translate.from(translations);
}
translateTo(locale) {
return _Text.getTranslation(this.value, locale) ?? this.value;
}
render(locale) {
return locale ? this.translateTo(locale) : this.value;
}
};
var Translate = class _Translate {
constructor(translations) {
this.translations = translations;
}
static from(translations) {
return new _Translate(translations);
}
to(locale) {
return this.translations[locale];
}
};
var Template = class {
constructor(content) {
this.content = content;
}
render(locale) {
const content = this.content.toString();
const ID = "[a-zA-Z]+[a-zA-Z0-9-_]*";
const SINGLE_QUOTE_STR = "'(?:\\'|[^'])*'";
const DOUBLE_QUOTE_STR = '"(?:\\"|[^"])*"';
const STR = `${SINGLE_QUOTE_STR}|${DOUBLE_QUOTE_STR}`;
const ATTR = `(${ID})\\s*=\\s*(${STR})\\s*`;
const ATTRS = `${ATTR}(?:\\s*${ATTR})*`;
const ATTRS_BLOCK = `\\[(${ATTRS})\\]`;
const ELT = `(${ID})\\s*${ATTRS_BLOCK}`;
const ELT_BLOCK = `${ELT}\\s*\\{\\s*(.*?)\\s*\\}`;
const elt_m = RegExp(ELT_BLOCK).exec(content);
if (elt_m) {
const attrs = {};
let attrs_str = elt_m[2] || "";
let attrs_m = RegExp(ATTR, "gm").exec(attrs_str);
while (attrs_m) {
attrs[attrs_m[1]] = parse_str(attrs_m[2]);
attrs_str = attrs_str.replace(attrs_m[0], "");
attrs_m = RegExp(ATTR, "gm").exec(attrs_str);
}
const elt = element(elt_m[1], attrs, text(elt_m[7]));
return elt.render(locale);
}
return content;
}
};
function doc(root, type = "html", charset = "UTF-8", version, mode) {
return new Doc(root, type, charset, version, mode);
}
function text(value, translations = {}) {
return new Text(value, translations);
}
function component(name, props = {}, ...nodes) {
return new Component(name, props, ...nodes);
}
function element(name, attrs = {}, ...nodes) {
return new Element(name, attrs, ...nodes);
}
function template(content) {
return new Template(content);
}
function render(node, locale) {
return node.render(locale);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Component,
Doc,
Element,
Node,
Slot,
Tag,
Template,
Text,
Translate,
component,
doc,
element,
render,
template,
text
});