UNPKG

@mlightcad/mtext-parser

Version:

AutoCAD MText parser written in TypeScript

1,062 lines (1,061 loc) 31.6 kB
var S = /* @__PURE__ */ ((s) => (s[s.NONE = 0] = "NONE", s[s.WORD = 1] = "WORD", s[s.STACK = 2] = "STACK", s[s.SPACE = 3] = "SPACE", s[s.NBSP = 4] = "NBSP", s[s.TABULATOR = 5] = "TABULATOR", s[s.NEW_PARAGRAPH = 6] = "NEW_PARAGRAPH", s[s.NEW_COLUMN = 7] = "NEW_COLUMN", s[s.WRAP_AT_DIMLINE = 8] = "WRAP_AT_DIMLINE", s[s.PROPERTIES_CHANGED = 9] = "PROPERTIES_CHANGED", s))(S || {}), F = /* @__PURE__ */ ((s) => (s[s.BOTTOM = 0] = "BOTTOM", s[s.MIDDLE = 1] = "MIDDLE", s[s.TOP = 2] = "TOP", s))(F || {}), E = /* @__PURE__ */ ((s) => (s[s.DEFAULT = 0] = "DEFAULT", s[s.LEFT = 1] = "LEFT", s[s.RIGHT = 2] = "RIGHT", s[s.CENTER = 3] = "CENTER", s[s.JUSTIFIED = 4] = "JUSTIFIED", s[s.DISTRIBUTED = 5] = "DISTRIBUTED", s))(E || {}), R = /* @__PURE__ */ ((s) => (s[s.NONE = 0] = "NONE", s[s.UNDERLINE = 1] = "UNDERLINE", s[s.OVERLINE = 2] = "OVERLINE", s[s.STRIKE_THROUGH = 4] = "STRIKE_THROUGH", s))(R || {}); const v = { c: "Ø", d: "°", p: "±" }, y = { l: 1, r: 2, c: 3, j: 4, d: 5 /* DISTRIBUTED */ }; function N(s) { const [t, e, r] = s; return r << 16 | e << 8 | t; } function I(s) { const t = s & 255, e = s >> 8 & 255, r = s >> 16 & 255; return [t, e, r]; } function w(s) { return s.replace(/\r\n|\r|\n/g, "\\P"); } function x(s) { return s.replace(/\\P/g, "").replace(/\\~/g, "").includes("\\"); } function P(s, t = !1) { const e = /* @__PURE__ */ new Set(), r = /\\[fF](.*?)[;|]/g; return [...s.matchAll(r)].forEach((a) => { let l = a[1].toLowerCase(); t && (l = l.replace(/\.(ttf|otf|woff|shx)$/, "")), e.add(l); }), e; } class O { /** * Creates a new ContextStack with an initial context. * @param initial The initial MTextContext to use as the base of the stack. */ constructor(t) { this.stack = [], this.stack.push(t); } /** * Pushes a copy of the given context onto the stack. * @param ctx The MTextContext to push (copied). */ push(t) { this.stack.push(t); } /** * Pops the top context from the stack and merges its paragraph properties into the new top context. * If only one context remains, nothing is popped. * @returns The popped MTextContext, or undefined if the stack has only one context. */ pop() { if (this.stack.length <= 1) return; const t = this.stack.pop(), e = this.stack[this.stack.length - 1]; return JSON.stringify(e.paragraph) !== JSON.stringify(t.paragraph) && (e.paragraph = { ...t.paragraph }), t; } /** * Returns the current (top) context on the stack. */ get current() { return this.stack[this.stack.length - 1]; } /** * Returns the current stack depth (number of nested blocks), not counting the root context. */ get depth() { return this.stack.length - 1; } /** * Returns the root (bottom) context, which represents the global formatting state. * Used for paragraph property application. */ get root() { return this.stack[0]; } /** * Replaces the current (top) context with the given context. * @param ctx The new context to set as the current context. */ setCurrent(t) { this.stack[this.stack.length - 1] = t; } } class D { /** * Creates a new MTextParser instance * @param content - The MText content to parse * @param ctx - Optional initial MText context * @param options - Parser options */ constructor(t, e, r = {}) { this.continueStroke = !1, this.inStackContext = !1, this.scanner = new d(t); const a = e ?? new m(); this.ctxStack = new O(a), this.yieldPropertyCommands = r.yieldPropertyCommands ?? !1, this.resetParagraphParameters = r.resetParagraphParameters ?? !1; } /** * Decode multi-byte character from hex code * @param hex - Hex code string (e.g. "C4E3") * @returns Decoded character or empty square if invalid */ decodeMultiByteChar(t) { try { const e = new Uint8Array([ parseInt(t.substr(0, 2), 16), parseInt(t.substr(2, 2), 16) ]), a = new TextDecoder("gbk").decode(e); if (a !== "▯") return a; const i = new TextDecoder("big5").decode(e); return i !== "▯" ? i : "▯"; } catch { return "▯"; } } /** * Push current context onto the stack */ pushCtx() { this.ctxStack.push(this.ctxStack.current); } /** * Pop context from the stack */ popCtx() { this.ctxStack.pop(); } /** * Parse stacking expression (numerator/denominator) * @returns Tuple of [TokenType.STACK, [numerator, denominator, type]] */ parseStacking() { const t = new d(this.extractExpression(!0)); let e = "", r = "", a = ""; const l = () => { let c = t.peek(), n = !1; return c.charCodeAt(0) < 32 && (c = " "), c === "\\" && (n = !0, t.consume(1), c = t.peek()), t.consume(1), [c, n]; }, i = () => { let c = ""; for (; t.hasData; ) { const [n, p] = l(); if (!p && (n === "/" || n === "#" || n === "^")) return [c, n]; c += n; } return [c, ""]; }, u = (c) => { let n = "", p = c; for (; t.hasData; ) { const [h, o] = l(); if (!(p && h === " ")) { if (p = !1, !o && h === ";") break; n += h; } } return n; }; return [e, a] = i(), a && (r = u(a === "^")), e === "" && r.includes("I/") ? [2, [" ", " ", "/"]] : a === "^" ? [2, [e, r, "^"]] : [2, [e, r, a]]; } /** * Parse MText properties * @param cmd - The property command to parse * @returns Property changes if yieldPropertyCommands is true and changes occurred */ parseProperties(t) { const e = this.ctxStack.current.copy(), r = this.ctxStack.current.copy(); switch (t) { case "L": r.underline = !0, this.continueStroke = !0; break; case "l": r.underline = !1, r.hasAnyStroke || (this.continueStroke = !1); break; case "O": r.overline = !0, this.continueStroke = !0; break; case "o": r.overline = !1, r.hasAnyStroke || (this.continueStroke = !1); break; case "K": r.strikeThrough = !0, this.continueStroke = !0; break; case "k": r.strikeThrough = !1, r.hasAnyStroke || (this.continueStroke = !1); break; case "A": this.parseAlign(r); break; case "C": this.parseAciColor(r); break; case "c": this.parseRgbColor(r); break; case "H": this.parseHeight(r); break; case "W": this.parseWidth(r); break; case "Q": this.parseOblique(r); break; case "T": this.parseCharTracking(r); break; case "p": this.parseParagraphProperties(r); break; case "f": case "F": this.parseFontProperties(r); break; default: throw new Error(`Unknown command: ${t}`); } if (this.continueStroke = r.hasAnyStroke, r.continueStroke = this.continueStroke, this.ctxStack.setCurrent(r), this.yieldPropertyCommands) { const a = this.getPropertyChanges(e, r); if (Object.keys(a).length > 0) return { command: t, changes: a, depth: this.ctxStack.depth }; } } /** * Get property changes between two contexts * @param oldCtx - The old context * @param newCtx - The new context * @returns Object containing changed properties */ getPropertyChanges(t, e) { const r = {}; if (t.underline !== e.underline && (r.underline = e.underline), t.overline !== e.overline && (r.overline = e.overline), t.strikeThrough !== e.strikeThrough && (r.strikeThrough = e.strikeThrough), t.color.aci !== e.color.aci && (r.aci = e.color.aci), t.color.rgbValue !== e.color.rgbValue && (r.rgb = e.color.rgb), t.align !== e.align && (r.align = e.align), JSON.stringify(t.fontFace) !== JSON.stringify(e.fontFace) && (r.fontFace = e.fontFace), (t.capHeight.value !== e.capHeight.value || t.capHeight.isRelative !== e.capHeight.isRelative) && (r.capHeight = e.capHeight), (t.widthFactor.value !== e.widthFactor.value || t.widthFactor.isRelative !== e.widthFactor.isRelative) && (r.widthFactor = e.widthFactor), (t.charTrackingFactor.value !== e.charTrackingFactor.value || t.charTrackingFactor.isRelative !== e.charTrackingFactor.isRelative) && (r.charTrackingFactor = e.charTrackingFactor), t.oblique !== e.oblique && (r.oblique = e.oblique), JSON.stringify(t.paragraph) !== JSON.stringify(e.paragraph)) { const a = {}; t.paragraph.indent !== e.paragraph.indent && (a.indent = e.paragraph.indent), t.paragraph.align !== e.paragraph.align && (a.align = e.paragraph.align), t.paragraph.left !== e.paragraph.left && (a.left = e.paragraph.left), t.paragraph.right !== e.paragraph.right && (a.right = e.paragraph.right), JSON.stringify(t.paragraph.tabs) !== JSON.stringify(e.paragraph.tabs) && (a.tabs = e.paragraph.tabs), Object.keys(a).length > 0 && (r.paragraph = a); } return r; } /** * Parse alignment property * @param ctx - The context to update */ parseAlign(t) { const e = this.scanner.get(); "012".includes(e) ? t.align = parseInt(e) : t.align = 0, this.consumeOptionalTerminator(); } /** * Parse height property * @param ctx - The context to update */ parseHeight(t) { const e = this.extractFloatExpression(!0); if (e) try { e.endsWith("x") ? t.capHeight = { value: parseFloat(e.slice(0, -1)), isRelative: !0 } : t.capHeight = { value: parseFloat(e), isRelative: !1 }; } catch { this.scanner.consume(-e.length); return; } this.consumeOptionalTerminator(); } /** * Parse width property * @param ctx - The context to update */ parseWidth(t) { const e = this.extractFloatExpression(!0); if (e) try { e.endsWith("x") ? t.widthFactor = { value: parseFloat(e.slice(0, -1)), isRelative: !0 } : t.widthFactor = { value: parseFloat(e), isRelative: !1 }; } catch { this.scanner.consume(-e.length); return; } this.consumeOptionalTerminator(); } /** * Parse character tracking property * @param ctx - The context to update */ parseCharTracking(t) { const e = this.extractFloatExpression(!0); if (e) try { e.endsWith("x") ? t.charTrackingFactor = { value: Math.abs(parseFloat(e.slice(0, -1))), isRelative: !0 } : t.charTrackingFactor = { value: Math.abs(parseFloat(e)), isRelative: !1 }; } catch { this.scanner.consume(-e.length); return; } this.consumeOptionalTerminator(); } /** * Parse float value or factor * @param value - Current value to apply factor to * @returns New value */ parseFloatValueOrFactor(t) { const e = this.extractFloatExpression(!0); if (e) if (e.endsWith("x")) { const r = parseFloat(e.slice(0, -1)); t *= r; } else t = parseFloat(e); return t; } /** * Parse oblique angle property * @param ctx - The context to update */ parseOblique(t) { const e = this.extractFloatExpression(!1); e && (t.oblique = parseFloat(e)), this.consumeOptionalTerminator(); } /** * Parse ACI color property * @param ctx - The context to update */ parseAciColor(t) { const e = this.extractIntExpression(); if (e) { const r = parseInt(e); r < 257 && (t.color.aci = r); } this.consumeOptionalTerminator(); } /** * Parse RGB color property * @param ctx - The context to update */ parseRgbColor(t) { const e = this.extractIntExpression(); if (e) { const r = parseInt(e) & 16777215; t.color.rgbValue = r; } this.consumeOptionalTerminator(); } /** * Extract float expression from scanner * @param relative - Whether to allow relative values (ending in 'x') * @returns Extracted expression */ extractFloatExpression(t = !1) { const e = t ? /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?x?/ : /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?/, r = this.scanner.tail.match(e); if (r) { const a = r[0]; return this.scanner.consume(a.length), a; } return ""; } /** * Extract integer expression from scanner * @returns Extracted expression */ extractIntExpression() { const t = this.scanner.tail.match(/^\d+/); if (t) { const e = t[0]; return this.scanner.consume(e.length), e; } return ""; } /** * Extract expression until semicolon or end * @param escape - Whether to handle escaped semicolons * @returns Extracted expression */ extractExpression(t = !1) { const e = this.scanner.find(";", t); if (e < 0) { const i = this.scanner.tail; return this.scanner.consume(i.length), i; } const a = this.scanner.peek(e - this.scanner.currentIndex - 1) === "\\", l = this.scanner.tail.slice(0, e - this.scanner.currentIndex + (a ? 1 : 0)); return this.scanner.consume(l.length + 1), l; } /** * Parse font properties * @param ctx - The context to update */ parseFontProperties(t) { const e = this.extractExpression().split("|"); if (e.length > 0 && e[0]) { const r = e[0]; let a = "Regular", l = 400; for (const i of e.slice(1)) i.startsWith("b1") ? l = 700 : i === "i" || i.startsWith("i1") ? a = "Italic" : (i === "i0" || i.startsWith("i0")) && (a = "Regular"); t.fontFace = { family: r, style: a, weight: l }; } } /** * Parse paragraph properties from the MText content * Handles properties like indentation, alignment, and tab stops * @param ctx - The context to update */ parseParagraphProperties(t) { const e = new d(this.extractExpression()); let r = t.paragraph.indent, a = t.paragraph.left, l = t.paragraph.right, i = t.paragraph.align, u = []; const c = () => { const n = e.tail.match(/^[+-]?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?/); if (n) { const p = parseFloat(n[0]); for (e.consume(n[0].length); e.peek() === ","; ) e.consume(1); return p; } return 0; }; for (; e.hasData; ) switch (e.get()) { case "i": r = c(); break; case "l": a = c(); break; case "r": l = c(); break; case "x": break; case "q": { const p = e.get(); for (i = y[p] || 0; e.peek() === ","; ) e.consume(1); break; } case "t": for (u = []; e.hasData; ) { const p = e.peek(); if (p === "r" || p === "c") { e.consume(1); const h = c(); u.push(p + h.toString()); } else { const h = c(); isNaN(h) ? e.consume(1) : u.push(h); } } break; } t.paragraph = { indent: r, left: a, right: l, align: i, tabs: u }; } /** * Consume optional terminator (semicolon) */ consumeOptionalTerminator() { this.scanner.peek() === ";" && this.scanner.consume(1); } /** * Parse MText content into tokens * @yields MTextToken objects */ *parse() { let r = null; function a(i) { const u = { ...i.paragraph }; i.paragraph = { indent: 0, left: 0, right: 0, align: 0, tabs: [] }; const c = {}; return u.indent !== 0 && (c.indent = 0), u.left !== 0 && (c.left = 0), u.right !== 0 && (c.right = 0), u.align !== 0 && (c.align = 0), JSON.stringify(u.tabs) !== JSON.stringify([]) && (c.tabs = []), c; } const l = () => { var u; let i = ""; for (; this.scanner.hasData; ) { let c = !1, n = this.scanner.peek(); const p = this.scanner.currentIndex; if (n.charCodeAt(0) < 32) { if (this.scanner.consume(1), n === " ") return [5, null]; if (n === ` `) return [6, null]; n = " "; } if (n === "\\") if ("\\{}".includes(this.scanner.peek(1))) c = !0, this.scanner.consume(1), n = this.scanner.peek(); else { if (i) return [1, i]; this.scanner.consume(1); const h = this.scanner.get(); switch (h) { case "~": return [4, null]; case "P": return [6, null]; case "N": return [7, null]; case "X": return [8, null]; case "S": { this.inStackContext = !0; const o = this.parseStacking(); return this.inStackContext = !1, o; } case "m": case "M": if (this.scanner.peek() === "+") { this.scanner.consume(1); const o = (u = this.scanner.tail.match(/^[0-9A-Fa-f]{4}/)) == null ? void 0 : u[0]; if (o) { this.scanner.consume(4); const g = this.decodeMultiByteChar(o); return i ? [1, i] : [1, g]; } this.scanner.consume(-1); } i += "\\M"; continue; case "U": if (this.scanner.peek() === "+") { this.scanner.consume(1); const o = this.scanner.tail.match(/^[0-9A-Fa-f]{4,8}/); if (o) { const g = o[0]; this.scanner.consume(g.length); const _ = parseInt(g, 16); let f = ""; try { f = String.fromCodePoint(_); } catch { f = "▯"; } return i ? [1, i] : [1, f]; } this.scanner.consume(-1); } i += "\\U"; continue; default: if (h) try { const o = this.parseProperties(h); if (this.yieldPropertyCommands && o) return [9, o]; continue; } catch { const o = this.scanner.tail.slice( p, this.scanner.currentIndex ); i += o; } } continue; } if (n === "%" && this.scanner.peek(1) === "%") { const h = this.scanner.peek(2).toLowerCase(), o = v[h]; if (o) { this.scanner.consume(3), i += o; continue; } else { this.scanner.consume(3); continue; } } if (n === " ") return i ? (this.scanner.consume(1), r = 3, [1, i]) : (this.scanner.consume(1), [3, null]); if (!c) { if (n === "{") { if (i) return [1, i]; this.scanner.consume(1), this.pushCtx(); continue; } else if (n === "}") { if (i) return [1, i]; if (this.scanner.consume(1), this.yieldPropertyCommands) { const h = this.ctxStack.current; this.popCtx(); const o = this.getPropertyChanges(h, this.ctxStack.current); if (Object.keys(o).length > 0) return [ 9, { command: void 0, changes: o, depth: this.ctxStack.depth } ]; } else this.popCtx(); continue; } } if (!this.inStackContext && n === "^") { const h = this.scanner.peek(1); if (h) { const o = h.charCodeAt(0); if (this.scanner.consume(2), o === 32) i += "^"; else { if (o === 73) return i ? [1, i] : [5, null]; if (o === 74) return i ? [1, i] : [6, null]; if (o === 77) continue; i += "▯"; } continue; } } this.scanner.consume(1), n.charCodeAt(0) >= 32 && (i += n); } return i ? [1, i] : [0, null]; }; for (; ; ) { const [i, u] = l.call(this); if (i) { if (yield new k(i, this.ctxStack.current.copy(), u), i === 6 && this.resetParagraphParameters) { const c = this.ctxStack.current, n = a(c); this.yieldPropertyCommands && Object.keys(n).length > 0 && (yield new k(9, c.copy(), { command: void 0, changes: { paragraph: n }, depth: this.ctxStack.depth })); } r && (yield new k(r, this.ctxStack.current.copy(), null), r = null); } else break; } } } class d { /** * Create a new text scanner * @param text - The text to scan */ constructor(t) { this.text = t, this.textLen = t.length, this._index = 0; } /** * Get the current index in the text */ get currentIndex() { return this._index; } /** * Check if the scanner has reached the end of the text */ get isEmpty() { return this._index >= this.textLen; } /** * Check if there is more text to scan */ get hasData() { return this._index < this.textLen; } /** * Get the next character and advance the index * @returns The next character, or empty string if at end */ get() { if (this.isEmpty) return ""; const t = this.text[this._index]; return this._index++, t; } /** * Advance the index by the specified count * @param count - Number of characters to advance */ consume(t = 1) { this._index = Math.max(0, Math.min(this._index + t, this.textLen)); } /** * Look at a character without advancing the index * @param offset - Offset from current position * @returns The character at the offset position, or empty string if out of bounds */ peek(t = 0) { const e = this._index + t; return e >= this.textLen || e < 0 ? "" : this.text[e]; } /** * Find the next occurrence of a character * @param char - The character to find * @param escape - Whether to handle escaped characters * @returns Index of the character, or -1 if not found */ find(t, e = !1) { let r = this._index; for (; r < this.textLen; ) { if (e && this.text[r] === "\\") { if (r + 1 < this.textLen) { if (this.text[r + 1] === t) return r + 1; r += 2; continue; } r++; continue; } if (this.text[r] === t) return r; r++; } return -1; } /** * Get the remaining text from the current position */ get tail() { return this.text.slice(this._index); } /** * Check if the next character is a space */ isNextSpace() { return this.peek() === " "; } /** * Consume spaces until a non-space character is found * @returns Number of spaces consumed */ consumeSpaces() { let t = 0; for (; this.isNextSpace(); ) this.consume(), t++; return t; } } class b { // Store as 0xRRGGBB or null /** * Create a new MTextColor instance. * @param color The initial color: number for ACI, [r,g,b] for RGB, or null/undefined for default (ACI=256). */ constructor(t) { this._aci = 256, this._rgbValue = null, Array.isArray(t) ? this.rgb = t : typeof t == "number" ? this.aci = t : this.aci = 256; } /** * Get the current ACI color value. * @returns The ACI color (0-256), or null if using RGB. */ get aci() { return this._aci; } /** * Set the ACI color value. Setting this disables any RGB color. * @param value The ACI color (0-256), or null to unset. * @throws Error if value is out of range. */ set aci(t) { if (t === null) this._aci = null; else if (t >= 0 && t <= 256) this._aci = t, this._rgbValue = null; else throw new Error("ACI not in range [0, 256]"); } /** * Get the current RGB color as a tuple [r, g, b], or null if not set. * @returns The RGB color tuple, or null if using ACI. */ get rgb() { if (this._rgbValue === null) return null; const t = this._rgbValue >> 16 & 255, e = this._rgbValue >> 8 & 255, r = this._rgbValue & 255; return [t, e, r]; } /** * Set the RGB color. Setting this disables ACI color. * @param value The RGB color tuple [r, g, b], or null to use ACI. */ set rgb(t) { if (t) { const [e, r, a] = t; this._rgbValue = (e & 255) << 16 | (r & 255) << 8 | a & 255, this._aci = null; } else this._rgbValue = null; } /** * Returns true if the color is set by RGB, false if by ACI. */ get isRgb() { return this._rgbValue !== null; } /** * Returns true if the color is set by ACI, false if by RGB. */ get isAci() { return this._rgbValue === null && this._aci !== null; } /** * Get or set the internal RGB value as a number (0xRRGGBB), or null if not set. * Setting this will switch to RGB mode and set ACI to null. */ get rgbValue() { return this._rgbValue; } set rgbValue(t) { t === null ? this._rgbValue = null : (this._rgbValue = t & 16777215, this._aci = null); } /** * Returns a deep copy of this color. * @returns A new MTextColor instance with the same color state. */ copy() { const t = new b(); return t._aci = this._aci, t._rgbValue = this._rgbValue, t; } /** * Returns a plain object for serialization. * @returns An object with aci, rgb (tuple), and rgbValue (number or null). */ toObject() { return { aci: this._aci, rgb: this.rgb, rgbValue: this._rgbValue }; } /** * Equality check for color. * @param other The other MTextColor to compare. * @returns True if both ACI and RGB values are equal. */ equals(t) { return this._aci === t._aci && this._rgbValue === t._rgbValue; } } class m { constructor() { this._stroke = 0, this.continueStroke = !1, this.color = new b(), this.align = 0, this.fontFace = { family: "", style: "Regular", weight: 400 }, this._capHeight = { value: 1, isRelative: !1 }, this._widthFactor = { value: 1, isRelative: !1 }, this._charTrackingFactor = { value: 1, isRelative: !1 }, this.oblique = 0, this.paragraph = { indent: 0, left: 0, right: 0, align: 0, tabs: [] }; } /** * Get the capital letter height */ get capHeight() { return this._capHeight; } /** * Set the capital letter height * @param value - Height value */ set capHeight(t) { this._capHeight = { value: Math.abs(t.value), isRelative: t.isRelative }; } /** * Get the character width factor */ get widthFactor() { return this._widthFactor; } /** * Set the character width factor * @param value - Width factor value */ set widthFactor(t) { this._widthFactor = { value: Math.abs(t.value), isRelative: t.isRelative }; } /** * Get the character tracking factor */ get charTrackingFactor() { return this._charTrackingFactor; } /** * Set the character tracking factor * @param value - Tracking factor value */ set charTrackingFactor(t) { this._charTrackingFactor = { value: Math.abs(t.value), isRelative: t.isRelative }; } /** * Get the ACI color value */ get aci() { return this.color.aci; } /** * Set the ACI color value * @param value - ACI color value (0-256) * @throws Error if value is out of range */ set aci(t) { this.color.aci = t; } /** * Get the RGB color value */ get rgb() { return this.color.rgb; } /** * Set the RGB color value */ set rgb(t) { this.color.rgb = t; } /** * Gets whether the current text should be rendered in italic style. * @returns {boolean} True if the font style is 'Italic', otherwise false. */ get italic() { return this.fontFace.style === "Italic"; } /** * Sets whether the current text should be rendered in italic style. * @param value - If true, sets the font style to 'Italic'; if false, sets it to 'Regular'. */ set italic(t) { this.fontFace.style = t ? "Italic" : "Regular"; } /** * Gets whether the current text should be rendered in bold style. * This is primarily used for mesh fonts and affects font selection. * @returns {boolean} True if the font weight is 700 or higher, otherwise false. */ get bold() { return (this.fontFace.weight || 400) >= 700; } /** * Sets whether the current text should be rendered in bold style. * This is primarily used for mesh fonts and affects font selection. * @param value - If true, sets the font weight to 700; if false, sets it to 400. */ set bold(t) { this.fontFace.weight = t ? 700 : 400; } /** * Get whether text is underlined */ get underline() { return !!(this._stroke & 1); } /** * Set whether text is underlined * @param value - Whether to underline */ set underline(t) { this._setStrokeState(1, t); } /** * Get whether text has strike-through */ get strikeThrough() { return !!(this._stroke & 4); } /** * Set whether text has strike-through * @param value - Whether to strike through */ set strikeThrough(t) { this._setStrokeState(4, t); } /** * Get whether text has overline */ get overline() { return !!(this._stroke & 2); } /** * Set whether text has overline * @param value - Whether to overline */ set overline(t) { this._setStrokeState(2, t); } /** * Check if any stroke formatting is active */ get hasAnyStroke() { return !!this._stroke; } /** * Set the state of a stroke type * @param stroke - The stroke type to set * @param state - Whether to enable or disable the stroke */ _setStrokeState(t, e = !0) { e ? this._stroke |= t : this._stroke &= ~t; } /** * Create a copy of this context * @returns A new context with the same properties */ copy() { const t = new m(); return t._stroke = this._stroke, t.continueStroke = this.continueStroke, t.color = this.color.copy(), t.align = this.align, t.fontFace = { ...this.fontFace }, t._capHeight = { ...this._capHeight }, t._widthFactor = { ...this._widthFactor }, t._charTrackingFactor = { ...this._charTrackingFactor }, t.oblique = this.oblique, t.paragraph = { ...this.paragraph }, t; } } class k { /** * Create a new MText token * @param type - The token type * @param ctx - The text context at this token * @param data - Optional token data */ constructor(t, e, r) { this.type = t, this.ctx = e, this.data = r; } } export { b as MTextColor, m as MTextContext, F as MTextLineAlignment, E as MTextParagraphAlignment, D as MTextParser, R as MTextStroke, k as MTextToken, d as TextScanner, S as TokenType, w as escapeDxfLineEndings, P as getFonts, x as hasInlineFormattingCodes, I as int2rgb, N as rgb2int }; //# sourceMappingURL=parser.es.js.map