notations 1.0.2 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +1 -0
  2. package/dist/notations.umd.js +4234 -12211
  3. package/dist/notations.umd.min.js +2 -3
  4. package/dist/notations.umd.min.js.map +1 -1
  5. package/lib/cjs/block.d.ts +4 -0
  6. package/lib/cjs/block.js +24 -0
  7. package/lib/cjs/block.js.map +1 -1
  8. package/lib/cjs/core.d.ts +15 -0
  9. package/lib/cjs/core.js +144 -4
  10. package/lib/cjs/core.js.map +1 -1
  11. package/lib/cjs/entity.d.ts +4 -0
  12. package/lib/cjs/entity.js +12 -0
  13. package/lib/cjs/entity.js.map +1 -1
  14. package/lib/cjs/events.d.ts +56 -0
  15. package/lib/cjs/events.js +27 -0
  16. package/lib/cjs/events.js.map +1 -0
  17. package/lib/cjs/index.d.ts +1 -0
  18. package/lib/cjs/index.js +1 -0
  19. package/lib/cjs/index.js.map +1 -1
  20. package/lib/cjs/parser.js +1 -1
  21. package/lib/cjs/parser.js.map +1 -1
  22. package/lib/cjs/shapes.d.ts +11 -0
  23. package/lib/cjs/shapes.js +25 -2
  24. package/lib/cjs/shapes.js.map +1 -1
  25. package/lib/cjs/web/components/DockViewPlayground.d.ts +51 -0
  26. package/lib/cjs/web/components/DockViewPlayground.js +364 -0
  27. package/lib/cjs/web/components/DockViewPlayground.js.map +1 -0
  28. package/lib/cjs/web/components/NotationBlock.d.ts +35 -0
  29. package/lib/cjs/web/components/NotationBlock.js +219 -0
  30. package/lib/cjs/web/components/NotationBlock.js.map +1 -0
  31. package/lib/cjs/web/components/NotebookCell.d.ts +41 -0
  32. package/lib/cjs/web/components/NotebookCell.js +269 -0
  33. package/lib/cjs/web/components/NotebookCell.js.map +1 -0
  34. package/lib/cjs/web/components/NotebookView.d.ts +37 -0
  35. package/lib/cjs/web/components/NotebookView.js +379 -0
  36. package/lib/cjs/web/components/NotebookView.js.map +1 -0
  37. package/lib/cjs/web/components/SideBySideEditor.d.ts +47 -0
  38. package/lib/cjs/web/components/SideBySideEditor.js +171 -0
  39. package/lib/cjs/web/components/SideBySideEditor.js.map +1 -0
  40. package/lib/cjs/web/dockview.d.ts +2 -0
  41. package/lib/cjs/web/dockview.js +11 -0
  42. package/lib/cjs/web/dockview.js.map +1 -0
  43. package/lib/cjs/web/index.d.ts +8 -0
  44. package/lib/cjs/web/index.js +34 -0
  45. package/lib/cjs/web/index.js.map +1 -0
  46. package/lib/cjs/web/types/notebook.d.ts +64 -0
  47. package/lib/cjs/web/types/notebook.js +56 -0
  48. package/lib/cjs/web/types/notebook.js.map +1 -0
  49. package/lib/cjs/web/utils/cellFactory.d.ts +16 -0
  50. package/lib/cjs/web/utils/cellFactory.js +137 -0
  51. package/lib/cjs/web/utils/cellFactory.js.map +1 -0
  52. package/lib/cjs/web/utils/sourceSerializer.d.ts +19 -0
  53. package/lib/cjs/web/utils/sourceSerializer.js +162 -0
  54. package/lib/cjs/web/utils/sourceSerializer.js.map +1 -0
  55. package/lib/esm/block.d.ts +4 -0
  56. package/lib/esm/block.js +24 -0
  57. package/lib/esm/block.js.map +1 -1
  58. package/lib/esm/core.d.ts +15 -0
  59. package/lib/esm/core.js +144 -4
  60. package/lib/esm/core.js.map +1 -1
  61. package/lib/esm/entity.d.ts +4 -0
  62. package/lib/esm/entity.js +12 -0
  63. package/lib/esm/entity.js.map +1 -1
  64. package/lib/esm/events.d.ts +56 -0
  65. package/lib/esm/events.js +24 -0
  66. package/lib/esm/events.js.map +1 -0
  67. package/lib/esm/index.d.ts +1 -0
  68. package/lib/esm/index.js +1 -0
  69. package/lib/esm/index.js.map +1 -1
  70. package/lib/esm/parser.js +1 -1
  71. package/lib/esm/parser.js.map +1 -1
  72. package/lib/esm/shapes.d.ts +11 -0
  73. package/lib/esm/shapes.js +24 -2
  74. package/lib/esm/shapes.js.map +1 -1
  75. package/lib/esm/web/components/DockViewPlayground.d.ts +51 -0
  76. package/lib/esm/web/components/DockViewPlayground.js +358 -0
  77. package/lib/esm/web/components/DockViewPlayground.js.map +1 -0
  78. package/lib/esm/web/components/NotationBlock.d.ts +35 -0
  79. package/lib/esm/web/components/NotationBlock.js +216 -0
  80. package/lib/esm/web/components/NotationBlock.js.map +1 -0
  81. package/lib/esm/web/components/NotebookCell.d.ts +41 -0
  82. package/lib/esm/web/components/NotebookCell.js +266 -0
  83. package/lib/esm/web/components/NotebookCell.js.map +1 -0
  84. package/lib/esm/web/components/NotebookView.d.ts +37 -0
  85. package/lib/esm/web/components/NotebookView.js +376 -0
  86. package/lib/esm/web/components/NotebookView.js.map +1 -0
  87. package/lib/esm/web/components/SideBySideEditor.d.ts +47 -0
  88. package/lib/esm/web/components/SideBySideEditor.js +168 -0
  89. package/lib/esm/web/components/SideBySideEditor.js.map +1 -0
  90. package/lib/esm/web/dockview.d.ts +2 -0
  91. package/lib/esm/web/dockview.js +3 -0
  92. package/lib/esm/web/dockview.js.map +1 -0
  93. package/lib/esm/web/index.d.ts +8 -0
  94. package/lib/esm/web/index.js +9 -0
  95. package/lib/esm/web/index.js.map +1 -0
  96. package/lib/esm/web/types/notebook.d.ts +64 -0
  97. package/lib/esm/web/types/notebook.js +50 -0
  98. package/lib/esm/web/types/notebook.js.map +1 -0
  99. package/lib/esm/web/utils/cellFactory.d.ts +16 -0
  100. package/lib/esm/web/utils/cellFactory.js +127 -0
  101. package/lib/esm/web/utils/cellFactory.js.map +1 -0
  102. package/lib/esm/web/utils/sourceSerializer.d.ts +19 -0
  103. package/lib/esm/web/utils/sourceSerializer.js +154 -0
  104. package/lib/esm/web/utils/sourceSerializer.js.map +1 -0
  105. package/package.json +43 -1
@@ -3,6 +3,7 @@ import { Entity } from "./entity";
3
3
  import { Cycle } from "./cycle";
4
4
  import { Line } from "./core";
5
5
  import { LayoutParams } from "./layouts";
