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
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serializeCells = serializeCells;
4
+ exports.serializeCell = serializeCell;
5
+ exports.serializeBlockItem = serializeBlockItem;
6
+ exports.updateCellSource = updateCellSource;
7
+ exports.validateCellSource = validateCellSource;
8
+ exports.findCellSourceRange = findCellSourceRange;
9
+ const block_1 = require("../../block");
10
+ const DEFAULT_OPTIONS = {
11
+ indent: " ",
12
+ lineSeparator: "\n",
13
+ preserveUnmodified: true,
14
+ };
15
+ function serializeCells(cells, options = {}) {
16
+ const opts = Object.assign(Object.assign({}, DEFAULT_OPTIONS), options);
17
+ const parts = [];
18
+ for (const cell of cells) {
19
+ const serialized = serializeCell(cell, 0, opts);
20
+ if (serialized) {
21
+ parts.push(serialized);
22
+ }
23
+ }
24
+ return parts.join(opts.lineSeparator + opts.lineSeparator);
25
+ }
26
+ function serializeCell(cell, depth, options) {
27
+ const indent = options.indent.repeat(depth);
28
+ if (options.preserveUnmodified && cell.source && !cell.state.hasError) {
29
+ if (depth === 0) {
30
+ return cell.source;
31
+ }
32
+ return cell.source
33
+ .split("\n")
34
+ .map((line) => indent + line)
35
+ .join(options.lineSeparator);
36
+ }
37
+ return serializeBlockItem(cell.blockItem, depth, options);
38
+ }
39
+ function serializeBlockItem(item, depth, options) {
40
+ if ((0, block_1.isRawBlock)(item)) {
41
+ return serializeRawBlock(item, depth, options);
42
+ }
43
+ if ((0, block_1.isLine)(item)) {
44
+ return serializeLine(item, depth, options);
45
+ }
46
+ if ((0, block_1.isBlock)(item)) {
47
+ return serializeBlock(item, depth, options);
48
+ }
49
+ return "";
50
+ }
51
+ function serializeRawBlock(rawBlock, depth, options) {
52
+ const indent = options.indent.repeat(depth);
53
+ const content = rawBlock.content;
54
+ if (rawBlock.contentType === "md") {
55
+ return `${indent}---${options.lineSeparator}${content}${options.lineSeparator}${indent}---`;
56
+ }
57
+ if (rawBlock.contentType === "metadata") {
58
+ return `${indent}@@${content}`;
59
+ }
60
+ return content
61
+ .split("\n")
62
+ .map((line) => indent + line)
63
+ .join(options.lineSeparator);
64
+ }
65
+ function serializeLine(line, depth, options) {
66
+ const indent = options.indent.repeat(depth);
67
+ return `${indent}; [Line serialization not fully implemented]`;
68
+ }
69
+ function serializeBlock(block, depth, options) {
70
+ const indent = options.indent.repeat(depth);
71
+ const childIndent = options.indent.repeat(depth + 1);
72
+ const parts = [];
73
+ const header = serializeBlockHeader(block);
74
+ parts.push(`${indent}${header} {`);
75
+ for (const child of block.blockItems) {
76
+ const childSource = serializeBlockItem(child, depth + 1, options);
77
+ if (childSource) {
78
+ parts.push(childSource);
79
+ }
80
+ }
81
+ parts.push(`${indent}}`);
82
+ return parts.join(options.lineSeparator);
83
+ }
84
+ function serializeBlockHeader(block) {
85
+ var _a;
86
+ const type = block.blockType;
87
+ switch (type) {
88
+ case "section":
89
+ return `\\section("${block.name || ""}")`;
90
+ case "repeat": {
91
+ const repeatCount = (_a = block.repeatCount) !== null && _a !== void 0 ? _a : 1;
92
+ return `\\repeat(${repeatCount})`;
93
+ }
94
+ case "cycle":
95
+ if (block.localCycle) {
96
+ return `\\cycle("${block.localCycle.toString()}")`;
97
+ }
98
+ return "\\cycle()";
99
+ case "beatduration":
100
+ if (block.localAtomsPerBeat !== null) {
101
+ return `\\beatDuration(${block.localAtomsPerBeat})`;
102
+ }
103
+ return "\\beatDuration(1)";
104
+ case "breaks":
105
+ if (block.localBreaks) {
106
+ return `\\breaks(${block.localBreaks.join(", ")})`;
107
+ }
108
+ return "\\breaks()";
109
+ case "role": {
110
+ const roleName = Array.from(block.localRoles.keys())[0] || "";
111
+ return `\\role("${roleName}")`;
112
+ }
113
+ case "group":
114
+ if (block.name) {
115
+ return `\\group("${block.name}")`;
116
+ }
117
+ return "\\group()";
118
+ case "notation":
119
+ return "";
120
+ default:
121
+ return `\\${type}()`;
122
+ }
123
+ }
124
+ function updateCellSource(cell, newSource) {
125
+ return Object.assign(Object.assign({}, cell), { source: newSource });
126
+ }
127
+ function validateCellSource(source) {
128
+ let braceCount = 0;
129
+ for (const char of source) {
130
+ if (char === "{")
131
+ braceCount++;
132
+ if (char === "}")
133
+ braceCount--;
134
+ if (braceCount < 0) {
135
+ return {
136
+ isValid: false,
137
+ error: "Unmatched closing brace",
138
+ };
139
+ }
140
+ }
141
+ if (braceCount !== 0) {
142
+ return {
143
+ isValid: false,
144
+ error: "Unmatched opening brace",
145
+ };
146
+ }
147
+ return { isValid: true };
148
+ }
149
+ function findCellSourceRange(cell, fullSource) {
150
+ if ((0, block_1.isRawBlock)(cell.blockItem)) {
151
+ const rawBlock = cell.blockItem;
152
+ const start = fullSource.indexOf(rawBlock.content);
153
+ if (start >= 0) {
154
+ return {
155
+ start,
156
+ end: start + rawBlock.content.length,
157
+ };
158
+ }
159
+ }
160
+ return null;
161
+ }
162
+ //# sourceMappingURL=sourceSerializer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sourceSerializer.js","sourceRoot":"","sources":["../../../../src/web/utils/sourceSerializer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Source serializer for converting CellModel trees back to notation source.\n *\n * This module handles serializing edited cells back into notation source text,\n * preserving formatting and structure where possible.\n */\n\nimport type { BlockItem, Block, RawBlock } from \"../../block\";\nimport type { Line } from \"../../core\";\nimport { isBlock, isLine, isRawBlock } from \"../../block\";\nimport { CellModel } from \"../types/notebook\";\n\n/**\n * Options for source serialization.\n */\nexport interface SerializerOptions {\n /**\n * Indentation string to use for nested blocks.\n * @default \" \" (two spaces)\n */\n indent?: string;\n\n /**\n * Line separator.\n * @default \"\\n\"\n */\n lineSeparator?: string;\n\n /**\n * Whether to preserve original source for unmodified cells.\n * @default true\n */\n preserveUnmodified?: boolean;\n}\n\nconst DEFAULT_OPTIONS: SerializerOptions = {\n indent: \" \",\n lineSeparator: \"\\n\",\n preserveUnmodified: true,\n};\n\n/**\n * Serializes a cell tree back to notation source.\n *\n * @param cells The cell models to serialize\n * @param options Serialization options\n * @returns The serialized notation source\n */\nexport function serializeCells(cells: CellModel[], options: SerializerOptions = {}): string {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const parts: string[] = [];\n\n for (const cell of cells) {\n const serialized = serializeCell(cell, 0, opts);\n if (serialized) {\n parts.push(serialized);\n }\n }\n\n return parts.join(opts.lineSeparator! + opts.lineSeparator!);\n}\n\n/**\n * Serializes a single cell to source.\n *\n * @param cell The cell to serialize\n * @param depth The current nesting depth\n * @param options Serialization options\n * @returns The serialized source\n */\nexport function serializeCell(cell: CellModel, depth: number, options: SerializerOptions): string {\n const indent = options.indent!.repeat(depth);\n\n // If preserving unmodified and cell has source, use it directly\n if (options.preserveUnmodified && cell.source && !cell.state.hasError) {\n // For top-level cells, return source as-is\n if (depth === 0) {\n return cell.source;\n }\n // For nested cells, indent each line\n return cell.source\n .split(\"\\n\")\n .map((line) => indent + line)\n .join(options.lineSeparator!);\n }\n\n // Otherwise, serialize from the block item\n return serializeBlockItem(cell.blockItem, depth, options);\n}\n\n/**\n * Serializes a BlockItem to source.\n *\n * @param item The block item to serialize\n * @param depth The current nesting depth\n * @param options Serialization options\n * @returns The serialized source\n */\nexport function serializeBlockItem(item: BlockItem, depth: number, options: SerializerOptions): string {\n if (isRawBlock(item)) {\n return serializeRawBlock(item as RawBlock, depth, options);\n }\n\n if (isLine(item)) {\n return serializeLine(item as Line, depth, options);\n }\n\n if (isBlock(item)) {\n return serializeBlock(item as Block, depth, options);\n }\n\n return \"\";\n}\n\n/**\n * Serializes a RawBlock to source.\n */\nfunction serializeRawBlock(rawBlock: RawBlock, depth: number, options: SerializerOptions): string {\n const indent = options.indent!.repeat(depth);\n const content = rawBlock.content;\n\n // Determine wrapper based on content type\n if (rawBlock.contentType === \"md\") {\n // Markdown content uses triple backtick or raw syntax\n return `${indent}---${options.lineSeparator}${content}${options.lineSeparator}${indent}---`;\n }\n\n if (rawBlock.contentType === \"metadata\") {\n // Metadata reference\n return `${indent}@@${content}`;\n }\n\n // Default: plain text or other content\n return content\n .split(\"\\n\")\n .map((line) => indent + line)\n .join(options.lineSeparator!);\n}\n\n/**\n * Serializes a Line to source.\n *\n * Note: This is a simplified serialization. Full Line serialization\n * would need to reconstruct atoms, spaces, embellishments, etc.\n */\nfunction serializeLine(line: Line, depth: number, options: SerializerOptions): string {\n const indent = options.indent!.repeat(depth);\n\n // For now, return a placeholder\n // Full implementation would iterate through line.atoms and serialize each\n // This would require significant work to reconstruct the DSL syntax\n return `${indent}; [Line serialization not fully implemented]`;\n}\n\n/**\n * Serializes a Block to source.\n */\nfunction serializeBlock(block: Block, depth: number, options: SerializerOptions): string {\n const indent = options.indent!.repeat(depth);\n const childIndent = options.indent!.repeat(depth + 1);\n const parts: string[] = [];\n\n // Block header\n const header = serializeBlockHeader(block);\n parts.push(`${indent}${header} {`);\n\n // Children\n for (const child of block.blockItems) {\n const childSource = serializeBlockItem(child, depth + 1, options);\n if (childSource) {\n parts.push(childSource);\n }\n }\n\n // Closing brace\n parts.push(`${indent}}`);\n\n return parts.join(options.lineSeparator!);\n}\n\n/**\n * Serializes a block header (command with parameters).\n */\nfunction serializeBlockHeader(block: Block): string {\n const type = block.blockType;\n\n switch (type) {\n case \"section\":\n return `\\\\section(\"${block.name || \"\"}\")`;\n\n case \"repeat\": {\n // RepeatBlock has repeatCount property\n const repeatCount = (block as any).repeatCount ?? 1;\n return `\\\\repeat(${repeatCount})`;\n }\n\n case \"cycle\":\n // CycleBlock has localCycle\n if (block.localCycle) {\n return `\\\\cycle(\"${block.localCycle.toString()}\")`;\n }\n return \"\\\\cycle()\";\n\n case \"beatduration\":\n if (block.localAtomsPerBeat !== null) {\n return `\\\\beatDuration(${block.localAtomsPerBeat})`;\n }\n return \"\\\\beatDuration(1)\";\n\n case \"breaks\":\n if (block.localBreaks) {\n return `\\\\breaks(${block.localBreaks.join(\", \")})`;\n }\n return \"\\\\breaks()\";\n\n case \"role\": {\n // Get first role name from localRoles\n const roleName = Array.from(block.localRoles.keys())[0] || \"\";\n return `\\\\role(\"${roleName}\")`;\n }\n\n case \"group\":\n if (block.name) {\n return `\\\\group(\"${block.name}\")`;\n }\n return \"\\\\group()\";\n\n case \"notation\":\n // Root notation block has no header\n return \"\";\n\n default:\n return `\\\\${type}()`;\n }\n}\n\n/**\n * Updates a cell's source and marks it as modified.\n *\n * @param cell The cell to update\n * @param newSource The new source text\n * @returns A new CellModel with updated source\n */\nexport function updateCellSource(cell: CellModel, newSource: string): CellModel {\n return {\n ...cell,\n source: newSource,\n };\n}\n\n/**\n * Validates cell source by attempting to parse it.\n *\n * @param source The source to validate\n * @returns Object with isValid flag and optional error message\n */\nexport function validateCellSource(source: string): {\n isValid: boolean;\n error?: string;\n} {\n // For now, just check for basic syntax issues\n // Full validation would require the notation parser\n\n // Check for balanced braces\n let braceCount = 0;\n for (const char of source) {\n if (char === \"{\") braceCount++;\n if (char === \"}\") braceCount--;\n if (braceCount < 0) {\n return {\n isValid: false,\n error: \"Unmatched closing brace\",\n };\n }\n }\n\n if (braceCount !== 0) {\n return {\n isValid: false,\n error: \"Unmatched opening brace\",\n };\n }\n\n return { isValid: true };\n}\n\n/**\n * Extracts the source range for a cell from full notation source.\n * This is a best-effort function that tries to find the cell's content\n * in the original source.\n *\n * @param cell The cell to find\n * @param fullSource The full notation source\n * @returns Source range or null if not found\n */\nexport function findCellSourceRange(cell: CellModel, fullSource: string): { start: number; end: number } | null {\n // This is a simplified implementation\n // Full implementation would need source position tracking in the parser\n\n if (isRawBlock(cell.blockItem)) {\n const rawBlock = cell.blockItem as RawBlock;\n const start = fullSource.indexOf(rawBlock.content);\n if (start >= 0) {\n return {\n start,\n end: start + rawBlock.content.length,\n };\n }\n }\n\n return null;\n}\n"]}
@@ -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/esm/block.js CHANGED
@@ -40,6 +40,7 @@ export class Block extends Entity {
40
40
  this._parentBlock = null;
41
41
  this._currRoleDef = null;
42
42
  this._currentLine = null;
43
+ this._observers = [];
43
44
  this._unnamedLayoutParams = [];
44
45
  this._namedLayoutParams = new Map();
45
46
  this._layoutParams = null;
@@ -50,6 +51,16 @@ export class Block extends Entity {
50
51
  this.setParent(parent);
51
52
  }
52
53
  }
