UNPKG

@fmlang/fml-to-schema

Version:

Convert Forms Markup Language (FML) to jsonv-ts (JSON Schema)

1,604 lines (1,586 loc) 53.9 kB
// @bun // node_modules/@fmlang/tokenizer/lib/main.js class Result { value; error; constructor(value, error) { this.value = value; this.error = error; } IsError() { return this.error != null || this.value == null; } HasValue() { return this.value != null; } } class Token { token_type; lexeme; literal; line; constructor(token_type, lexeme, literal, line) { this.token_type = token_type; this.lexeme = lexeme; this.literal = literal; this.line = line; } } var TokenType = { IDENTIFIER: 0, STRING: 1, NUMBER: 2, MARKDOWN: 3, ASTERISK: 4, COMMA: 5, DOT: 6, MINUS: 7, PLUS: 8, SEMICOLON: 9, FORWARD_SLASH: 10, BACK_SLASH: 11, POUND: 12, LEFT_BRACE: 13, RIGHT_BRACE: 14, LEFT_BRACKET: 15, RIGHT_BRACKET: 16, LEFT_PARENTHESIS: 17, RIGHT_PARENTHESIS: 18, EXCLAMATION_POINT: 19, EXCLAMATION_POINT_EQUAL: 20, EQUAL: 21, EQUAL_EQUAL: 22, GREATER_THAN: 23, GREATER_THAN_EQUAL: 24, LESS_THAN: 25, LESS_THAN_EQUAL: 26, AND: 27, ELSE: 28, FALSE: 29, LOOP: 30, IF: 31, OR: 32, PRINT: 33, RETURN: 34, TRUE: 35, LET: 36, CONST: 37, EOL: 99, EOF: 100 }; var KeywordMap = { and: TokenType.AND, else: TokenType.ELSE, false: TokenType.FALSE, loop: TokenType.LOOP, if: TokenType.IF, or: TokenType.OR, print: TokenType.PRINT, return: TokenType.RETURN, true: TokenType.TRUE, let: TokenType.LET, const: TokenType.CONST }; class Tokenizer { tokens = []; start = 0; current = 0; line = 1; source = ""; constructor(fml) { this.source = fml; this.start = 0; this.tokens = []; this.current = 0; this.line = 1; } Tokenize() { while (!this.IsAtEnd()) { this.start = this.current; this.ScanToken(); } this.tokens.push(new Token(TokenType.EOF, "", null, this.line)); return new Result(this.tokens, null); } IsAtEnd() { return this.current >= this.source.length; } ScanToken() { let c = this.Advance(); switch (c) { case "(": this.AddToken(TokenType.LEFT_PARENTHESIS); break; case ")": this.AddToken(TokenType.RIGHT_PARENTHESIS); break; case "{": this.AddToken(TokenType.LEFT_BRACE); break; case "}": this.AddToken(TokenType.RIGHT_BRACE); break; case "[": this.AddToken(TokenType.LEFT_BRACKET); break; case "]": this.AddToken(TokenType.RIGHT_BRACKET); break; case ",": this.AddToken(TokenType.COMMA); break; case ".": this.AddToken(TokenType.DOT); break; case "-": this.AddToken(TokenType.MINUS); break; case "+": this.AddToken(TokenType.PLUS); break; case "*": this.AddToken(TokenType.ASTERISK); break; case "": this.AddToken(TokenType.SEMICOLON); break; case "!": this.AddToken(this.MatchNext("=") ? TokenType.EXCLAMATION_POINT_EQUAL : TokenType.EXCLAMATION_POINT); break; case "=": this.AddToken(this.MatchNext("=") ? TokenType.EQUAL_EQUAL : TokenType.EQUAL); break; case "<": this.AddToken(this.MatchNext("=") ? TokenType.LESS_THAN_EQUAL : TokenType.LESS_THAN); break; case ">": this.AddToken(this.MatchNext("=") ? TokenType.GREATER_THAN_EQUAL : TokenType.GREATER_THAN); break; case "/": { if (this.MatchNext("/")) { while (this.PeekNext() != ` ` && !this.IsAtEnd()) { this.Advance(); } } else { this.AddToken(TokenType.FORWARD_SLASH); } break; } case "#": { if (this.MatchNext("{")) { this.ReadMarkdown(); } this.AddToken(TokenType.POUND); break; } case '"': { this.ReadString(); break; } case " ": case "\r": case "\t": break; case ` `: this.line++; break; default: if (this.IsDigit(c)) { this.ReadNumber(); } else if (this.IsAlpha(c)) { this.ReadIdentifier(); } else { throw new Error(`Unexpected character ${c}`); } break; } } Advance() { this.current++; return this.source[this.current - 1]; } MatchNext(expected) { if (this.IsAtEnd()) return false; if (this.source[this.current] != expected) return false; this.current++; return true; } IsDigit(lexeme) { return lexeme >= "0" && lexeme <= "9"; } ReadNumber() { while (this.IsDigit(this.PeekNext())) { this.Advance(); } if (this.PeekNext() == "." && this.IsDigit(this.PeekNext(1))) { this.Advance(); while (this.IsDigit(this.PeekNext())) { this.Advance(); } } let num = parseFloat(this.source.substring(this.start, this.current)); this.AddToken(TokenType.NUMBER, num); } PeekNext(offset = 0) { if (this.IsAtEnd()) return "\x00"; return this.source[this.current + offset]; } ReadString() { while (this.PeekNext() != '"' && !this.IsAtEnd()) { let next = this.PeekNext(); if (this.PeekNext() == "\\" && this.PeekNext(1) == '"') { this.Advance(); } if (this.PeekNext() == ` `) { this.line++; } this.Advance(); } if (this.IsAtEnd()) { throw new Error("Unterminated string on line " + this.line); } this.Advance(); let value = this.source.substring(this.start + 1, this.current - 1); value = value.replace(/\\"/g, '"'); this.AddToken(TokenType.STRING, value); } IsAlpha(c) { return c >= "a" && c <= "z" || c >= "A" && c <= "Z" || c == "_"; } IsAlphaNumeric(c) { return this.IsAlpha(c) || this.IsDigit(c); } ReadIdentifier() { while (this.IsAlphaNumeric(this.PeekNext())) { this.Advance(); } let text = this.source.substring(this.start, this.current); let token_type = KeywordMap[text] || TokenType.IDENTIFIER; this.AddToken(token_type); } AddToken(token_type, literal = null) { let text = this.source.substring(this.start, this.current); this.tokens.push(new Token(token_type, text, literal, this.line)); } ReadMarkdown() { while (!this.IsAtEnd()) { if (this.PeekNext() != "}") { this.Advance(); } else { if (this.PeekNext(1) == "#") { break; } else { if (this.IsAtEnd()) { throw new Error(`Unterminated markdown on line ${this.line}: ${this.source.substring(this.start)}`); } this.Advance(); } } } if (this.IsAtEnd()) { throw new Error(`Unterminated markdown on line ${this.line}: ${this.source.substring(this.start)}`); } if (!this.MatchNext("}")) { throw new Error(`Unterminated markdown on line ${this.line}: ${this.source.substring(this.start)}`); } if (!this.MatchNext("#")) { throw new Error(`Unterminated markdown on line ${this.line}: ${this.source.substring(this.start)}`); } let value = this.source.substring(this.start + 2, this.current - 2); value = value.trim().split(` `).map((line) => line.trim()).join(` `); this.AddToken(TokenType.MARKDOWN, value); this.line += value.split(` `).length + 1; this.start = this.current; } } // node_modules/@fmlang/parser/lib/main.js class Expr { } class Attribute extends Expr { left; right; line_number; constructor(left, right, line_number) { super(); this.left = left; this.right = right; this.line_number = line_number; } accept(visitor) { return visitor.visitAttributeExpr(this); } } class Control extends Expr { identifier; attributes; line_number; constructor(identifier, attributes, line_number) { super(); this.identifier = identifier; this.attributes = attributes; this.line_number = line_number; } accept(visitor) { return visitor.visitControlExpr(this); } } class Identifier extends Expr { name; line_number; constructor(name, line_number) { super(); this.name = name; this.line_number = line_number; } accept(visitor) { return visitor.visitIdentifierExpr(this); } } class Container extends Expr { identifier; attributes; children; line_number; constructor(identifier, attributes, children, line_number) { super(); this.identifier = identifier; this.attributes = attributes; this.children = children; this.line_number = line_number; } accept(visitor) { return visitor.visitContainerExpr(this); } } class Literal extends Expr { value; line_number; constructor(value, line_number) { super(); this.value = value; this.line_number = line_number; } accept(visitor) { return visitor.visitLiteralExpr(this); } } class Markdown extends Expr { attributes; value; line_number; constructor(attributes, value, line_number) { super(); this.attributes = attributes; this.value = value; this.line_number = line_number; } accept(visitor) { return visitor.visitMarkdownExpr(this); } } class Select extends Expr { identifier; attributes; children; line_number; constructor(identifier, attributes, children, line_number) { super(); this.identifier = identifier; this.attributes = attributes; this.children = children; this.line_number = line_number; } accept(visitor) { return visitor.visitSelectExpr(this); } } class Radio extends Expr { identifier; attributes; children; line_number; constructor(identifier, attributes, children, line_number) { super(); this.identifier = identifier; this.attributes = attributes; this.children = children; this.line_number = line_number; } accept(visitor) { return visitor.visitRadioExpr(this); } } class CheckList extends Expr { identifier; attributes; children; line_number; constructor(identifier, attributes, children, line_number) { super(); this.identifier = identifier; this.attributes = attributes; this.children = children; this.line_number = line_number; } accept(visitor) { return visitor.visitCheckListExpr(this); } } class Result2 { value; error; constructor(value, error) { this.value = value; this.error = error; } IsError() { return this.error != null || this.value == null; } HasValue() { return this.value != null; } } var TokenType2 = { IDENTIFIER: 0, STRING: 1, NUMBER: 2, MARKDOWN: 3, ASTERISK: 4, COMMA: 5, DOT: 6, MINUS: 7, PLUS: 8, SEMICOLON: 9, FORWARD_SLASH: 10, BACK_SLASH: 11, POUND: 12, LEFT_BRACE: 13, RIGHT_BRACE: 14, LEFT_BRACKET: 15, RIGHT_BRACKET: 16, LEFT_PARENTHESIS: 17, RIGHT_PARENTHESIS: 18, EXCLAMATION_POINT: 19, EXCLAMATION_POINT_EQUAL: 20, EQUAL: 21, EQUAL_EQUAL: 22, GREATER_THAN: 23, GREATER_THAN_EQUAL: 24, LESS_THAN: 25, LESS_THAN_EQUAL: 26, AND: 27, ELSE: 28, FALSE: 29, LOOP: 30, IF: 31, OR: 32, PRINT: 33, RETURN: 34, TRUE: 35, LET: 36, CONST: 37, EOL: 99, EOF: 100 }; var KeywordMap2 = { and: TokenType2.AND, else: TokenType2.ELSE, false: TokenType2.FALSE, loop: TokenType2.LOOP, if: TokenType2.IF, or: TokenType2.OR, print: TokenType2.PRINT, return: TokenType2.RETURN, true: TokenType2.TRUE, let: TokenType2.LET, const: TokenType2.CONST }; class Parser { tokens; current = 0; constructor(tokens) { this.tokens = tokens; } Parse() { let expr = this.root(); return new Result2(expr, null); } root() { return this.container(); } container() { let identifier = this.identifier(); if (identifier == null) { return null; } let attributes = this.attributes(); if (attributes == null) { this.current--; return null; } let elements = this.elements(); if (elements == null) { for (const attribute of attributes) { this.current = this.current - 3; } return null; } let line_number = this.peek_at_previous().line; return new Container(identifier, attributes, elements, line_number); } identifier() { const line_number = this.peek_at_current().line; if (this.match(TokenType2.IDENTIFIER)) { return new Identifier(this.tokens[this.current - 1].lexeme, line_number); } return null; } attributes() { if (this.match(TokenType2.LEFT_PARENTHESIS)) { let attributes = this.attribute(); if (this.match(TokenType2.RIGHT_PARENTHESIS)) { return attributes || []; } } return null; } attribute() { let attributes = []; let left = this.identifier(); let equal = this.match(TokenType2.EQUAL); let right = this.literal(); if (left == null || right == null) { return null; } while (left != null && right != null) { let line_number = this.peek_at_previous().line; attributes.push(new Attribute(left, right, line_number)); left = this.identifier(); equal = this.match(TokenType2.EQUAL); right = this.literal(); } return attributes; } elements() { if (this.match(TokenType2.LEFT_BRACE)) { let children = this.element(); this.match(TokenType2.RIGHT_BRACE); return children; } return null; } element() { let result = []; let identifier = this.identifier(); if (identifier == null) { return null; } let attributes = this.attributes(); if (attributes == null) { return null; } let peeked = this.peek_at_current(); let elements = this.elements(); if (this.match(TokenType2.MARKDOWN)) { this.advance(); this.advance(); let markdown = peeked.literal; const line_number = this.peek_at_previous().line; result.push(new Markdown(attributes, markdown, line_number)); } else if (this.peek_at_current().token_type == TokenType2.LEFT_BRACKET) { let children = this.read_list(); if (children == null) { throw new Error("Expected list of children on line " + this.peek_at_current().line); } let id = identifier; const line_number = this.peek_at_previous().line; switch (id.name) { case "select": result.push(new Select(identifier, attributes, children, line_number)); break; case "radio": result.push(new Radio(identifier, attributes, children, line_number)); break; case "checklist": result.push(new CheckList(identifier, attributes, children, line_number)); break; default: result.push(new Select(identifier, attributes, children, line_number)); break; } } else if (elements == null) { const line_number = this.peek_at_previous().line; result.push(new Control(identifier, attributes, line_number)); } else { const line_number = this.peek_at_previous().line; result.push(new Container(identifier, attributes, elements, line_number)); } while (true) { identifier = this.identifier(); if (identifier == null) { return result; } attributes = this.attributes(); if (attributes == null) { return result; } let peeked2 = this.peek_at_current(); elements = this.elements(); const line_number = this.peek_at_previous().line; if (peeked2.token_type == TokenType2.MARKDOWN) { this.advance(); this.advance(); let markdown = peeked2.literal; result.push(new Markdown(attributes, markdown, line_number)); } else if (this.peek_at_current().token_type == TokenType2.LEFT_BRACKET) { let children = this.read_list(); if (children == null) { throw new Error("Expected list of children on line " + this.peek_at_current().line); } let id = identifier; switch (id.name) { case "select": result.push(new Select(identifier, attributes, children, line_number)); break; case "radio": result.push(new Radio(identifier, attributes, children, line_number)); break; case "checklist": result.push(new CheckList(identifier, attributes, children, line_number)); break; default: result.push(new Select(identifier, attributes, children, line_number)); break; } } else if (elements == null) { result.push(new Control(identifier, attributes, line_number)); } else { result.push(new Container(identifier, attributes, elements, line_number)); } } } match(...token_types) { for (let token_type of token_types) { if (this.check(token_type)) { this.advance(); return true; } } return false; } check(token_type) { if (this.is_at_end()) { return false; } let peeked = this.peek_at_current(); return peeked.token_type == token_type; } advance() { if (!this.is_at_end()) { this.current++; } } is_at_end() { const peeked = this.peek_at_current(); if (peeked == null) { return true; } return peeked.token_type == TokenType2.EOF; } peek_at_current() { return this.tokens[this.current]; } peek_at_previous() { return this.tokens[this.current - 1]; } peek_at_next() { return this.tokens[this.current + 1]; } literal() { let literal_types = [TokenType2.STRING, TokenType2.NUMBER, TokenType2.TRUE, TokenType2.FALSE]; for (let token_type of literal_types) { if (this.check(token_type)) { this.advance(); let previous = this.peek_at_previous(); let line_number = previous.line; return new Literal(previous, line_number); } } return null; } control() { let identifier = this.identifier(); let attributes = this.attributes(); if (identifier == null || attributes == null) { return null; } this.match(TokenType2.EOL); const line_number = this.peek_at_previous().line; return new Control(identifier, attributes, line_number); } read_list() { let items = []; this.match(TokenType2.LEFT_BRACKET); while (!this.check(TokenType2.RIGHT_BRACKET)) { let item = this.literal(); if (item == null) { return null; } items.push(item); this.match(TokenType2.COMMA); } this.match(TokenType2.RIGHT_BRACKET); return items; } } // node_modules/jsonv-ts/dist/lib/index.js var C = Symbol.for("kind"); var A = Symbol.for("optional"); var b = Symbol.for("raw"); var O = class extends Error { constructor(t) { super(`Expected ${t}`); } }; var E = class extends Error { constructor(n, r) { super(`${n}, got: '${JSON.stringify(r)}'`); this.value = r; } }; function M(e) { return e === null; } function p(e) { return !Array.isArray(e) && typeof e == "object" && e !== null; } function l(e) { return typeof e == "string"; } function h(e) { return typeof e == "number"; } function q(e) { return typeof e == "number" && Number.isInteger(e); } function g(e) { return typeof e == "boolean"; } function y(e) { return Array.isArray(e); } function L(e) { return typeof e == "string" && /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(e); } function d(e) { return p(e) && C in e; } function K(e) { return d(e) && g(e[b]); } function N(e, t, n) { if (!e) throw new E(t, n); } function x(e) { if (y(e)) return e.map(x).sort(); if (p(e)) { let t = Object.entries(e).sort(([n], [r]) => n.localeCompare(r)).map(([n, r]) => [n, x(r)]); return Object.fromEntries(t); } return l(e) ? e.normalize("NFC") : e; } var z = (e = [], t = "") => "/" + [t, ...e.map((n) => String(n).replace(/\./g, "/"))].filter(Boolean).join("/"); var ze = (e) => e.split("/").slice(1); function D(e, t, n = undefined) { let r = typeof t == "string" ? ze(t) : z(t); return _(e, r, n); } function _(e, t, n = undefined) { let r = typeof t == "string" ? t.split(/[.\[\]\"]+/).filter((o) => o) : t; if (r.length === 0) return e; try { let [o, ...i] = r; return !o || !(o in e) ? n : _(e[o], i, n); } catch { if (typeof n < "u") return n; throw new Error(`Invalid path: ${r.join(".")}`); } } var c = (e = {}, t, n, r) => ({ valid: false, errors: [...e.errors ?? [], { keywordLocation: z([...e.keywordPath ?? [], t]), instanceLocation: z(e.instancePath), error: typeof n == "string" ? n : `Invalid value for ${t}`, data: r }] }); var a = () => ({ valid: true, errors: [] }); var w = (e, t, n) => { let r = Array.isArray(t) ? t : [t], o = n ? Array.isArray(n) ? n : [n] : []; return { ...e, keywordPath: [...e.keywordPath ?? [], ...r], instancePath: o ? [...e.instancePath ?? [], ...o] : e.instancePath }; }; var j = (e = {}) => ({ ...e, errors: [] }); var H = ({ type: e }, t, n = {}) => { if (e === undefined) return a(); let r, o = { string: l, number: h, integer: q, object: p, array: y, boolean: g, null: M }; if (Array.isArray(e)) { for (let i of e) { if (!(i in o)) throw new O(`Unknown type: ${i}`); if (o[i](t)) return a(); } r = `Expected one of: ${e.join(", ")}`; } else { if (!(e in o)) throw new O(`Unknown type: ${e}`); o[e](t) || (r = `Expected ${e}`); } return r ? c(n, "type", r, t) : a(); }; var W = ({ const: e }, t, n = {}) => { let r = JSON.stringify(x(e)), o = JSON.stringify(x(t)); return r !== o ? c(n, "const", `Expected const: ${r}`, o) : a(); }; var Y = ({ enum: e = [] }, t, n = {}) => { let r = JSON.stringify(e.map(x)), o = JSON.stringify(x(t)); return r.includes(o) ? a() : c(n, "enum", `Expected enum: ${r}`, t); }; function $(e, t, n = {}) { return e.map((r) => r.validate(t, j(n)).valid ? r : undefined).filter(Boolean); } var Z = ({ anyOf: e = [] }, t, n = {}) => $(e, t, n).length > 0 ? a() : c(n, "anyOf", "Expected at least one to match", t); var G = ({ oneOf: e = [] }, t, n = {}) => $(e, t).length === 1 ? a() : c(n, "oneOf", "Expected exactly one to match", t); var Q = ({ allOf: e = [] }, t, n = {}) => $(e, t, n).length === e.length ? a() : c(n, "allOf", "Expected all to match", t); var X = ({ not: e }, t, n = {}) => d(e) && e.validate(t, n).valid ? c(n, "not", "Expected not to match", t) : a(); var ee = ({ if: e, then: t, else: n }, r, o = {}) => { if (e && (t || n)) { if (e.validate(r, j(o)).valid) return t ? t.validate(r, j(o)) : a(); if (n) return n.validate(r, j(o)); } return a(); }; var te = ({ pattern: e = "" }, t, n = {}) => l(t) ? new RegExp(e, "u").test(t) ? a() : c(n, "pattern", `Expected string matching pattern ${e}`, t) : a(); var ne = ({ minLength: e = 0 }, t, n = {}) => l(t) ? [...x(t)].length >= e ? a() : c(n, "minLength", `Expected string with minimum length of ${e}`, t) : a(); var re = ({ maxLength: e = 0 }, t, n = {}) => l(t) ? [...x(t)].length <= e ? a() : c(n, "maxLength", `Expected string with maximum length of ${e}`, t) : a(); var oe = ({ multipleOf: e = 0 }, t, n = {}) => { if (!h(t)) return a(); if (!(Number.isFinite(t) && Number.isFinite(e)) || e <= 0) throw new O("number"); let r = t / e, o = Number.EPSILON * Math.max(1, Math.abs(r)); return Math.abs(r - Math.round(r)) <= o ? a() : c(n, "multipleOf", `Expected number being a multiple of ${e}`, t); }; var ie = ({ maximum: e = 0 }, t, n = {}) => !h(t) || t <= e ? a() : c(n, "maximum", `Expected number less than or equal to ${e}`, t); var ae = ({ exclusiveMaximum: e = 0 }, t, n = {}) => !h(t) || t < e ? a() : c(n, "exclusiveMaximum", `Expected number less than ${e}`, t); var se = ({ minimum: e = 0 }, t, n = {}) => !h(t) || t >= e ? a() : c(n, "minimum", `Expected number greater than or equal to ${e}`, t); var ce = ({ exclusiveMinimum: e = 0 }, t, n = {}) => !h(t) || t > e ? a() : c(n, "exclusiveMinimum", `Expected number greater than ${e}`, t); var me = ({ properties: e = {} }, t, n = {}) => { if (!p(t)) return a(); for (let [r, o] of Object.entries(t)) { let i = e[r]; if (!d(i)) continue; let s = i.validate(o, w(n, ["properties", r], r)); if (!s.valid) return s; } return a(); }; var pe = ({ properties: e = {}, additionalProperties: t, patternProperties: n }, r, o = {}) => { if (!p(r)) return a(); if (!d(t)) throw new O("additionalProperties must be a boolean or a managed schema"); let i = Object.keys(e), s = p(n) ? Object.keys(r).filter((u) => Object.keys(n).some((S) => new RegExp(S).test(u))) : [], f = Object.keys(r).filter((u) => !i.includes(u) && !s.includes(u)); if (f.length > 0) { if (K(t)) return t.validate(undefined); if (d(t)) for (let u of f) { let S = t.validate(r[u], w(o, ["additionalProperties"], u)); if (!S.valid) return S; } } return a(); }; var fe = ({ dependentRequired: e }, t, n = {}) => { if (!p(t)) return a(); let r = Object.keys(t).filter((o) => typeof t[o] != "function"); if (p(e)) { for (let [o, i] of Object.entries(e)) if (r.includes(o)) { for (let s of i) if (!r.includes(s)) return c(n, "dependentRequired", `Expected dependent required property ${s}`, t); } } return a(); }; var ue = ({ required: e = [] }, t, n = {}) => { if (!p(t)) return a(); let r = Object.keys(t).filter((o) => typeof t[o] != "function"); return e.every((o) => r.includes(o)) ? a() : c(n, "required", `Expected object with required properties ${e.join(", ")}`, t); }; var de = ({ dependentSchemas: e }, t, n = {}) => { if (!p(t)) return a(); let r = Object.keys(t).filter((o) => typeof t[o] != "function"); if (p(e)) { for (let [o, i] of Object.entries(e)) if (r.includes(o)) { let s = i.validate(t, n); if (!s.valid) return s; } } return a(); }; var le = ({ minProperties: e = 0 }, t, n = {}) => p(t) ? Object.keys(t).length >= e ? a() : c(n, "minProperties", `Expected object with at least ${e} properties`, t) : a(); var he = ({ maxProperties: e = 0 }, t, n = {}) => !p(t) || Object.keys(t).length <= e ? a() : c(n, "maxProperties", `Expected object with at most ${e} properties`, t); var ye = ({ patternProperties: e = {} }, t, n = {}) => { if (!p(t)) return a(); if (!p(e)) throw new O("patternProperties must be an object"); for (let [r, o] of Object.entries(t)) for (let [i, s] of Object.entries(e)) if (new RegExp(i, "u").test(r)) { let f = s.validate(o, w(n, ["patternProperties"], r)); if (!f.valid) return f; } return a(); }; var Se = ({ propertyNames: e }, t, n = {}) => { if (!p(t) || e === undefined) return a(); if (!d(e)) throw new O("propertyNames must be a managed schema"); for (let r of Object.keys(t)) { let o = e.validate(r, w(n, ["propertyNames"], r)); if (!o.valid) return o; } return a(); }; var Te = ({ items: e, prefixItems: t = [] }, n, r = {}) => { if (!y(n) || e === undefined) return a(); if (!d(e)) throw new O("items must be a managed schema"); for (let [o, i] of n.slice(t.length).entries()) { let s = e.validate(i, w(r, ["items"], String(o))); if (!s.valid) return s; } return a(); }; var Oe = ({ minItems: e = 0 }, t, n = {}) => !y(t) || t.length >= e ? a() : c(n, "minItems", `Expected array with at least ${e} items`, t); var xe = ({ maxItems: e = 0 }, t, n = {}) => !y(t) || t.length <= e ? a() : c(n, "maxItems", `Expected array with at most ${e} items`, t); var be = ({ uniqueItems: e = false }, t, n = {}) => { if (!y(t) || !e) return a(); let r = t.map(x); return new Set(r.map((o) => JSON.stringify(o))).size === t.length ? a() : c(n, "uniqueItems", "Expected array with unique items", t); }; var ge = ({ contains: e, minContains: t, maxContains: n }, r, o = {}) => { if (!d(e)) throw new Error("contains must be a managed schema"); if (!y(r)) return a(); let i = r.filter((s) => e.validate(s).valid).length; return i < (t ?? 1) ? c(o, t ? "minContains" : "contains", `Expected array to contain at least ${t ?? 1}, but found ${i}`, r) : n !== undefined && i > n ? c(o, "maxContains", `Expected array to contain at most ${n}, but found ${i}`, r) : a(); }; var we = ({ prefixItems: e = [] }, t, n = {}) => { if (!y(t)) return a(); for (let r = 0;r < t.length; r++) { let o = e[r]?.validate(t[r], w(n, String(r), String(r))); if (o && o?.valid !== true) return o; } return a(); }; var ke = { email: (e) => { if (e.length > 318) return false; if (/^[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,20}(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,21}){0,2}@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,60}[a-z0-9])?){0,3}$/i.test(e)) return true; if (!e.includes("@") || /(^\.|^"|\.@|\.\.)/.test(e)) return false; let [n, r, ...o] = e.split("@"); return !n || !r || o.length !== 0 || n.length > 64 || r.length > 253 || !/^[a-z0-9.-]+$/i.test(r) || !/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+$/i.test(n) ? false : r.split(".").every((i) => /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/i.test(i)); }, hostname: (e) => e.length > (e.endsWith(".") ? 254 : 253) ? false : /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*\.?$/i.test(e), date: (e) => { if (e.length !== 10) return false; if (e[5] === "0" && e[6] === "2") { if (/^\d\d\d\d-02-(?:[012][1-8]|[12]0|[01]9)$/.test(e)) return true; let t = e.match(/^(\d\d\d\d)-02-29$/); if (!t) return false; let n = Number(t[1]); return n % 16 === 0 || n % 4 === 0 && n % 25 !== 0; } return e.endsWith("31") ? /^\d\d\d\d-(?:0[13578]|1[02])-31$/.test(e) : /^\d\d\d\d-(?:0[13-9]|1[012])-(?:[012][1-9]|[123]0)$/.test(e); }, time: (e) => { if (e.length > 27 || !/^(?:2[0-3]|[0-1]\d):[0-5]\d:(?:[0-5]\d|60)(?:\.\d+)?(?:z|[+-](?:2[0-3]|[0-1]\d)(?::?[0-5]\d)?)?$/i.test(e)) return false; if (!/:60/.test(e)) return true; let n = e.match(/([0-9.]+|[^0-9.])/g); if (!n) return false; let r = Number(n[0]) * 60 + Number(n[2]); return n[5] === "+" ? r += 24 * 60 - Number(n[6] || 0) * 60 - Number(n[8] || 0) : n[5] === "-" && (r += Number(n[6] || 0) * 60 + Number(n[8] || 0)), r % (24 * 60) === 23 * 60 + 59; }, "date-time": (e) => { if (e.length > 38) return false; let t = /^\d\d\d\d-(?:0[1-9]|1[0-2])-(?:[0-2]\d|3[01])[t\s](?:2[0-3]|[0-1]\d):[0-5]\d:(?:[0-5]\d|60)(?:\.\d+)?(?:z|[+-](?:2[0-3]|[0-1]\d)(?::?[0-5]\d)?)$/i, n = e[5] === "0" && e[6] === "2"; if (n && e[8] === "3" || !t.test(e)) return false; if (e[17] === "6") { let r = e.slice(11).match(/([0-9.]+|[^0-9.])/g); if (!r) return false; let o = Number(r[0]) * 60 + Number(r[2]); if (r[5] === "+" ? o += 24 * 60 - Number(r[6] || 0) * 60 - Number(r[8] || 0) : r[5] === "-" && (o += Number(r[6] || 0) * 60 + Number(r[8] || 0)), o % (24 * 60) !== 23 * 60 + 59) return false; } if (n) { if (/^\d\d\d\d-02-(?:[012][1-8]|[12]0|[01]9)/.test(e)) return true; let r = e.match(/^(\d\d\d\d)-02-29/); if (!r) return false; let o = Number(r[1] ?? 0); return o % 16 === 0 || o % 4 === 0 && o % 25 !== 0; } return e[8] === "3" && e[9] === "1" ? /^\d\d\d\d-(?:0[13578]|1[02])-31/.test(e) : /^\d\d\d\d-(?:0[13-9]|1[012])-(?:[012][1-9]|[123]0)/.test(e); }, ipv4: (e) => e.length <= 15 && /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d\d?)$/.test(e), ipv6: (e) => { if (e.length > 45 || e.length < 2) return false; let t = 0, n = 0, r = 0, o = false, i = false, s = 0, f = true; for (let S = 0;S < e.length; S++) { let T = e.charCodeAt(S); if (S === 1 && s === 58 && T !== 58) return false; if (T >= 48 && T <= 57) { if (++r > 4) return false; } else if (T === 46) { if (t > 6 || n >= 3 || r === 0 || i) return false; n++, r = 0; } else if (T === 58) { if (n > 0 || t >= 7) return false; if (s === 58) { if (o) return false; o = true; } else S === 0 && (f = false); t++, r = 0, i = false; } else if (T >= 97 && T <= 102 || T >= 65 && T <= 70) { if (n > 0 || ++r > 4) return false; i = true; } else return false; s = T; } if (t < 2 || n > 0 && (n !== 3 || r === 0)) return false; if (o && e.length === 2) return true; if (n > 0 && !/(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/.test(e)) return false; let u = n > 0 ? 6 : 7; return o ? (f || r > 0) && t < u : t === u && f && r > 0; }, uri: (e) => /^[a-z][a-z0-9+\-.]*:(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/?(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i.test(e), "uri-reference": (e) => /^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/?(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i.test(e), "uri-template": (e) => /^(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2}|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i.test(e), "json-pointer": (e) => /^(?:|\/(?:[^~]|~0|~1)*)$/.test(e), "relative-json-pointer": (e) => /^(?:0|[1-9][0-9]*)(?:|#|\/(?:[^~]|~0|~1)*)$/.test(e), uuid: (e) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(e), duration: (e) => e.length > 1 && e.length < 80 && (/^P\d+([.,]\d+)?W$/.test(e) || /^P[\dYMDTHS]*(\d[.,]\d+)?[YMDHS]$/.test(e) && /^P([.,\d]+Y)?([.,\d]+M)?([.,\d]+D)?(T([.,\d]+H)?([.,\d]+M)?([.,\d]+S)?)?$/.test(e)), regex: (e) => { if (/[^\\]\\Z/.test(e)) return false; try { return new RegExp(e, "u"), true; } catch { return false; } } }; var $e = ({ format: e }, t, n = {}) => !l(t) || !e ? a() : ke[e] ? ke[e](t) ? a() : c(n, "format", `Expected format: ${e}`, t) : a(); var k = class { constructor(t) { this.root = t; this.cache = new Map; } cache; hasRef(t, n) { return n !== undefined && "$ref" in t && l(t.$ref); } resolve(t) { let n = this.cache.get(t); if (!n) { if (n = D(this.root, t), !d(n)) throw new Error(`ref not found: ${t}`); if ("$ref" in n && n.$ref === t) throw new Error(`ref loop: ${t}`); this.cache.set(t, n); } return n; } }; var Be = { type: H, const: W, enum: Y, allOf: Q, anyOf: Z, oneOf: G, not: X, minLength: ne, maxLength: re, pattern: te, format: $e, minimum: se, exclusiveMinimum: ce, maximum: ie, exclusiveMaximum: ae, multipleOf: oe, required: ue, dependentRequired: fe, dependentSchemas: de, minProperties: le, maxProperties: he, propertyNames: Se, properties: me, patternProperties: ye, additionalProperties: pe, minItems: Oe, maxItems: xe, uniqueItems: be, contains: ge, prefixItems: we, items: Te, if: ee }; function Pe(e, t, n = {}) { let r = { keywordPath: n.keywordPath || [], instancePath: n.instancePath || [], coerce: n.coerce || false, errors: n.errors || [], shortCircuit: n.shortCircuit || false, ignoreUnsupported: n.ignoreUnsupported || false, resolver: n.resolver || new k(e), depth: n.depth ? n.depth + 1 : 0 }, o = structuredClone(n?.coerce ? e.coerce(t, { resolver: r.resolver, depth: r.depth }) : t); if (n.ignoreUnsupported !== true) { let i = ["$defs"]; for (let s of i) if (e[s]) throw new Error(`${s} not implemented`); } if (r.resolver.hasRef(e, o)) { let i = r.resolver.resolve(e.$ref).validate(o, { ...r, errors: [] }); i.valid || r.errors.push(...i.errors); } else for (let [i, s] of Object.entries(Be)) { if (e[i] === undefined) continue; let f = s(e, o, { ...r, errors: [] }); if (!f.valid) { if (n.shortCircuit) return f; r.errors.push(...f.errors); } } return { valid: r.errors.length === 0, errors: r.errors }; } function Ce(e, t, n = {}) { let r = structuredClone(t), o = { resolver: n.resolver || new k(e), depth: n.depth || 0 }; return o.resolver.hasRef(e, r) ? o.resolver.resolve(e.$ref).coerce(r, { ...o, depth: o.depth + 1 }) : r; } var m = (e = {}, t = "any") => { let n = p(e) ? e : {}, r = g(e) ? e : (b in e) ? e[b] : undefined, o = { ...n, [C]: t, [b]: r, optional: function() { return m({ ...this, validate: undefined, [b]: r, [A]: true }, t); }, template: function(i = {}) { if (n.const !== undefined) return n.const; if (n.default !== undefined) return n.default; if (n.enum !== undefined) return n.enum[0]; if (n.template) return n.template(i); }, toJSON: function() { let i = this[b]; return g(i) ? i : JSON.parse(JSON.stringify(n)); } }; return o.coerce = function(i, s = {}) { let f = { ...s, resolver: s.resolver || new k(o), depth: s.depth ? s.depth + 1 : 0 }, u = i; return "coerce" in n && n.coerce !== undefined ? n.coerce(u, f) : Ce(o, u, f); }, o.validate = function(i, s = {}) { if (g(r)) return r === false ? c(s, "", "Always fails") : a(); let f = s.errors || []; if ("validate" in n && n.validate !== undefined) { let u = n.validate(i, s); u.valid || (f = [...f, ...u.errors]); } return Pe(o, i, { ...s, errors: f }); }, o; }; var v = (e, t = {}) => { for (let o of Object.keys(e || {})) N(L(o), "invalid property name", o), N(d(e[o]), "properties must be managed schemas", e[o]); let n = Object.entries(e || {}).filter(([, o]) => !(A in o)).map(([o]) => o), r = t.additionalProperties === false ? m(false) : t.additionalProperties; return m({ template: Ae, coerce: Ne, ...t, additionalProperties: r, type: "object", properties: e, required: n.length > 0 ? n : undefined }, "object"); }; function Ae(e = {}) { let t = {}; if (this.properties) for (let [n, r] of Object.entries(this.properties)) { if (e.withOptional !== true && !this.required?.includes(n)) continue; let o = r.template(e); o !== undefined && (t[n] = o); } return t; } function Ne(e, t = {}) { let n = e; if (typeof n == "string" && (n.match(/^\{/) || n.match(/^\[/)) && (n = JSON.parse(n)), !(typeof n != "object" || n === null)) { if (this.properties) for (let [r, o] of Object.entries(this.properties)) { let i = n[r]; i !== undefined && (n[r] = o.coerce(i, t)); } return n; } } var B = (e = {}) => m({ template: () => "", coerce: (t) => h(t) ? String(t) : t, ...e, type: "string" }, "string"); var I = (e = {}) => m({ coerce: (t) => l(t) ? Number(t) : t, template: je, ...e, type: "number" }, "number"); var U = (e = {}) => m({ coerce: (t) => l(t) ? Number.parseInt(t) : t, template: je, ...e, type: "integer" }, "integer"); function je() { if (this.minimum) return this.minimum; if (this.exclusiveMinimum) { if (this.multipleOf) { let e = this.exclusiveMinimum; for (;e % this.multipleOf !== 0; ) e++; return e; } return this.exclusiveMinimum + 1; } return 0; } var J = (e = {}) => m({ ...e, coerce: function(t) { if ("coerce" in e && e.coerce) return e.coerce(t); if (l(t) && ["true", "false", "1", "0"].includes(t)) return t === "true" || t === "1"; if (h(t)) { if (t === 1) return true; if (t === 0) return false; } return t; }, type: "boolean" }, "boolean"); // src/ComponentForIdentifier.ts function ComponentForIdentifier(identifier, attributes, children) { const component = identifier; const id = attributes["id"]; const name = attributes["name"]; const namespace = attributes["namespace"]; const childrenArray = attributes["children"]; const min = attributes["min"]; const max = attributes["max"]; const required = attributes["required"]; const readonly = attributes["readonly"]; const disabled = attributes["disabled"]; let entry = {}; switch (component) { case "page": case "form": case "section": case "repeater": case "header": case "markdown": { if (childrenArray || children) entry = { container: true, children }; break; } case "time": { const validator = B({ format: "time" }); if (!required) { validator.optional(); } entry = { [`${namespace}.${id}`]: validator }; break; } case "select": { const validator = B(); if (!required) { validator.optional(); } entry = { [`${namespace}.${id}`]: validator }; break; } case "radio": case "checklist": { const validator = B(); if (!required) { validator.optional(); } entry = { [`${namespace}.${id}`]: validator }; break; } case "currency": { const validator = U(); if (!required) { validator.optional(); } entry = { [`${namespace}.${id}`]: validator }; break; } case "date": { const validator = B({ format: "date" }); if (!required) { validator.optional(); } entry = { [`${namespace}.${id}`]: validator }; break; } case "phone": { const validator = B({ maxLength: 15 }); if (!required) { validator.optional(); } entry = { [`${namespace}.${id}`]: validator }; break; } case "text": { let string_options = {}; if (min) { string_options = { min }; } if (max) { string_options = { ...string_options, max }; } const validator = B(); if (!required) { validator.optional(); } entry = { [`${namespace}.${id}`]: validator }; break; } case "email": { const validator = B({ format: "email" }); if (!required) { validator.optional(); } entry = { [`${namespace}.${id}`]: validator }; break; } case "textarea": { const validator = B(); if (!required) { validator.optional(); } entry = { [`${namespace}.${id}`]: validator }; break; } case "checkbox": { const validator = J(); if (!required) { validator.optional(); } entry = { [`${namespace}.${id}`]: validator }; break; } case "integer": { let entry2 = U(); if (min) { entry2 = entry2.min(min); } if (max) { entry2 = entry2.max(max); } if (!required) { entry2 = entry2.optional(); } entry2 = { [`${namespace}.${id}`]: entry2 }; break; } case "decimal": { const validator = I(); if (!required) { validator.optional(); } entry = { [`${namespace}.${id}`]: validator }; break; } default: { const validator = B(); if (!required) { validator.optional(); } entry = { [`${namespace}.${id}`]: validator }; console.warn(`Unknown component type: ${component}`); break; } } return entry; } // src/ToSpacedTitleCase.ts function ToSpacedTitleCase(s) { let words = []; let word = ""; for (let character of s) { if (character == " " || character == "_" || character == "-") { words.push(word); word = ""; } else if (character >= "0" && character <= "9") { const last_character = word[word.length - 1]; if (last_character == undefined) { word = character; } else if (last_character >= "0" && last_character <= "9") { word += character; } else { words.push(word); word = character; } } else if (character == character.toUpperCase()) { if (word != "") { words.push(word); } word = character; } else { word += character; } } if (word != "") { words.push(word); } words = words.map((word2) => { if (word2 == "") { return ""; } let result = word2.toLowerCase() || word2; return result[0]?.toUpperCase() + result.slice(1); }); return words.join(" "); } // src/EvaluateToSchema.ts class EvaluateToSchema { namespace = {}; name_stack = []; visitCheckListExpr(checklist) { const identifier = checklist.identifier.accept(this); const attributes = checklist.attributes.map((attribute) => { const name = attribute.left.name; let right = attribute.right.value.literal; if (!right) { right = attribute.right.value.lexeme == "true"; } return { [name]: right }; }); const attributes_merged = this.ProcessControlAttributes(attributes, identifier, checklist.line_number); const children = checklist.children.map((child_expr) => { const child = child_expr.accept(this); const name = child.literal; return { name }; }).map((x2) => { return `"${x2.name}"`; }); return ComponentForIdentifier(identifier, attributes_merged, ""); } visitAttributeExpr(attribute) { return attribute.accept(this); } visitControlExpr(control) { const identifier = control.identifier.accept(this); const attributes = control.attributes.map((attribute) => { const name = attribute.left.name; let right = attribute.right.value.literal; if (!right) { right = attribute.right.value.lexeme == "true"; } return { [name]: right }; }); const attributes_merged = this.ProcessControlAttributes(attributes, identifier, control.line_number); return ComponentForIdentifier(identifier, attributes_merged, ""); } visitIdentifierExpr(identifier) { const ident = identifier; return ident.name; } visitContainerExpr(container) { const identifier = container.identifier.accept(this); const attributes = container.attributes.map((attribute) => { const name = attribute.left.name; let right = attribute.right.value.literal; if (!right) { right = attribute.right.value.lexeme == "true"; } return { [name]: right }; }); let attributes_merged = {}; if (attributes.length > 0) { attributes_merged = attributes.reduce((acc, curr) => { return { ...acc, ...curr }; }); } const id = attributes_merged["id"]; if (id) { if (identifier == "repeater") { this.name_stack.push(`${id}[]`); } else { this.name_stack.push(id); } } const children = container.children.map((child) => { return child.accept(this); }); this.name_stack.pop(); return ComponentForIdentifier(identifier, attributes_merged, children); } visitLiteralExpr(literal) { return literal.value; } visitMarkdownExpr(markdown) { return {}; } visitSelectExpr(select) { const identifier = select.identifier.accept(this); const attributes = select.attributes.map((attribute) => { const name = attribute.left.name; let right = attribute.right.value.literal; if (!right) { right = attribute.right.value.lexeme == "true"; } return { [name]: right }; }); const attributes_merged = this.ProcessControlAttributes(attributes, identifier, select.line_number); const children = select.children.map((child_expr) => { const child = child_expr.accept(this); const name = child.literal; return { name }; }).join(""); return ComponentForIdentifier(identifier, attributes_merged, children); } visitRadioExpr(radio) { const identifier = radio.identifier.accept(this); const attributes = radio.attributes.map((attribute) => { const name = attribute.left.name; let right = attribute.right.value.literal; if (!right) { right = attribute.right.value.lexeme == "true"; } return { [name]: right }; }); const attributes_merged = this.ProcessControlAttributes(attributes, identifier, radio.line_number); const children = radio.children.map((chil