UNPKG

bliss-svg-builder

Version:

Compose, render, and manipulate Blissymbolics SVG using a compact DSL and a programmatic mutation API.

798 lines (670 loc) 31.9 kB
/** * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ // --- Options --- /** Known option keys accepted by BlissSVGBuilder (kebab-case). */ export interface BlissOptions { // Stroke and spacing 'stroke-width'?: number; 'dot-extra-width'?: number; 'sdot-extra-width'?: number; 'dot-width'?: number; 'sdot-width'?: number; 'char-space'?: number; 'word-space'?: number; 'external-glyph-space'?: number; // Margins (builder-level) margin?: number; 'margin-top'?: number; 'margin-bottom'?: number; 'margin-left'?: number; 'margin-right'?: number; // Sizing 'min-width'?: number; center?: boolean; // Cropping (builder-level) crop?: number | 'auto' | 'auto-vertical' | 'compact'; 'crop-top'?: number | 'auto'; 'crop-bottom'?: number | 'auto'; 'crop-left'?: number | 'auto'; 'crop-right'?: number | 'auto'; // Grid (builder-level) grid?: boolean; 'grid-color'?: string; 'grid-major-color'?: string; 'grid-medium-color'?: string; 'grid-minor-color'?: string; 'grid-sky-color'?: string; 'grid-earth-color'?: string; 'grid-stroke-width'?: number; 'grid-major-stroke-width'?: number; 'grid-medium-stroke-width'?: number; 'grid-minor-stroke-width'?: number; 'grid-sky-stroke-width'?: number; 'grid-earth-stroke-width'?: number; // Colors and background color?: string; background?: string; 'background-top'?: string; 'background-mid'?: string; 'background-bottom'?: string; // Text and metadata text?: string; 'svg-desc'?: string; 'svg-title'?: string; 'svg-height'?: number; // Error handling 'error-placeholder'?: boolean; // SVG pass-through attributes (any key not in the known set). Includes // `boolean` so the boolean options (`grid`, `center`, `error-placeholder`) // conform to the index signature; without it `tsc` rejects this interface. [key: string]: string | number | boolean | undefined; } /** Cascading option layers: defaults (lowest priority) and overrides (highest priority). */ export interface OptionLayers { defaults?: BlissOptions; overrides?: BlissOptions; } // --- Element snapshots --- /** Bounding box of an element in absolute SVG coordinates. */ export interface ElementBounds { readonly minX: number; readonly maxX: number; readonly minY: number; readonly maxY: number; readonly width: number; readonly height: number; } /** A frozen, read-only snapshot of an element in the composition tree. */ export interface ElementSnapshot { readonly key: string; /** * The input code that produces this element (e.g. `'B431'`, `'Xa'`, `'H'`). * At part level, the structural lookup key the user would write (`'B81'`, * `'H'`, `'Xa'`, `'TSP'`, `'Xα'`, `'Xhαllo'`). At glyph level, the input * code only when the glyph is actually a glyph: B-codes (`'B431'`), single * X-codes (`'Xa'`, `'Xα'`), or `define()`d `type:'glyph'` aliases * (`'LOVE'`); `''` for composites, bare shape primitives, and * multi-character text fallback. Always `''` at group level. Note: this is * the live identity. `toString()` and `toJSON()` decompose alias names by * default; pass `{ preserve: true }` to keep them in serialized output. */ readonly codeName: string; /** * The rendered Unicode character for an external glyph (e.g. `'a'` for * `Xa`, `'α'` for `Xα`). `''` for B-codes, composites, shape primitives, * multi-character text fallback, and non-glyph levels. */ readonly char: string; readonly x: number; readonly y: number; readonly offsetX: number; readonly offsetY: number; readonly width: number; readonly height: number; readonly advanceX: number; readonly baseWidth: number; readonly level: number; readonly isRoot: boolean; readonly isGroup: boolean; readonly isGlyph: boolean; readonly isPart: boolean; readonly bounds: ElementBounds; readonly isIndicator: boolean; /** * For an indicator part, whether it originates from a character-level * marker (single `;`, `'character'`) or a word-level overlay (`;;`, * `'word'`). `null` for a non-indicator, a non-part level, or an indicator * whose definition cannot be resolved. The `'word'` value appears only on * the resolved snapshot: a word overlay has no raw node, so a part handle * can never reach one. Like `isIndicator`, a composite indicator's internal * sub-parts also classify (as `'character'`), so an enumeration that * recurses `children` should de-duplicate by depth. */ readonly indicatorLevel: 'character' | 'word' | null; /** * For an indicator part, `'semantic'` when its definition carries a * semantic indicator (e.g. THING), otherwise `'grammatical'`. `null` for a * non-indicator, a non-part level, or an unresolved definition. */ readonly indicatorKind: 'semantic' | 'grammatical' | null; readonly isShape: boolean; readonly isBlissGlyph: boolean; readonly isExternalGlyph: boolean; readonly isHeadGlyph: boolean; readonly isSpaceGroup: boolean; readonly index: number; readonly parentKey: string | null; readonly children: readonly ElementSnapshot[]; } // --- Element handle (live mutation API) --- /** * A live handle referencing a node in the raw composition object. * Returned by `getElementByKey()`, `group()`, `glyph()`, and `part()`. * Mutations through a handle trigger a rebuild of the composition. */ export declare class ElementHandle { /** Structural depth: 1 = group, 2 = glyph, 3+ = part. */ readonly level: number; /** True when level === 1 (a word group). */ readonly isGroup: boolean; /** True when level === 2 (a Bliss character). */ readonly isGlyph: boolean; /** True when level >= 3 (a part within a character). */ readonly isPart: boolean; /** * The input code that produces this element (e.g. `'B431'`, `'Xa'`, `'H'`). * At part level, the structural lookup key the user would write (`'B81'`, * `'H'`, `'Xa'`, `'TSP'`, `'Xα'`, `'Xhαllo'`). At glyph level, the input * code only when the glyph is actually a glyph: B-codes (`'B431'`), single * X-codes (`'Xa'`, `'Xα'`), or `define()`d `type:'glyph'` aliases * (`'LOVE'`); `''` for composites, bare shape primitives, and * multi-character text fallback. Always `''` at group level. Note: this is * the live identity. `toString()` and `toJSON()` decompose alias names by * default; pass `{ preserve: true }` to keep them in serialized output. */ readonly codeName: string; /** * The rendered Unicode character for an external glyph (e.g. `'a'` for * `Xa`, `'α'` for `Xα`). `''` for B-codes, composites, shape primitives, * multi-character text fallback, and non-glyph levels. */ readonly char: string; /** Stable across mutations. Use with `getElementByKey(key)` to recover a handle to this same node later. */ readonly key: string; /** Whether this part is an indicator. Only true on part-level handles. */ readonly isIndicator: boolean; /** * Indicator origin level: `'character'` for a single-`;` indicator part, or * `null` for a non-indicator or non-part handle. A word-level overlay (`;;`) * has no raw node, so a part handle can never reference one — it reads as * `'word'` on `snapshot()` instead. */ readonly indicatorLevel: 'character' | 'word' | null; /** * Indicator kind: `'semantic'` when the definition carries a semantic * indicator, `'grammatical'` otherwise, or `null` for a non-indicator part, * a non-part handle, or an unresolved definition. */ readonly indicatorKind: 'semantic' | 'grammatical' | null; /** Whether this part is a shape primitive. */ readonly isShape: boolean; /** Whether this glyph is a B-code Bliss character. */ readonly isBlissGlyph: boolean; /** Whether this glyph is an external font character. */ readonly isExternalGlyph: boolean; /** Whether this glyph is the head of its word group. */ readonly isHeadGlyph: boolean; /** Whether this group is a space separator (TSP/QSP). */ readonly isSpaceGroup: boolean; // --- Dimensions (read-only, from snapshot) --- /** Absolute x position of this element's origin. */ readonly x: number; /** Absolute y position of this element's origin. */ readonly y: number; /** Position offset relative to the parent. */ readonly offsetX: number; /** Position offset relative to the parent. */ readonly offsetY: number; /** Total width including indicator overhang. */ readonly width: number; /** Total height. */ readonly height: number; /** Absolute bounding box. */ readonly bounds: ElementBounds; /** Horizontal spacing step to next sibling. */ readonly advanceX: number; /** Width excluding indicators. Equals width when no indicators present. */ readonly baseWidth: number; /** Returns all dimension properties at once. */ measure(): { x: number; y: number; offsetX: number; offsetY: number; width: number; height: number; bounds: ElementBounds; advanceX: number; baseWidth: number; }; // --- Navigation --- /** Returns the head glyph handle within this group. Only valid on group handles. */ headGlyph(): ElementHandle | null; /** Returns the glyph at the given index within this group. Negative indices count from the end (-1 = last). Only valid on group handles. */ glyph(index: number): ElementHandle | null; /** * Returns the part at the given index. Negative indices count from the end (-1 = last). * Valid on glyph handles (returns a part of the glyph) and * part handles (returns a nested sub-part). */ part(index: number): ElementHandle | null; // --- Mutation: add/insert --- /** Appends a glyph to this group. Only valid on group handles. */ addGlyph(code: string, opts?: BlissOptions | OptionLayers): this; /** Inserts a glyph at the given index in this group. Only valid on group handles. */ insertGlyph(index: number, code: string, opts?: BlissOptions | OptionLayers): this; /** Appends a part to this glyph. On group handles, delegates to the last glyph. */ addPart(code: string, opts?: BlissOptions | OptionLayers): this; /** Inserts a part at the given index in this glyph. Only valid on glyph handles. */ insertPart(index: number, code: string, opts?: BlissOptions | OptionLayers): this; // --- Mutation: remove/replace (self) --- /** Removes this element. Cascades: removing the last part removes its glyph, etc. */ remove(): undefined; /** Disconnects this element from its parent without cascade cleanup. May leave empty containers. */ detach(): undefined; /** Replaces this element with a new one. Valid on glyph and part handles. */ replace(code: string, opts?: BlissOptions | OptionLayers): this; // --- Mutation: remove/replace (parent-centric, by index) --- /** Removes the glyph at the given index in this group. Only valid on group handles. */ removeGlyph(index: number): this; /** Replaces the glyph at the given index in this group. Only valid on group handles. */ replaceGlyph(index: number, code: string, opts?: BlissOptions | OptionLayers): this; /** Removes the part at the given index in this glyph. Only valid on glyph handles. */ removePart(index: number): this; /** Replaces the part at the given index in this glyph. Only valid on glyph handles. */ replacePart(index: number, code: string, opts?: BlissOptions | OptionLayers): this; // --- Mutation: indicators --- /** * SETS the indicator state on this element from the given indicator codes, * preserving an existing semantic indicator unless `{ stripSemantic: true }`. * * Polymorphic by handle level: * - **Glyph handle** — character-level: bakes the indicators into the * glyph's parts. `flatten` has no effect (glyph indicators are already flat). * - **Group handle** — word-level: sets the reversible `wordIndicators` * overlay (the DSL `;;` channel), leaving the base glyphs intact so a later * `clearIndicators()` restores them. `{ flatten: true }` opts out of the * overlay and bakes onto the head glyph as character-level parts instead * (the pre-overlay, character-level shape). A `flatten` apply keeps the * overlay when its code applies no indicator (it would bake nothing), rather * than silently dropping the overlay. * * An EMPTY code (omitted, `''`, or whitespace-only) is allowed as the * deliberate empty indicator set: on a group handle it stores the empty `;;` * overlay (render-significant — it hides the head's own character-level * indicators and adds none; with `{ stripSemantic: true }` it stores the * `;;!` strip overlay); on a glyph handle it has the same state effect as * `clearIndicators()`, with `stripSemantic` additionally removing the * semantic (a bare base stays a harmless silent no-op, like a trailing `;`). * * A NON-empty code whose codes are ALL invalid (non-indicators or unknown) * REFUSES: nothing mutates (no clearing, no stripping) and each rejected * code warns (`NON_INDICATOR_AS_CHARACTER_INDICATOR` / * `NON_INDICATOR_AS_WORD_INDICATOR` / `UNKNOWN_CODE`). A mixed list applies * the valid subset and warns per rejected code. One deliberate exception: * on a group handle, `{ stripSemantic: true }` is itself valid overlay * content, so an all-invalid apply WITH it still stores the `;;!` strip * overlay (DSL parity with `WORD;;!ZZ9` — the bad code drops, the `!` * stays). A non-string code throws a `TypeError`. * * The per-surface `flatten` asymmetry is deliberate: it applies only to the * group/word-level overlay, the only surface with a portable `;;` form to * collapse. * * On a glyph handle the first part is always the base, so applying onto a lone * indicator or a detach-emptied glyph attaches the indicator (matching * `addPart`). An apply that targets a glyph that cannot carry an indicator * (a space glyph, or an invalid part pattern) adds an * `NOOP_INDICATOR_MUTATION` warning to `warnings` instead of silently doing * nothing. */ applyIndicators(code?: string, opts?: { stripSemantic?: boolean; flatten?: boolean }): this; /** * The PURE UNDO: removes indicators, always preserving an existing semantic * indicator. Clear takes no `stripSemantic` — that option lives on apply: * `applyIndicators('', { stripSemantic: true })` REMOVES the baked semantic * on a glyph handle, but on a group handle it STORES the reversible `;;!` * strip overlay (hides the head's indicators at render, removes nothing). * * Polymorphic by handle level (see `applyIndicators`): * - **Glyph handle** — removes the glyph's grammatical indicator parts. * - **Group handle** — removes the word-level `wordIndicators` overlay, and * thereby UN-HIDES the head glyph's own character-level indicators: while * the overlay existed it replaced them at render, so clearing it restores * the original characters. `{ flatten: true }` bakes the cleared state * onto the head glyph instead of leaving an overlay. * * A clear that finds nothing to remove (a glyph with no indicators; a group * with no overlay) adds an `NOOP_INDICATOR_MUTATION` warning to `warnings`. */ clearIndicators(opts?: { flatten?: boolean }): this; // --- Mutation: space/word structure --- /** * Splits this word group into two at the glyph boundary, inserting a space * between. Only valid on group handles. A word-level (`;;`) indicator overlay * is a word property: the first (left) part always keeps it. A `^` head * marker is kept only if its glyph lands in the first part; otherwise the * second part re-derives its head. */ splitAt(glyphIndex: number): this; /** * Merges this word group with the next one, removing spaces between them. * Only valid on group handles. The merged word keeps this group's word-level * (`;;`) indicator overlay; an overlay on the absorbed word is dropped and a * `DROPPED_WORD_INDICATOR` warning is added to `warnings`. The absorbed * word's `^` head marker is also dropped (silently); the merged word * resolves a single head. */ mergeWithNext(): this; // --- Mutation: options --- /** Sets or merges options on this element. Accepts flat options (treated as overrides) or { defaults, overrides }. */ setOptions(opts: BlissOptions | OptionLayers): this; /** Removes specific option keys from this element. */ removeOptions(...keys: string[]): this; } // --- Definition types --- /** Context object passed to custom `getPath` functions. */ export interface ShapeContext { [key: string]: any; } /** * Definition for a custom glyph: a base character or a compound indicator, * composed from existing codes. A glyph definition may not bake in an indicator * part unless it is itself a compound indicator (`isIndicator: true`); define a * base+indicator combination as a {@link BareDefinition} alias instead (the * indicator attaches at the use site). `define()` reports a violation in its * `errors` result rather than throwing. */ export interface GlyphDefinition { type?: 'glyph'; codeString: string; /** Marks an all-indicator definition as a compound indicator. */ isIndicator?: boolean; anchorOffsetX?: number; anchorOffsetY?: number; width?: number; shrinksPrecedingWordSpace?: boolean; kerningRules?: Record<string, any>; /** * Default options merged into each use of the definition. Keys must be * well-formed option names (letters, digits, hyphens; camelCase accepted; * names beginning with `on` are rejected, as for any attribute) and may not * include a global-only (builder-canvas) option key such as `margin` or * `grid` — those configure the whole SVG and would be inert on a * definition; `define()` reports a violation in its `errors` result, * `patchDefinition()` throws. */ defaultOptions?: BlissOptions; } /** Definition for a custom shape (rendered via getPath or codeString). */ export interface ShapeDefinition { type?: 'shape'; getPath?: (ctx: ShapeContext) => string; codeString?: string; width?: number; height?: number; x?: number; y?: number; extraPathOptions?: Record<string, any>; /** Default options merged into each use; global-only option keys are rejected (see {@link GlyphDefinition.defaultOptions}). */ defaultOptions?: BlissOptions; } /** Definition for an external glyph (custom rendering around a Unicode character). */ export interface ExternalGlyphDefinition { type: 'externalGlyph'; getPath: (ctx: ShapeContext) => string; width: number; /** The rendered Unicode character (e.g. `'a'` for the external glyph registered as `'Xa'`). */ char: string; y?: number; height?: number; kerningRules?: Record<string, any>; /** Default options merged into each use; global-only option keys are rejected (see {@link GlyphDefinition.defaultOptions}). */ defaultOptions?: BlissOptions; } /** Bare alias definition (maps a code name to a code string). */ export interface BareDefinition { codeString: string; /** Default options merged into each use; global-only option keys are rejected (see {@link GlyphDefinition.defaultOptions}). */ defaultOptions?: BlissOptions; } /** Union of all definition types accepted by `BlissSVGBuilder.define()`. */ export type CodeDefinition = | GlyphDefinition | ShapeDefinition | ExternalGlyphDefinition | BareDefinition; /** Definition type identifiers. */ export type DefinitionType = 'shape' | 'glyph' | 'externalGlyph' | 'bare' | 'space'; /** Result returned by `BlissSVGBuilder.define()`. */ export interface DefineResult { defined: string[]; skipped: string[]; errors: string[]; } /** Frozen metadata returned by `BlissSVGBuilder.getDefinition()`. */ export interface DefinitionMetadata { readonly type: DefinitionType; readonly isBuiltIn: boolean; readonly [key: string]: any; } // --- Serialization output --- /** * Normalized parsed structure returned by `toJSON()`. Describes the default * (authoring) shape: the composition the user wrote, plus `isIndicator`/`width` * on indicator parts. Definition-derived metadata * (`isBlissGlyph`/`isExternalGlyph`/`char`/`kerningRules` and part * `anchorOffsetX`/`anchorOffsetY`) is omitted — it is fully re-derived from the * code when this object is passed back to the constructor. `{ deep: true }` * retains that metadata plus nested sub-parts for `toString()`/`merge()`; those * extra fields are not part of this type. */ export interface BlissJSON { options?: Record<string, string>; groups: Array<{ options?: Record<string, string | boolean>; /** * Word-level fail-render flag: set when the parser rejects the whole word * (e.g. a malformed `;;` indicator that is not the trailing part of the * word). The word renders as a single error placeholder (`error-placeholder` * on) or nothing (off) and emits one `MALFORMED_WORD_INDICATOR` warning. * `errorSource` is the original offending string, re-emitted verbatim by * `toString()` so the malformation round-trips. */ errorCode?: WarningCode; error?: string; errorSource?: string; /** * Word-level indicator overlay (the DSL `;;` form): stored on the word and * resolved onto the head glyph at render. Present in default output (kept * by default); absent when there is no word-level indicator. */ wordIndicators?: { codes: string[]; stripSemantic: boolean }; glyphs?: Array<{ codeName?: string; options?: Record<string, string | boolean>; isHeadGlyph?: boolean; parts?: Array<{ codeName: string; options?: Record<string, string | boolean>; /** Present (true) only on an indicator part. */ isIndicator?: boolean; /** Rendered indicator width; present only on an indicator part. */ width?: number; x?: number; y?: number; parts?: Array<any>; }>; }>; }>; } // --- Warnings --- /** * Every warning code the builder can emit. Mirrors the `WARNING_CODES` registry * in `bliss-constants.js` (the runtime source of truth). */ export type WarningCode = | 'MALFORMED_GLOBAL_OPTIONS' | 'MALFORMED_GROUP_OPTIONS' | 'MALFORMED_WORD_INDICATOR' | 'MALFORMED_COORDINATES' | 'MALFORMED_KERNING_VALUE' | 'MISPLACED_HEAD_MARKER' | 'MISPLACED_CHARACTER_INDICATOR' | 'MISPLACED_WORD_INDICATOR' | 'MISPLACED_PART_OPTION' | 'MISPLACED_CHARACTER_OPTION' | 'MISPLACED_GROUP_OPTION' | 'MISPLACED_GLOBAL_OPTION' | 'MULTIPLE_HEAD_MARKERS' | 'MULTIPLE_OPTION_BRACKETS' | 'DUPLICATE_KEY' | 'UNKNOWN_CODE' | 'DROPPED_WORD_INDICATOR' | 'UNSUPPORTED_TEXT_BLOCKS' | 'NOOP_INDICATOR_MUTATION' | 'COMPOSITE_AS_PART' | 'WORD_AS_PART' | 'NON_INDICATOR_AS_WORD_INDICATOR' | 'NON_INDICATOR_AS_CHARACTER_INDICATOR'; /** A warning generated when the builder encounters a problem it can recover from. */ export interface Warning { /** Warning type identifier (see `WarningCode`). */ readonly code: WarningCode; /** Human-readable description of the issue. */ readonly message: string; /** The problematic DSL code that triggered the warning. */ readonly source: string; } // --- Builder stats --- export interface BuilderStats { groupCount: number; glyphCount: number; } // --- Main class --- export declare class BlissSVGBuilder { /** * Creates an instance of BlissSVGBuilder. * @param input - A DSL string, a plain object from `toJSON()`, or omitted for an empty builder * @param options - Defaults/overrides to merge, or flat options treated as overrides */ constructor(input?: string | BlissJSON, options?: BlissOptions | OptionLayers); /** * Library version string (set at build time). * Also exported as the named `LIB_VERSION` constant. */ static readonly LIB_VERSION: string; // --- SVG output (getters) --- /** SVG content (path elements and groups) without the outer `<svg>` wrapper. */ readonly svgContent: string; /** Parsed SVG as a DOM element. Requires a DOM environment. */ readonly svgElement: SVGSVGElement; /** Complete SVG markup without XML declaration. */ readonly svgCode: string; /** Complete SVG markup with XML declaration. */ readonly standaloneSvg: string; // --- Warnings --- /** Warnings generated during parsing/rendering (unknown codes, invalid syntax, etc.). */ readonly warnings: readonly Warning[]; // --- Element tree (getters) --- /** Root element snapshot (frozen tree of all elements). */ readonly elements: ElementSnapshot; /** Non-space group snapshots. */ readonly groups: readonly ElementSnapshot[]; /** Group and glyph counts. */ readonly stats: BuilderStats; // --- Traversal and querying --- /** Depth-first traversal of all element snapshots. Return `false` to stop early. */ traverse(callback: (el: ElementSnapshot) => boolean | void): void; /** Returns all element snapshots matching the predicate. */ query(predicate: (el: ElementSnapshot) => boolean): ElementSnapshot[]; /** Looks up an element handle by its snapshot key. */ getElementByKey(key: string): ElementHandle | null; /** Returns a handle to the non-space group at the given index. Negative indices count from the end (-1 = last). */ group(index: number): ElementHandle | null; /** Returns a handle to any group (including spaces) at the given raw index. Negative indices count from the end (-1 = last). */ element(index: number): ElementHandle | null; /** Total number of raw groups (including space groups). */ readonly elementCount: number; /** Returns a handle to the glyph at the given flat index across all groups. Negative indices count from the end (-1 = last). */ glyph(flatIndex: number): ElementHandle | null; /** Returns a handle to the part at the given flat index across all glyphs. Negative indices count from the end (-1 = last). */ part(flatIndex: number): ElementHandle | null; /** Returns the root element snapshot (alias for `elements`). */ snapshot(): ElementSnapshot; // --- Building and manipulation --- /** Appends a new glyph group with automatic space management. */ addGroup(code: string, opts?: BlissOptions | OptionLayers): this; /** Appends a glyph to the last non-space group (creates one if empty). */ addGlyph(code: string, opts?: BlissOptions | OptionLayers): this; /** Appends a part to the last glyph of the last group. */ addPart(code: string, opts?: BlissOptions | OptionLayers): this; /** Inserts a group at the given index. Negative indices count from the end. */ insertGroup(index: number, code: string, opts?: BlissOptions | OptionLayers): this; /** Removes the group at the given index. Negative indices count from the end. */ removeGroup(index: number): this; /** Replaces the group at the given index with new content. Negative indices count from the end. */ replaceGroup(index: number, code: string, opts?: BlissOptions | OptionLayers): this; /** Merges another builder's content into this one. Appends the other builder's groups with a space between. The other builder's global options are discarded. */ merge(other: BlissSVGBuilder): this; /** Splits this builder at the given group index. This builder keeps the left half; a new builder with the right half is returned. Both share the same global options. */ splitAt(groupIndex: number): BlissSVGBuilder; /** Appends a raw group with no automatic space management. SP auto-resolves to TSP/QSP. */ addElement(code: string, opts?: BlissOptions | OptionLayers): this; /** Inserts a raw group at the given index with no automatic space management. SP auto-resolves. */ insertElement(index: number, code: string, opts?: BlissOptions | OptionLayers): this; /** Removes the raw group at the given index (plain splice, no space cleanup). */ removeElement(index: number): this; /** Replaces the raw group at the given index with new content. */ replaceElement(index: number, code: string, opts?: BlissOptions | OptionLayers): this; /** Removes all content from the builder. */ clear(): this; // --- Serialization --- /** * Returns a portable DSL string. Custom codes are decomposed to built-in * codes by default; pass `{ preserve: true }` to keep custom names. * * `flattenIndicators` collapses word-level (`;;`) indicators onto the head * glyph as character-level `;`, reproducing the pre-overlay output. It is the * same concept as `applyIndicators(code, { flatten })`; the name is qualified * here only because `toString`/`toJSON` lack the "indicator" context the * method name provides. */ toString(options?: { preserve?: boolean; flattenIndicators?: boolean }): string; /** * Returns a normalized parsed structure (plain object). Custom glyph codes * are resolved to built-in codes by default; pass `{ preserve: true }` to keep them. * * `flattenIndicators` bakes word-level (`;;`) indicators onto the head and * omits the `wordIndicators` field (see `toString`). * * `deep` keeps nested sub-parts and all definition-derived metadata (consumed * by `toString()`/`merge()`); the default output omits those (they are * re-derived from the code on reconstruction) and is the authoring shape * described by {@link BlissJSON}. */ toJSON(options?: { preserve?: boolean; deep?: boolean; flattenIndicators?: boolean }): BlissJSON; // --- Static: definition management --- /** * Defines one or more custom codes (glyphs, shapes, external glyphs, or bare aliases). * @param definitions - Map of code names to their definitions * @param options - Pass `{ overwrite: true }` to replace existing custom definitions */ static define( definitions: Record<string, CodeDefinition>, options?: { overwrite?: boolean } ): DefineResult; /** Returns `true` if a code is defined (built-in or custom). */ static isDefined(code: string): boolean; /** Returns frozen metadata for a code, or `null` if not found. */ static getDefinition(code: string): DefinitionMetadata | null; /** Lists all defined codes, optionally filtered by type. */ static listDefinitions(filter?: { type?: DefinitionType }): string[]; /** Removes a custom definition. Throws if the code is built-in. */ static removeDefinition(code: string): boolean; /** * Patches properties on an existing custom definition. * Only keys valid for the definition's type are accepted. * Built-in definitions cannot be patched. */ static patchDefinition(code: string, changes: Partial<CodeDefinition>): { patched: true }; } /** * Library version string (set at build time). * Also accessible as the `BlissSVGBuilder.LIB_VERSION` static. */ export declare const LIB_VERSION: string; export default BlissSVGBuilder;