54
+ addObserver(observer) {
55
+ this._observers.push(observer);
56
+ return () => this.removeObserver(observer);
57
+ }
58
+ removeObserver(observer) {
59
+ const index = this._observers.indexOf(observer);
60
+ if (index >= 0) {
61
+ this._observers.splice(index, 1);
62
+ }
63
+ }
53
64
  children() {
54
65
  return this.blockItems;
55
66
  }
@@ -195,14 +206,27 @@ export class Block extends Entity {
195
206
  return rd;
196
207
  }
197
208
  addBlockItem(item) {
209
+ var _a;
210
+ const index = this.blockItems.length;
198
211
  item.setParent(this);
199
212
  this.blockItems.push(item);
213
+ if (this._eventsEnabled) {
214
+ for (const observer of this._observers) {
215
+ (_a = observer.onItemAdded) === null || _a === void 0 ? void 0 : _a.call(observer, this, item, index);
216
+ }
217
+ }
200
218
  }
201
219
  removeBlockItem(item) {
220
+ var _a;
202
221
  const index = this.blockItems.indexOf(item);
203
222
  if (index >= 0) {
204
223
  this.blockItems.splice(index, 1);
205
224
  item.setParent(null);
225
+ if (this._eventsEnabled) {
226
+ for (const observer of this._observers) {
227
+ (_a = observer.onItemRemoved) === null || _a === void 0 ? void 0 : _a.call(observer, this, item, index);
228
+ }
229
+ }
206
230
  }
207
231
  return index;
208
232
  }
@@ -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/esm/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
  }