6
+ import { BlockObserver } from "./events";
6
7
  export declare class RoleDef {
7
8
  name: string;
8
9
  notesOnly: boolean;
@@ -31,7 +32,10 @@ export declare class Block extends Entity {
31
32
  private _parentBlock;
32
33
  protected _currRoleDef: TSU.Nullable<RoleDef>;
33
34
  protected _currentLine: TSU.Nullable<Line>;
35
+ private _observers;
34
36
  constructor(blockType: string, parent?: TSU.Nullable<Block>, name?: TSU.Nullable<string>);
37
+ addObserver(observer: BlockObserver<BlockItem, Block>): () => void;
38
+ removeObserver(observer: BlockObserver<BlockItem, Block>): void;
35
39
  children(): BlockItem[];
36
40
  get parentBlock(): TSU.Nullable<Block>;
37
41
  get cycle(): TSU.Nullable<Cycle>;
package/lib/cjs/block.js CHANGED
@@ -49,6 +49,7 @@ class Block extends entity_1.Entity {
49
49
  this._parentBlock = null;
50
50
  this._currRoleDef = null;
51
51
  this._currentLine = null;
52
+ this._observers = [];
52
53
  this._unnamedLayoutParams = [];
53
54
  this._namedLayoutParams = new Map();
54
55
  this._layoutParams = null;
@@ -59,6 +60,16 @@ class Block extends entity_1.Entity {
59
60
  this.setParent(parent);
60
61
  }
61
62
  }
63
+ addObserver(observer) {
64
+ this._observers.push(observer);
65
+ return () => this.removeObserver(observer);
66
+ }
67
+ removeObserver(observer) {
68
+ const index = this._observers.indexOf(observer);
69
+ if (index >= 0) {
70
+ this._observers.splice(index, 1);
71
+ }
72
+ }
62
73
  children() {
63
74
  return this.blockItems;
64
75
  }
@@ -204,14 +215,27 @@ class Block extends entity_1.Entity {
204
215
  return rd;
205
216
  }
206
217
  addBlockItem(item) {
218
+ var _a;
219
+ const index = this.blockItems.length;
207
220
  item.setParent(this);
208
221
  this.blockItems.push(item);
222
+ if (this._eventsEnabled) {
223
+ for (const observer of this._observers) {
224
+ (_a = observer.onItemAdded) === null || _a === void 0 ? void 0 : _a.call(observer, this, item, index);
225
+ }
226
+ }
209
227
  }
210
228
  removeBlockItem(item) {
229
+ var _a;
211
230
  const index = this.blockItems.indexOf(item);
212
231
  if (index >= 0) {
213
232
  this.blockItems.splice(index, 1);
214
233
  item.setParent(null);
234
+ if (this._eventsEnabled) {
235
+ for (const observer of this._observers) {
236
+ (_a = observer.onItemRemoved) === null || _a === void 0 ? void 0 : _a.call(observer, this, item, index);
237
+ }
238
+ }
215
239
  }
216
240
  return index;
217
241
  }
@@ -1 +1 @@
1
- {"version":3,"file":"block.js","sourceRoot":"","sources":["../../src/block.ts"],"names":[],"mappings":"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","sourcesContent":["import * as TSU from \"@panyam/tsutils\";\nimport { Entity } from \"./entity\";\nimport { Cycle } from \"./cycle\";\nimport { Line } from \"./core\";\nimport { LayoutParams } from \"./layouts\";\n\n/**\n * Definition of a role in a block context.\n * This is used for block-scoped role definitions.\n */\nexport class RoleDef {\n /** Name of the role */\n name = \"\";\n\n /** Whether this role contains only notes (true) or can also contain syllables/text (false) */\n notesOnly = false;\n\n /** Index of this role in the notation */\n index = 0;\n}\n\n/**\n * Represents a raw block of content in the notation.\n * Raw blocks can contain arbitrary content like markdown, HTML, etc.\n */\nexport class RawBlock extends Entity {\n readonly TYPE: string = \"RawBlock\";\n\n /**\n * Creates a new RawBlock.\n * @param content The content of the block\n * @param contentType The type of content (e.g., \"md\" for markdown)\n */\n constructor(\n public content: string,\n public contentType: string = \"md\",\n ) {\n super();\n }\n\n /**\n * Returns a debug-friendly representation of this raw block.\n * @returns An object containing debug information\n */\n debugValue(): any {\n return { ...super.debugValue(), content: this.content, contentType: this.contentType };\n }\n}\n\n/**\n * Union type for items that can appear in a block.\n */\nexport type BlockItem = Block | Line | RawBlock;\n\n/**\n * Type guard to check if an entity is a Block.\n */\nexport function isBlock(item: BlockItem): item is Block {\n return item.TYPE === \"Block\";\n}\n\n/**\n * Type guard to check if an entity is a Line.\n */\nexport function isLine(item: BlockItem): item is Line {\n return item.TYPE === \"Line\";\n}\n\n/**\n * Type guard to check if an entity is a RawBlock.\n */\nexport function isRawBlock(item: BlockItem): item is RawBlock {\n return item.TYPE === \"RawBlock\";\n}\n\n/**\n * Represents a scoped block created by a command with braces.\n * For example: \\section(\"Pallavi\") { ... }\n *\n * Blocks inherit properties from their parent Block and can override them locally.\n * Properties are resolved lazily by walking up the tree.\n *\n * Block = Command + Children (unified model)\n */\nexport class Block extends Entity {\n readonly TYPE: string = \"Block\";\n\n /** The type of block (e.g., \"section\", \"repeat\", \"cycle\") */\n readonly blockType: string;\n\n /** Optional name for the block (e.g., section name) */\n readonly name: TSU.Nullable<string>;\n\n /** Child items (before expansion by subclasses) */\n readonly blockItems: BlockItem[] = [];\n\n // Local properties\n localCycle: TSU.Nullable<Cycle> = null;\n localAtomsPerBeat: TSU.Nullable<number> = null;\n localBreaks: TSU.Nullable<number[]> = null;\n readonly localRoles = new Map<string, RoleDef>();\n\n // Store parent reference (Block or null for root)\n private _parentBlock: TSU.Nullable<Block> = null;\n\n // State tracking for command application (protected for Notation override)\n protected _currRoleDef: TSU.Nullable<RoleDef> = null;\n protected _currentLine: TSU.Nullable<Line> = null;\n\n /**\n * Creates a new Block.\n * @param blockType The type of block (e.g., \"section\", \"group\")\n * @param parent The parent block (null for root)\n * @param name Optional name for the block\n */\n constructor(blockType: string, parent: TSU.Nullable<Block> = null, name: TSU.Nullable<string> = null) {\n super();\n this.blockType = blockType;\n this.name = name;\n this._parentBlock = parent;\n // Also set Entity's parent for tree traversal\n if (parent) {\n this.setParent(parent);\n }\n }\n\n /**\n * Returns the expanded children for layout iteration.\n * Subclasses can override this to transform children (e.g., Repeat, Section).\n */\n children(): BlockItem[] {\n return this.blockItems;\n }\n\n /**\n * Gets the parent block.\n */\n get parentBlock(): TSU.Nullable<Block> {\n return this._parentBlock;\n }\n\n // ============================================\n // Property inheritance via tree walking\n // ============================================\n\n /**\n * Gets the effective cycle by walking up the tree.\n */\n get cycle(): TSU.Nullable<Cycle> {\n if (this.localCycle !== null) {\n return this.localCycle;\n }\n return this.parentBlock?.cycle ?? null;\n }\n\n /**\n * Gets the effective atoms per beat by walking up the tree.\n * Defaults to 1 if not set anywhere in the tree.\n */\n get atomsPerBeat(): number {\n if (this.localAtomsPerBeat !== null) {\n return this.localAtomsPerBeat;\n }\n return this.parentBlock?.atomsPerBeat ?? 1;\n }\n\n /**\n * Gets the effective line breaks by walking up the tree.\n * Defaults to empty array if not set anywhere.\n */\n get breaks(): number[] {\n if (this.localBreaks !== null) {\n return this.localBreaks;\n }\n return this.parentBlock?.breaks ?? [];\n }\n\n // ============================================\n // Layout parameters management\n // ============================================\n\n /** Layout parameters caching for this block scope */\n private _unnamedLayoutParams: LayoutParams[] = [];\n private _namedLayoutParams = new Map<string, LayoutParams>();\n private _layoutParams: LayoutParams | null = null;\n\n /**\n * Gets the unnamed layout parameters for this block.\n */\n get unnamedLayoutParams(): ReadonlyArray<LayoutParams> {\n return this._unnamedLayoutParams;\n }\n\n /**\n * Gets the named layout parameters for this block.\n */\n get namedLayoutParams(): ReadonlyMap<string, LayoutParams> {\n return this._namedLayoutParams;\n }\n\n /**\n * Gets the current layout parameters for this block scope.\n * Uses the effective cycle, atomsPerBeat, and breaks from tree walking.\n * Creates or finds a matching LayoutParams if needed.\n */\n get layoutParams(): LayoutParams {\n if (this._layoutParams == null) {\n // Find or create layout params matching current effective values\n this._layoutParams = this.findUnnamedLayoutParams();\n if (this._layoutParams == null) {\n this._layoutParams = this.snapshotLayoutParams();\n this._unnamedLayoutParams.push(this._layoutParams);\n }\n }\n return this._layoutParams;\n }\n\n /**\n * Resets the current layout parameters to null.\n * Called when layout-affecting properties change.\n */\n resetLayoutParams(): void {\n this._layoutParams = null;\n this.resetLine();\n }\n\n /**\n * Creates a snapshot of the current layout parameters.\n * @returns A new LayoutParams object with the current effective settings\n */\n protected snapshotLayoutParams(): LayoutParams {\n const effectiveCycle = this.cycle;\n if (effectiveCycle == null) {\n throw new Error(\"Cannot create layout params: no cycle defined\");\n }\n return new LayoutParams({\n cycle: effectiveCycle,\n beatDuration: this.atomsPerBeat,\n layout: this.breaks,\n });\n }\n\n /**\n * Finds an unnamed layout parameters object that matches the current effective settings.\n * @returns Matching layout parameters, or null if none found\n */\n protected findUnnamedLayoutParams(): LayoutParams | null {\n const effectiveCycle = this.cycle;\n if (effectiveCycle == null) return null;\n\n return (\n this._unnamedLayoutParams.find((lp) => {\n return (\n lp.beatDuration == this.atomsPerBeat && effectiveCycle.equals(lp.cycle) && lp.lineBreaksEqual(this.breaks)\n );\n }) || null\n );\n }\n\n /**\n * Ensures that named layout parameters with the given name exist.\n * @param name The name of the layout parameters\n * @returns The layout parameters\n */\n ensureNamedLayoutParams(name: string): LayoutParams {\n let lp = this._namedLayoutParams.get(name) || null;\n if (lp == null || this._layoutParams != lp) {\n if (lp == null) {\n // Create new named layout params\n lp = this.snapshotLayoutParams();\n this._namedLayoutParams.set(name, lp);\n } else {\n // Copy named LPs attributes into our locals\n this.localCycle = lp.cycle;\n this.localAtomsPerBeat = lp.beatDuration;\n this.localBreaks = lp.lineBreaks;\n }\n this._layoutParams = lp;\n this.resetLine();\n }\n return this._layoutParams!;\n }\n\n /**\n * Gets a role definition by name, walking up the tree if not found locally.\n * @param name The name of the role\n */\n getRole(name: string): TSU.Nullable<RoleDef> {\n const local = this.localRoles.get(name.toLowerCase());\n if (local) {\n return local;\n }\n return this.parentBlock?.getRole(name) ?? null;\n }\n\n // ============================================\n // State tracking for command application\n // ============================================\n\n /**\n * Gets the current role definition.\n * Falls back to parent's current role or the last defined role.\n */\n get currRoleDef(): TSU.Nullable<RoleDef> {\n if (this._currRoleDef !== null) {\n return this._currRoleDef;\n }\n // Fall back to parent's current role\n if (this.parentBlock) {\n return this.parentBlock.currRoleDef;\n }\n // Or use the last locally defined role\n const roles = Array.from(this.localRoles.values());\n return roles.length > 0 ? roles[roles.length - 1] : null;\n }\n\n /**\n * Sets the current role by name.\n * If the role doesn't exist, tries to create it via the root container's onMissingRole.\n * @param name The name of the role to activate\n * @throws Error if the role is not found and cannot be created\n */\n setCurrRole(name: string): void {\n name = name.trim().toLowerCase();\n if (name === \"\") {\n throw new Error(\"Role name cannot be empty\");\n }\n let roleDef = this.getRole(name);\n // If role not found, try auto-creation\n if (roleDef == null) {\n // Create the role locally in this block\n // Default: \"sw\" is notes-only, others are not\n roleDef = this.newRoleDef(name, name === \"sw\");\n }\n this._currRoleDef = roleDef;\n }\n\n /**\n * Gets the current line, creating one if needed.\n */\n get currentLine(): Line {\n if (this._currentLine === null) {\n return this.newLine();\n }\n return this._currentLine;\n }\n\n /**\n * Creates a new line in this block.\n */\n newLine(): Line {\n if (this._currentLine !== null && this._currentLine.isEmpty) {\n // Remove empty line before creating new one\n this.removeBlockItem(this._currentLine);\n }\n this._currentLine = new Line();\n this.addBlockItem(this._currentLine);\n return this._currentLine;\n }\n\n /**\n * Resets the current line pointer to null.\n * Called when layout parameters change to force a new line.\n */\n resetLine(): void {\n this._currentLine = null;\n }\n\n /**\n * Creates a new role definition local to this block.\n * @param name The name of the role\n * @param notesOnly Whether this role contains only notes\n */\n newRoleDef(name: string, notesOnly = false): RoleDef {\n name = name.trim().toLowerCase();\n if (name === \"\") {\n throw new Error(\"Role name cannot be empty\");\n }\n if (this.localRoles.has(name)) {\n throw new Error(`Role '${name}' already exists in this block`);\n }\n const rd = new RoleDef();\n rd.name = name;\n rd.notesOnly = notesOnly;\n rd.index = this.localRoles.size;\n this.localRoles.set(name, rd);\n return rd;\n }\n\n // ============================================\n // Child management\n // ============================================\n\n /**\n * Adds a child item to this block.\n * @param item The item to add\n */\n addBlockItem(item: BlockItem): void {\n item.setParent(this);\n this.blockItems.push(item);\n }\n\n /**\n * Removes a child item from this block.\n * @param item The item to remove\n * @returns The index of the removed item, or -1 if not found\n */\n removeBlockItem(item: BlockItem): number {\n const index = this.blockItems.indexOf(item);\n if (index >= 0) {\n this.blockItems.splice(index, 1);\n item.setParent(null);\n }\n return index;\n }\n\n /**\n * Returns a debug-friendly representation of this block.\n */\n debugValue(): any {\n const out: any = {\n ...super.debugValue(),\n blockType: this.blockType,\n blockItems: this.blockItems.map((c) => c.debugValue()),\n };\n if (this.name) {\n out.name = this.name;\n }\n if (this.localCycle) {\n out.localCycle = this.localCycle.uuid;\n }\n if (this.localAtomsPerBeat !== null) {\n out.localAtomsPerBeat = this.localAtomsPerBeat;\n }\n if (this.localBreaks !== null) {\n out.localBreaks = this.localBreaks;\n }\n if (this.localRoles.size > 0) {\n out.localRoles = Array.from(this.localRoles.keys());\n }\n return out;\n }\n}\n\n/**\n * Helper function to find the containing block of an entity by walking up the tree.\n * @param entity The entity to start from\n * @returns The containing Block, or null if not found\n */\nexport function findContainingBlock(entity: Entity): TSU.Nullable<Block> {\n let current: TSU.Nullable<Entity> = entity.parent;\n while (current !== null) {\n if (current instanceof Block) {\n return current;\n }\n current = current.parent;\n }\n return null;\n}\n\n// ============================================\n// Block Subclasses\n// ============================================\n\n/**\n * A section block with a heading.\n * Expands children to include a heading RawBlock followed by the content.\n *\n * Usage: \\section(\"Pallavi\") { ... }\n */\nexport class SectionBlock extends Block {\n constructor(sectionName: string, parent: TSU.Nullable<Block> = null) {\n super(\"section\", parent, sectionName);\n }\n\n /**\n * Expands children to include a heading RawBlock.\n */\n children(): BlockItem[] {\n const heading = new RawBlock(`# ${this.name}`, \"md\");\n return [heading, ...this.blockItems];\n }\n}\n\n/**\n * A repeat block that expands its children N times.\n *\n * Usage: \\repeat(2) { ... }\n */\nexport class RepeatBlock extends Block {\n /** Number of times to repeat (0 = visual markers only) */\n readonly repeatCount: number;\n\n constructor(repeatCount: number, parent: TSU.Nullable<Block> = null) {\n super(\"repeat\", parent);\n this.repeatCount = repeatCount;\n }\n\n /**\n * Expands children by repeating them N times.\n * If count is 0, returns children as-is (visual repeat markers only).\n */\n children(): BlockItem[] {\n if (this.repeatCount <= 0) {\n return this.blockItems;\n }\n const expanded: BlockItem[] = [];\n for (let i = 0; i < this.repeatCount; i++) {\n expanded.push(...this.blockItems);\n }\n return expanded;\n }\n}\n\n/**\n * A cycle block that sets localCycle for scoped notation.\n *\n * Usage: \\cycle(\"|4|4|\") { ... }\n */\nexport class CycleBlock extends Block {\n constructor(cycle: Cycle, parent: TSU.Nullable<Block> = null) {\n super(\"cycle\", parent);\n this.localCycle = cycle;\n }\n}\n\n/**\n * A beat duration block that sets localAtomsPerBeat for scoped notation.\n *\n * Usage: \\beatDuration(2) { ... }\n */\nexport class BeatDurationBlock extends Block {\n constructor(atomsPerBeat: number, parent: TSU.Nullable<Block> = null) {\n super(\"beatduration\", parent);\n this.localAtomsPerBeat = atomsPerBeat;\n }\n}\n\n/**\n * A breaks block that sets localBreaks for scoped notation.\n *\n * Usage: \\breaks(4, 2, 2) { ... }\n */\nexport class BreaksBlock extends Block {\n constructor(breaks: number[], parent: TSU.Nullable<Block> = null) {\n super(\"breaks\", parent);\n this.localBreaks = breaks;\n }\n}\n\n/**\n * A role block that creates a local role definition.\n *\n * Usage: \\role(\"Vocals\", notes=false) { ... }\n */\nexport class RoleBlock extends Block {\n constructor(roleName: string, notesOnly: boolean, parent: TSU.Nullable<Block> = null) {\n super(\"role\", parent);\n // Create the role locally\n this.newRoleDef(roleName, notesOnly);\n }\n}\n\n/**\n * A group block for organizing notation without special semantics.\n *\n * Usage: \\group(\"optional-name\") { ... }\n */\nexport class GroupBlock extends Block {\n constructor(groupName: string | null, parent: TSU.Nullable<Block> = null) {\n super(\"group\", parent, groupName);\n }\n}\n"]}
1
+ {"version":3,"file":"block.js","sourceRoot":"","sources":["../../src/block.ts"],"names":[],"mappings":"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","sourcesContent":["import * as TSU from \"@panyam/tsutils\";\nimport { Entity } from \"./entity\";\nimport { Cycle } from \"./cycle\";\nimport { Line } from \"./core\";\nimport { LayoutParams } from \"./layouts\";\nimport { BlockObserver } from \"./events\";\n\n/**\n * Definition of a role in a block context.\n * This is used for block-scoped role definitions.\n */\nexport class RoleDef {\n /** Name of the role */\n name = \"\";\n\n /** Whether this role contains only notes (true) or can also contain syllables/text (false) */\n notesOnly = false;\n\n /** Index of this role in the notation */\n index = 0;\n}\n\n/**\n * Represents a raw block of content in the notation.\n * Raw blocks can contain arbitrary content like markdown, HTML, etc.\n */\nexport class RawBlock extends Entity {\n readonly TYPE: string = \"RawBlock\";\n\n /**\n * Creates a new RawBlock.\n * @param content The content of the block\n * @param contentType The type of content (e.g., \"md\" for markdown)\n */\n constructor(\n public content: string,\n public contentType: string = \"md\",\n ) {\n super();\n }\n\n /**\n * Returns a debug-friendly representation of this raw block.\n * @returns An object containing debug information\n */\n debugValue(): any {\n return { ...super.debugValue(), content: this.content, contentType: this.contentType };\n }\n}\n\n/**\n * Union type for items that can appear in a block.\n */\nexport type BlockItem = Block | Line | RawBlock;\n\n/**\n * Type guard to check if an entity is a Block.\n */\nexport function isBlock(item: BlockItem): item is Block {\n return item.TYPE === \"Block\";\n}\n\n/**\n * Type guard to check if an entity is a Line.\n */\nexport function isLine(item: BlockItem): item is Line {\n return item.TYPE === \"Line\";\n}\n\n/**\n * Type guard to check if an entity is a RawBlock.\n */\nexport function isRawBlock(item: BlockItem): item is RawBlock {\n return item.TYPE === \"RawBlock\";\n}\n\n/**\n * Represents a scoped block created by a command with braces.\n * For example: \\section(\"Pallavi\") { ... }\n *\n * Blocks inherit properties from their parent Block and can override them locally.\n * Properties are resolved lazily by walking up the tree.\n *\n * Block = Command + Children (unified model)\n */\nexport class Block extends Entity {\n readonly TYPE: string = \"Block\";\n\n /** The type of block (e.g., \"section\", \"repeat\", \"cycle\") */\n readonly blockType: string;\n\n /** Optional name for the block (e.g., section name) */\n readonly name: TSU.Nullable<string>;\n\n /** Child items (before expansion by subclasses) */\n readonly blockItems: BlockItem[] = [];\n\n // Local properties\n localCycle: TSU.Nullable<Cycle> = null;\n localAtomsPerBeat: TSU.Nullable<number> = null;\n localBreaks: TSU.Nullable<number[]> = null;\n readonly localRoles = new Map<string, RoleDef>();\n\n // Store parent reference (Block or null for root)\n private _parentBlock: TSU.Nullable<Block> = null;\n\n // State tracking for command application (protected for Notation override)\n protected _currRoleDef: TSU.Nullable<RoleDef> = null;\n protected _currentLine: TSU.Nullable<Line> = null;\n\n /**\n * Observers that receive notifications when block items change.\n */\n private _observers: BlockObserver<BlockItem, Block>[] = [];\n\n /**\n * Creates a new Block.\n * @param blockType The type of block (e.g., \"section\", \"group\")\n * @param parent The parent block (null for root)\n * @param name Optional name for the block\n */\n constructor(blockType: string, parent: TSU.Nullable<Block> = null, name: TSU.Nullable<string> = null) {\n super();\n this.blockType = blockType;\n this.name = name;\n this._parentBlock = parent;\n // Also set Entity's parent for tree traversal\n if (parent) {\n this.setParent(parent);\n }\n }\n\n /**\n * Adds an observer to receive block item change notifications.\n * @param observer The observer to add\n * @returns A function to remove the observer\n */\n addObserver(observer: BlockObserver<BlockItem, Block>): () => void {\n this._observers.push(observer);\n return () => this.removeObserver(observer);\n }\n\n /**\n * Removes an observer.\n * @param observer The observer to remove\n */\n removeObserver(observer: BlockObserver<BlockItem, Block>): void {\n const index = this._observers.indexOf(observer);\n if (index >= 0) {\n this._observers.splice(index, 1);\n }\n }\n\n /**\n * Returns the expanded children for layout iteration.\n * Subclasses can override this to transform children (e.g., Repeat, Section).\n */\n children(): BlockItem[] {\n return this.blockItems;\n }\n\n /**\n * Gets the parent block.\n */\n get parentBlock(): TSU.Nullable<Block> {\n return this._parentBlock;\n }\n\n // ============================================\n // Property inheritance via tree walking\n // ============================================\n\n /**\n * Gets the effective cycle by walking up the tree.\n */\n get cycle(): TSU.Nullable<Cycle> {\n if (this.localCycle !== null) {\n return this.localCycle;\n }\n return this.parentBlock?.cycle ?? null;\n }\n\n /**\n * Gets the effective atoms per beat by walking up the tree.\n * Defaults to 1 if not set anywhere in the tree.\n */\n get atomsPerBeat(): number {\n if (this.localAtomsPerBeat !== null) {\n return this.localAtomsPerBeat;\n }\n return this.parentBlock?.atomsPerBeat ?? 1;\n }\n\n /**\n * Gets the effective line breaks by walking up the tree.\n * Defaults to empty array if not set anywhere.\n */\n get breaks(): number[] {\n if (this.localBreaks !== null) {\n return this.localBreaks;\n }\n return this.parentBlock?.breaks ?? [];\n }\n\n // ============================================\n // Layout parameters management\n // ============================================\n\n /** Layout parameters caching for this block scope */\n private _unnamedLayoutParams: LayoutParams[] = [];\n private _namedLayoutParams = new Map<string, LayoutParams>();\n private _layoutParams: LayoutParams | null = null;\n\n /**\n * Gets the unnamed layout parameters for this block.\n */\n get unnamedLayoutParams(): ReadonlyArray<LayoutParams> {\n return this._unnamedLayoutParams;\n }\n\n /**\n * Gets the named layout parameters for this block.\n */\n get namedLayoutParams(): ReadonlyMap<string, LayoutParams> {\n return this._namedLayoutParams;\n }\n\n /**\n * Gets the current layout parameters for this block scope.\n * Uses the effective cycle, atomsPerBeat, and breaks from tree walking.\n * Creates or finds a matching LayoutParams if needed.\n */\n get layoutParams(): LayoutParams {\n if (this._layoutParams == null) {\n // Find or create layout params matching current effective values\n this._layoutParams = this.findUnnamedLayoutParams();\n if (this._layoutParams == null) {\n this._layoutParams = this.snapshotLayoutParams();\n this._unnamedLayoutParams.push(this._layoutParams);\n }\n }\n return this._layoutParams;\n }\n\n /**\n * Resets the current layout parameters to null.\n * Called when layout-affecting properties change.\n */\n resetLayoutParams(): void {\n this._layoutParams = null;\n this.resetLine();\n }\n\n /**\n * Creates a snapshot of the current layout parameters.\n * @returns A new LayoutParams object with the current effective settings\n */\n protected snapshotLayoutParams(): LayoutParams {\n const effectiveCycle = this.cycle;\n if (effectiveCycle == null) {\n throw new Error(\"Cannot create layout params: no cycle defined\");\n }\n return new LayoutParams({\n cycle: effectiveCycle,\n beatDuration: this.atomsPerBeat,\n layout: this.breaks,\n });\n }\n\n /**\n * Finds an unnamed layout parameters object that matches the current effective settings.\n * @returns Matching layout parameters, or null if none found\n */\n protected findUnnamedLayoutParams(): LayoutParams | null {\n const effectiveCycle = this.cycle;\n if (effectiveCycle == null) return null;\n\n return (\n this._unnamedLayoutParams.find((lp) => {\n return (\n lp.beatDuration == this.atomsPerBeat && effectiveCycle.equals(lp.cycle) && lp.lineBreaksEqual(this.breaks)\n );\n }) || null\n );\n }\n\n /**\n * Ensures that named layout parameters with the given name exist.\n * @param name The name of the layout parameters\n * @returns The layout parameters\n */\n ensureNamedLayoutParams(name: string): LayoutParams {\n let lp = this._namedLayoutParams.get(name) || null;\n if (lp == null || this._layoutParams != lp) {\n if (lp == null) {\n // Create new named layout params\n lp = this.snapshotLayoutParams();\n this._namedLayoutParams.set(name, lp);\n } else {\n // Copy named LPs attributes into our locals\n this.localCycle = lp.cycle;\n this.localAtomsPerBeat = lp.beatDuration;\n this.localBreaks = lp.lineBreaks;\n }\n this._layoutParams = lp;\n this.resetLine();\n }\n return this._layoutParams!;\n }\n\n /**\n * Gets a role definition by name, walking up the tree if not found locally.\n * @param name The name of the role\n */\n getRole(name: string): TSU.Nullable<RoleDef> {\n const local = this.localRoles.get(name.toLowerCase());\n if (local) {\n return local;\n }\n return this.parentBlock?.getRole(name) ?? null;\n }\n\n // ============================================\n // State tracking for command application\n // ============================================\n\n /**\n * Gets the current role definition.\n * Falls back to parent's current role or the last defined role.\n */\n get currRoleDef(): TSU.Nullable<RoleDef> {\n if (this._currRoleDef !== null) {\n return this._currRoleDef;\n }\n // Fall back to parent's current role\n if (this.parentBlock) {\n return this.parentBlock.currRoleDef;\n }\n // Or use the last locally defined role\n const roles = Array.from(this.localRoles.values());\n return roles.length > 0 ? roles[roles.length - 1] : null;\n }\n\n /**\n * Sets the current role by name.\n * If the role doesn't exist, tries to create it via the root container's onMissingRole.\n * @param name The name of the role to activate\n * @throws Error if the role is not found and cannot be created\n */\n setCurrRole(name: string): void {\n name = name.trim().toLowerCase();\n if (name === \"\") {\n throw new Error(\"Role name cannot be empty\");\n }\n let roleDef = this.getRole(name);\n // If role not found, try auto-creation\n if (roleDef == null) {\n // Create the role locally in this block\n // Default: \"sw\" is notes-only, others are not\n roleDef = this.newRoleDef(name, name === \"sw\");\n }\n this._currRoleDef = roleDef;\n }\n\n /**\n * Gets the current line, creating one if needed.\n */\n get currentLine(): Line {\n if (this._currentLine === null) {\n return this.newLine();\n }\n return this._currentLine;\n }\n\n /**\n * Creates a new line in this block.\n */\n newLine(): Line {\n if (this._currentLine !== null && this._currentLine.isEmpty) {\n // Remove empty line before creating new one\n this.removeBlockItem(this._currentLine);\n }\n this._currentLine = new Line();\n this.addBlockItem(this._currentLine);\n return this._currentLine;\n }\n\n /**\n * Resets the current line pointer to null.\n * Called when layout parameters change to force a new line.\n */\n resetLine(): void {\n this._currentLine = null;\n }\n\n /**\n * Creates a new role definition local to this block.\n * @param name The name of the role\n * @param notesOnly Whether this role contains only notes\n */\n newRoleDef(name: string, notesOnly = false): RoleDef {\n name = name.trim().toLowerCase();\n if (name === \"\") {\n throw new Error(\"Role name cannot be empty\");\n }\n if (this.localRoles.has(name)) {\n throw new Error(`Role '${name}' already exists in this block`);\n }\n const rd = new RoleDef();\n rd.name = name;\n rd.notesOnly = notesOnly;\n rd.index = this.localRoles.size;\n this.localRoles.set(name, rd);\n return rd;\n }\n\n // ============================================\n // Child management\n // ============================================\n\n /**\n * Adds a child item to this block.\n * @param item The item to add\n */\n addBlockItem(item: BlockItem): void {\n const index = this.blockItems.length;\n item.setParent(this);\n this.blockItems.push(item);\n\n // Notify observers of added item\n if (this._eventsEnabled) {\n for (const observer of this._observers) {\n observer.onItemAdded?.(this, item, index);\n }\n }\n }\n\n /**\n * Removes a child item from this block.\n * @param item The item to remove\n * @returns The index of the removed item, or -1 if not found\n */\n removeBlockItem(item: BlockItem): number {\n const index = this.blockItems.indexOf(item);\n if (index >= 0) {\n this.blockItems.splice(index, 1);\n item.setParent(null);\n\n // Notify observers of removed item\n if (this._eventsEnabled) {\n for (const observer of this._observers) {\n observer.onItemRemoved?.(this, item, index);\n }\n }\n }\n return index;\n }\n\n /**\n * Returns a debug-friendly representation of this block.\n */\n debugValue(): any {\n const out: any = {\n ...super.debugValue(),\n blockType: this.blockType,\n blockItems: this.blockItems.map((c) => c.debugValue()),\n };\n if (this.name) {\n out.name = this.name;\n }\n if (this.localCycle) {\n out.localCycle = this.localCycle.uuid;\n }\n if (this.localAtomsPerBeat !== null) {\n out.localAtomsPerBeat = this.localAtomsPerBeat;\n }\n if (this.localBreaks !== null) {\n out.localBreaks = this.localBreaks;\n }\n if (this.localRoles.size > 0) {\n out.localRoles = Array.from(this.localRoles.keys());\n }\n return out;\n }\n}\n\n/**\n * Helper function to find the containing block of an entity by walking up the tree.\n * @param entity The entity to start from\n * @returns The containing Block, or null if not found\n */\nexport function findContainingBlock(entity: Entity): TSU.Nullable<Block> {\n let current: TSU.Nullable<Entity> = entity.parent;\n while (current !== null) {\n if (current instanceof Block) {\n return current;\n }\n current = current.parent;\n }\n return null;\n}\n\n// ============================================\n// Block Subclasses\n// ============================================\n\n/**\n * A section block with a heading.\n * Expands children to include a heading RawBlock followed by the content.\n *\n * Usage: \\section(\"Pallavi\") { ... }\n */\nexport class SectionBlock extends Block {\n constructor(sectionName: string, parent: TSU.Nullable<Block> = null) {\n super(\"section\", parent, sectionName);\n }\n\n /**\n * Expands children to include a heading RawBlock.\n */\n children(): BlockItem[] {\n const heading = new RawBlock(`# ${this.name}`, \"md\");\n return [heading, ...this.blockItems];\n }\n}\n\n/**\n * A repeat block that expands its children N times.\n *\n * Usage: \\repeat(2) { ... }\n */\nexport class RepeatBlock extends Block {\n /** Number of times to repeat (0 = visual markers only) */\n readonly repeatCount: number;\n\n constructor(repeatCount: number, parent: TSU.Nullable<Block> = null) {\n super(\"repeat\", parent);\n this.repeatCount = repeatCount;\n }\n\n /**\n * Expands children by repeating them N times.\n * If count is 0, returns children as-is (visual repeat markers only).\n */\n children(): BlockItem[] {\n if (this.repeatCount <= 0) {\n return this.blockItems;\n }\n const expanded: BlockItem[] = [];\n for (let i = 0; i < this.repeatCount; i++) {\n expanded.push(...this.blockItems);\n }\n return expanded;\n }\n}\n\n/**\n * A cycle block that sets localCycle for scoped notation.\n *\n * Usage: \\cycle(\"|4|4|\") { ... }\n */\nexport class CycleBlock extends Block {\n constructor(cycle: Cycle, parent: TSU.Nullable<Block> = null) {\n super(\"cycle\", parent);\n this.localCycle = cycle;\n }\n}\n\n/**\n * A beat duration block that sets localAtomsPerBeat for scoped notation.\n *\n * Usage: \\beatDuration(2) { ... }\n */\nexport class BeatDurationBlock extends Block {\n constructor(atomsPerBeat: number, parent: TSU.Nullable<Block> = null) {\n super(\"beatduration\", parent);\n this.localAtomsPerBeat = atomsPerBeat;\n }\n}\n\n/**\n * A breaks block that sets localBreaks for scoped notation.\n *\n * Usage: \\breaks(4, 2, 2) { ... }\n */\nexport class BreaksBlock extends Block {\n constructor(breaks: number[], parent: TSU.Nullable<Block> = null) {\n super(\"breaks\", parent);\n this.localBreaks = breaks;\n }\n}\n\n/**\n * A role block that creates a local role definition.\n *\n * Usage: \\role(\"Vocals\", notes=false) { ... }\n */\nexport class RoleBlock extends Block {\n constructor(roleName: string, notesOnly: boolean, parent: TSU.Nullable<Block> = null) {\n super(\"role\", parent);\n // Create the role locally\n this.newRoleDef(roleName, notesOnly);\n }\n}\n\n/**\n * A group block for organizing notation without special semantics.\n *\n * Usage: \\group(\"optional-name\") { ... }\n */\nexport class GroupBlock extends Block {\n constructor(groupName: string | null, parent: TSU.Nullable<Block> = null) {\n super(\"group\", parent, groupName);\n }\n}\n"]}
package/lib/cjs/core.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as TSU from "@panyam/tsutils";
2
2
  import { Entity, TimedEntity } from "./entity";
3
3
  import { LayoutParams } from "./layouts";
4
+ import { GroupObserver, RoleObserver, LineObserver } from "./events";
4
5
  type Fraction = TSU.Num.Fraction;
5
6
  export declare const ZERO: TSU.Num.Fraction;
6
7
  export declare const ONE: TSU.Num.Fraction;
@@ -89,7 +90,11 @@ export declare class Group extends Atom {
89
90
  readonly TYPE = "Group";
90
91
  durationIsMultiplier: boolean;
91
92
  readonly atoms: TSU.Lists.ValueList<Atom>;
93
+ private _observers;
92
94
  constructor(...atoms: Atom[]);
95
+ addObserver(observer: GroupObserver<Atom, Group>): () => void;
96
+ removeObserver(observer: GroupObserver<Atom, Group>): void;
97
+ private notifyObservers;
93
98
  equals(another: this, expect?: boolean): boolean;
94
99
  copyTo(another: this): void;
95
100
  get duration(): Fraction;
@@ -108,12 +113,16 @@ export declare class Line extends Entity {
108
113
  roles: Role[];
109
114
  marginText: string;
110
115
  layoutParams: LayoutParams;
116
+ private _observers;
117
+ addObserver(observer: LineObserver<Role, Line>): () => void;
118
+ removeObserver(observer: LineObserver<Role, Line>): void;
111
119
  indexOfRole(name: string): number;
112
120
  get isEmpty(): boolean;
113
121
  debugValue(): any;
114
122
  copyTo(another: this): void;
115
123
  addAtoms(roleName: string, defaultToNotes: boolean, ...atoms: Atom[]): this;
116
124
  ensureRole(roleName: string, defaultToNotes: boolean): Role;
125
+ removeRole(roleName: string): boolean;
117
126
  get duration(): Fraction;
118
127
  }
119
128
  export declare class Role extends Entity {
@@ -122,10 +131,16 @@ export declare class Role extends Entity {
122
131
  readonly TYPE = "Role";
123
132
  defaultToNotes: boolean;
124
133
  atoms: Atom[];
134
+ private _observers;
125
135
  constructor(line: Line, name: string);
136
+ addObserver(observer: RoleObserver<Atom, Role>): () => void;
137
+ removeObserver(observer: RoleObserver<Atom, Role>): void;
138
+ private notifyObservers;
126
139
  get isEmpty(): boolean;
127
140
  debugValue(): any;
128
141
  addAtoms(...atoms: Atom[]): void;
142
+ insertAtomsAt(index: number, ...atoms: Atom[]): void;
143
+ removeAtoms(...atoms: Atom[]): void;
129
144
  copyTo(another: Role): void;
130
145
  get duration(): Fraction;
131
146
  }
package/lib/cjs/core.js CHANGED
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.Role = exports.Line = exports.Group = exports.Note = exports.Syllable = exports.Literal = exports.Space = exports.Rest = exports.Marker = exports.LeafAtom = exports.Atom = exports.AtomType = exports.ONE = exports.ZERO = void 0;
37
37
  const TSU = __importStar(require("@panyam/tsutils"));
38
38
  const entity_1 = require("./entity");
39
+ const events_1 = require("./events");
39
40
  exports.ZERO = TSU.Num.Fraction.ZERO;
40
41
  exports.ONE = TSU.Num.Fraction.ONE;
41
42
  var AtomType;
@@ -247,8 +248,37 @@ class Group extends Atom {
247
248
  this.TYPE = "Group";
248
249
  this.durationIsMultiplier = false;
249
250
  this.atoms = new TSU.Lists.ValueList();
251
+ this._observers = [];
250
252
  this.addAtoms(false, ...atoms);
251
253
  }
254
+ addObserver(observer) {
255
+ this._observers.push(observer);
256
+ return () => this.removeObserver(observer);
257
+ }
258
+ removeObserver(observer) {
259
+ const index = this._observers.indexOf(observer);
260
+ if (index >= 0) {
261
+ this._observers.splice(index, 1);
262
+ }
263
+ }
264
+ notifyObservers(type, atoms, index) {
265
+ var _a, _b, _c;
266
+ if (!this._eventsEnabled)
267
+ return;
268
+ for (const observer of this._observers) {
269
+ switch (type) {
270
+ case events_1.AtomChangeType.ADD:
271
+ (_a = observer.onAtomsAdded) === null || _a === void 0 ? void 0 : _a.call(observer, this, atoms, index);
272
+ break;
273
+ case events_1.AtomChangeType.INSERT:
274
+ (_b = observer.onAtomsInserted) === null || _b === void 0 ? void 0 : _b.call(observer, this, atoms, index);
275
+ break;
276
+ case events_1.AtomChangeType.REMOVE:
277
+ (_c = observer.onAtomsRemoved) === null || _c === void 0 ? void 0 : _c.call(observer, this, atoms);
278
+ break;
279
+ }
280
+ }
281
+ }
252
282
  equals(another, expect = false) {
253
283
  if (!super.equals(another))
254
284
  return false;
@@ -257,7 +287,9 @@ class Group extends Atom {
257
287
  copyTo(another) {
258
288
  super.copyTo(another);
259
289
  another.durationIsMultiplier = this.durationIsMultiplier;
260
- this.atoms.forEach((atom) => another.atoms.add(atom.clone()));
290
+ for (const atom of this.atoms.values()) {
291
+ another.atoms.add(atom.clone());
292
+ }
261
293
  }
262
294
  get duration() {
263
295
  if (this.durationIsMultiplier) {
@@ -330,12 +362,27 @@ class Group extends Atom {
330
362
  }
331
363
  get totalChildDuration() {
332
364
  let out = exports.ZERO;
333
- this.atoms.forEach((atom) => (out = out.plus(atom.duration)));
365
+ for (const atom of this.atoms.values()) {
366
+ out = out.plus(atom.duration);
367
+ }
334
368
  return out;
335
369
  }
336
370
  insertAtomsAt(beforeAtom, adjustDuration = false, ...atoms) {
337
371
  adjustDuration = adjustDuration && !this.durationIsMultiplier;
338
372
  const oldChildDuration = adjustDuration ? this.totalChildDuration : exports.ONE;
373
+ let insertIndex;
374
+ if (beforeAtom) {
375
+ insertIndex = 0;
376
+ for (const a of this.atoms.values()) {
377
+ if (a === beforeAtom)
378
+ break;
379
+ insertIndex++;
380
+ }
381
+ }
382
+ else {
383
+ insertIndex = this.atoms.size;
384
+ }
385
+ const addedAtoms = [];
339
386
  for (const atom of atoms) {
340
387
  if (atom.parentGroup != null) {
341
388
  if (atom.parentGroup != this) {
@@ -352,6 +399,7 @@ class Group extends Atom {
352
399
  else {
353
400
  atom.parentGroup = this;
354
401
  this.atoms.add(atom, beforeAtom);
402
+ addedAtoms.push(atom);
355
403
  }
356
404
  }
357
405
  if (adjustDuration) {
@@ -365,6 +413,10 @@ class Group extends Atom {
365
413
  this._duration = this._duration.times(scaleFactor, true);
366
414
  }
367
415
  }
416
+ if (addedAtoms.length > 0) {
417
+ const type = beforeAtom ? events_1.AtomChangeType.INSERT : events_1.AtomChangeType.ADD;
418
+ this.notifyObservers(type, addedAtoms, insertIndex);
419
+ }
368
420
  return this;
369
421
  }
370
422
  addAtoms(adjustDuration = false, ...atoms) {
@@ -373,10 +425,12 @@ class Group extends Atom {
373
425
  removeAtoms(adjustDuration = false, ...atoms) {
374
426
  adjustDuration = adjustDuration && !this.durationIsMultiplier;
375
427
  const oldChildDuration = adjustDuration ? this.totalChildDuration : exports.ONE;
428
+ const removedAtoms = [];
376
429
  for (const atom of atoms) {
377
430
  if (atom.parentGroup == this) {
378
431
  this.atoms.remove(atom);
379
432
  atom.parentGroup = null;
433
+ removedAtoms.push(atom);
380
434
  }
381
435
  else if (atom.parentGroup != null) {
382
436
  throw new Error("Atom cannot be removed as it does not belong to this group");
@@ -393,6 +447,9 @@ class Group extends Atom {
393
447
  this._duration = this._duration.times(scaleFactor, true);
394
448
  }
395
449
  }
450
+ if (removedAtoms.length > 0) {
451
+ this.notifyObservers(events_1.AtomChangeType.REMOVE, removedAtoms, -1);
452
+ }
396
453
  return this;
397
454
  }
398
455
  }
@@ -404,6 +461,17 @@ class Line extends entity_1.Entity {
404
461
  this.offset = exports.ZERO;
405
462
  this.roles = [];
406
463
  this.marginText = "";
464
+ this._observers = [];
465
+ }
466
+ addObserver(observer) {
467
+ this._observers.push(observer);
468
+ return () => this.removeObserver(observer);
469
+ }
470
+ removeObserver(observer) {
471
+ const index = this._observers.indexOf(observer);
472
+ if (index >= 0) {
473
+ this._observers.splice(index, 1);
474
+ }
407
475
  }
408
476
  indexOfRole(name) {
409
477
  for (let i = 0; i < this.roles.length; i++) {
@@ -435,15 +503,35 @@ class Line extends entity_1.Entity {
435
503
  return this;
436
504
  }
437
505
  ensureRole(roleName, defaultToNotes) {
506
+ var _a;
438
507
  let ri = this.roles.findIndex((r) => r.name == roleName);
439
508
  if (ri < 0) {
440
509
  ri = this.roles.length;
441
510
  const role = new Role(this, roleName);
442
511
  role.defaultToNotes = defaultToNotes;
443
512
  this.roles.push(role);
513
+ if (this._eventsEnabled) {
514
+ for (const observer of this._observers) {
515
+ (_a = observer.onRoleAdded) === null || _a === void 0 ? void 0 : _a.call(observer, this, roleName, role);
516
+ }
517
+ }
444
518
  }
445
519
  return this.roles[ri];
446
520
  }
521
+ removeRole(roleName) {
522
+ var _a;
523
+ const ri = this.roles.findIndex((r) => r.name == roleName);
524
+ if (ri >= 0) {
525
+ this.roles.splice(ri, 1);
526
+ if (this._eventsEnabled) {
527
+ for (const observer of this._observers) {
528
+ (_a = observer.onRoleRemoved) === null || _a === void 0 ? void 0 : _a.call(observer, this, roleName);
529
+ }
530
+ }
531
+ return true;
532
+ }
533
+ return false;
534
+ }
447
535
  get duration() {
448
536
  let max = exports.ZERO;
449
537
  for (const role of this.roles) {
@@ -461,6 +549,35 @@ class Role extends entity_1.Entity {
461
549
  this.TYPE = "Role";
462
550
  this.defaultToNotes = true;
463
551
  this.atoms = [];
552
+ this._observers = [];
553
+ }
554
+ addObserver(observer) {
555
+ this._observers.push(observer);
556
+ return () => this.removeObserver(observer);
557
+ }
558
+ removeObserver(observer) {
559
+ const index = this._observers.indexOf(observer);
560
+ if (index >= 0) {
561
+ this._observers.splice(index, 1);
562
+ }
563
+ }
564
+ notifyObservers(type, atoms, index) {
565
+ var _a, _b, _c;
566
+ if (!this._eventsEnabled)
567
+ return;
568
+ for (const observer of this._observers) {
569
+ switch (type) {
570
+ case events_1.AtomChangeType.ADD:
571
+ (_a = observer.onAtomsAdded) === null || _a === void 0 ? void 0 : _a.call(observer, this, atoms, index);
572
+ break;
573
+ case events_1.AtomChangeType.INSERT:
574
+ (_b = observer.onAtomsInserted) === null || _b === void 0 ? void 0 : _b.call(observer, this, atoms, index);
575
+ break;
576
+ case events_1.AtomChangeType.REMOVE:
577
+ (_c = observer.onAtomsRemoved) === null || _c === void 0 ? void 0 : _c.call(observer, this, atoms);
578
+ break;
579
+ }
580
+ }
464
581
  }
465
582
  get isEmpty() {
466
583
  return this.atoms.length == 0;
@@ -469,7 +586,11 @@ class Role extends entity_1.Entity {
469
586
  return { name: this.name, atoms: this.atoms.map((a) => a.debugValue()) };
470
587
  }
471
588
  addAtoms(...atoms) {
472
- let last = null;
589
+ this.insertAtomsAt(this.atoms.length, ...atoms);
590
+ }
591
+ insertAtomsAt(index, ...atoms) {
592
+ const addedAtoms = [];
593
+ let last = index > 0 ? this.atoms[index - 1] : null;
473
594
  for (const atom of atoms) {
474
595
  if (atom.TYPE == AtomType.REST) {
475
596
  if (last && last.TYPE != AtomType.GROUP && last.TYPE != AtomType.LABEL) {
@@ -477,10 +598,29 @@ class Role extends entity_1.Entity {
477
598
  }
478
599
  }
479
600
  else {
480
- this.atoms.push(atom);
601
+ this.atoms.splice(index + addedAtoms.length, 0, atom);
602
+ addedAtoms.push(atom);
481
603
  }
482
604
  last = atom;
483
605
  }
606
+ if (addedAtoms.length > 0) {
607
+ const isAppend = index >= this.atoms.length - addedAtoms.length;
608
+ const type = isAppend ? events_1.AtomChangeType.ADD : events_1.AtomChangeType.INSERT;
609
+ this.notifyObservers(type, addedAtoms, index);
610
+ }
611
+ }
612
+ removeAtoms(...atoms) {
613
+ const removedAtoms = [];
614
+ for (const atom of atoms) {
615
+ const idx = this.atoms.indexOf(atom);
616
+ if (idx >= 0) {
617
+ this.atoms.splice(idx, 1);
618
+ removedAtoms.push(atom);
619
+ }
620
+ }
621
+ if (removedAtoms.length > 0) {
622
+ this.notifyObservers(events_1.AtomChangeType.REMOVE, removedAtoms, -1);
623
+ }
484
624
  }
485
625
  copyTo(another) {
486
626
  another.addAtoms(...this.atoms);